终于搞懂SpringBoot自动装配!
本篇博客是我个人对B站码场安员外SpringBoot自动配置视频的文字版总结,文中出现的源码均是简化后版本。
原视频链接:https://www.bilibili.com/video/BV1NY411P7VX/?spm_id_from=333.337.search-card.all.click&vd_source=40ac0553f204ea9791dc385431e71f1c
自动配置概念
什么是SpringBoot自动配置
SpringBoot自动配置(Auto-Configiuration):
- 它是指基于你引入的依赖Jar包,对 SpringBoot应用进行自动配置
- 它为SpringBoot框架的 “开箱即用” 提供了基础支撑
自动配置(Auto-Configiuration):SpringBoot中的配置类
自动装配(Autowire):Spring中的依赖注入
配置类(Configuration Class):
- 广义的“配置类”: 被注解
@Component
直接或间接修饰的某个类,即我们常说的Spirng组件,其中包含了@Configuration
类 - 狭义的“配置类”: 特指被注解
@Configuration
所修饰的某个类,又称为@Configuration
类
配置类示例
1 |
|
1 |
|
SpringBoot启动流程
SpringBoot启动流程代码简化版:
1 | public static void run(Class<?> primaryClass){ |
加载并处理所有配置类
加载并处理所有配置类 porcessConfigurationClasses(…)
1 | public static void processConfigurationClasses |
1 | public void parse(Class<?> configClass) { |
上述过程涉及到两个重要的注解:
@ComponentScan
- 对指定的package进行扫描,找到其中符合条件的类,默认搜索被
@Component
修饰的类 - 通过属性
basePackages
或basePackageClasses
,来指定要进行扫描的package - 如果未指定package,则默认扫描当前
@ComponentScan
所修饰的类所在的package
使用实例
1 |
|
@Import
- 提供一种显式地从其他地方加载配置类的方式,这样可以避免使用性能较差的组件扫描(Component Scan)
它支持三种导入方式:
- 普通类(这里的“普通”,是相对于随后的两个几口而言);
- 接口
ImportSelector
的实现类 - 接口
ImportBeanDefinitionRegistrar
的实现类
导入普通类
- 创建普通的JAVA类
1
2
3
4
5
6
7
8
9
10public class ConfigA {
public A a() {
return new A();
}
}
public class A{
} - 创建一个配置类,直接将刚才创建的
ConfigA
导入1
2
3
4
5
public class ConfigB {
} - 测试并运行运行结果:
1
2
3
4
5
6
7
8
9public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(ConfigB.class);
//现在的Bean ConfigA 和 A 都在Ioc容器中,是可用的
ConfigA ca = ctx.getBean(ConfigA.class);
A a = ctx.getBean(A.class);
System.out.println(ca.getClass().getSimpleName());
System.out.println(a.getClass().getSimpleName());
}ConfigA
A
导入接口ImportSelector实现类
接口ImportSelector中有一个selectImports方法,它的返回值是一个字符串数组,数组中每个元素分别代表一个将被导入的配置类的全限定名。
利用该特性我们可以给Ioc容器动态的导入多个配置类。
- 创建普通JAVA类
1
2
3
4
5
6
7
8
9
10public class ZooConfig {
public Tiger tiger() {
return new Tiger();
}
}
public class Tiger {
} - 创建一个ImportSelector实现类
1
2
3
4
5
6public class ZooImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata metadata) {
return new String[]{"it's so difficultQaQ"};
}
} - 创建一个配置类,将ImportSelector实现类导入4.测试并运行
1
2
3
4
5
public class ConfigB{
}运行结果:1
2
3
4
5
6
7
8
9public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(ConfigB.class);
//现在的Bean ZooConfig 和 Tiger 都在Ioc容器中,是可用的
ZooConfig zc = ctx.getBean(ZooConfig.class);
Tiger t = ctx.getBean(Tiger.class);
System.out.println(zc.getClass().getSimpleName());
System.out.println(t.getClass().getSimpleName());
}ZooConfig
Tiger
导入接口ImportBeanDefinitionRegistrar实现类
可以手动将多个BeanDefinition注册到IOC容器,从而实现个性化定制。
利用该特性可以给IOC容器动态的导入多个BeanDefinition。
- 创建普通类
1
2
3public class Dog {
} - 创建ImportBeanDefinitionRegistrar实现类
1
2
3
4
5
6
7
8
9public class ZooRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Dog.class);
registry.registerBeanDefinition("dog", bd);
}
} - 创建一个配置类,将ZooRegistrar类导入
1
2
3
4
5
public class ConfigB {
} - 测试并运行运行结果:
1
2
3
4
5
6
7
8public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(ConfigB.class);
//现在的Bean Dog 在Ioc容器中,是可用的
Dog dog = ctx.getBean("dog", Dog.class);
Tiger t = ctx.getBean(Tiger.class);
System.out.println(dog.getClass().getSimpleName());
}Dog
总结加载配置类的方式
- 使用`@Com
评论