basic - bean配置 &

bean

yaml配置Bean

单点注入

@Value("${键名}")

1
2
3
email:
user: nash
password: 798596
1
2
3
4
5
6
7
8
9
@Component 
public class EmailProperties{
@Value("${email.user}")
public String user;

@Value("${email.password}")
public String code;
}

结构化注入

利用@ConfigurationProperties(prefix="前缀"),
添加后该类自动将成员变量匹配上yml文件的字段

1
2
3
email:
user: nash
password: 123
1
2
3
4
5
6
@Component
@ConfigurationProperties(prefix = "email")
public class EmailProperties {
private String user;
private String password;
}

bean管理

bean的注册

注解 说明 位置
@Component 声明bean的基础注解 不属于以下三类时,用此注解
@Controller @Component的衍生注解 标注在控制器类上
@Service @Component的衍生注解 标注在业务类上
@Repository @Component的衍生注解 标注在数据访问类上(由于与mybatis整合,用的少)

流程

默认扫描规则 :
*Spring Boot 默认扫描“启动类所在包”及其子包*

导入第三方bean到容器

bug

第三方bean无妨用@Component及其衍生注解bean

解决

1.配置类 @Configuration + @Bean
  • 写一个Config类并用@Configuration修饰, 启动即扫此类
    配置类编写方法, 方法的返回值即为 第三方bean

  • 第三方bean需要依赖其他已注入的bean时,
    已注入的bean作为形参

2.@Import + @Bean
  • 在启动类加 @Import(配置类.class),
    多个可以写成数组@Import({,,,})
  • 如果实在太多可以导入ImportSelector接口的实现类, 然后重写selectImports方法, 返回我们需要导入的包(是一个String[]{“”,””,””})
  • 耦合度太高, 不够动态
3.配置文件
1
2
3
4
5
6
7
8
9
10
配置文件 common.imports

把要导入的配置类全写进去

ImportSelector 读取这个文件

把类名返回给 Spring

Spring 按这些类名去注册 bean

配置文件导入法里,配置文件保存的是要导入的配置类全限定名,
ImportSelector 负责读取这些类名并返回 String[],
再通过 @Import(ImportSelector实现类.class) 让 Spring 加载这些配置类,最终由配置类中的 @Bean 注册第三方 bean。

3.1 resources/common.imports

此文件即名单表, 里面一般写:

1
2
3
com.xxx.AConfig
com.xxx.BConfig
com.xxx.CConfig

意即这些类导入到Spring容器中
注意这里写的是配置类的路径, 而不是Bean!!!!
Bean一般写在配置类里面作为方法的返回值返回

3.2 CommonImportSelector

核心方法:

1
public String[] selectImports(...)

返回的即为我们要导入的类

3.2.1 读配置文件

1
2
3
InputStream is = CommonImportSelector.class
.getClassLoader()
.getResourceAsStream("common.imports");

此时会读取所有的配置类, 并且把所有@Bean修饰的都去注册为第三方bean

3.2.2 实现ImportSelector接口
在ImportSelector接口的子实现类中重写方法selectImports方法, 并且封装成String[]作为返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public String[] selectImports(AnnotationMetadata importingClassMetadata) {

List<String> imports = new ArrayList<>(); //每个bean的存类路径
//1.读取配置文件
InputStream is = CommonImportSelector.class
.getClassLoader()
.getResourceAsStream("common.imports");//配置文件
var br = new BufferedReader(new InputStreamReader(is));//放入

//2.按行读
String line = null;
try {
while ((line = br.readLine()) != null) {
imports.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

//list->String[]
return imports.toArray(new String[0]);
}

3.2.3 @Import(CommonImportSelector.class)
//ImportSelector接口的子实现类.class

1
2
3
4
5
6
7
8
9
10
11
12
13
启动类启动

看到 @Import(CommonImportSelector.class)

执行 CommonImportSelector

读取 common.imports

拿到配置类名

导入这些配置类

配置类里的 @Bean 生效
1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
@Import(CommonImportSelector.class)
public class SpringbootRegisterApplication {

public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringbootRegisterApplication.class, args);

Country country = context.getBean(Country.class);
System.out.println(country);

System.out.println(context.getBean("province"));
}
}