自动配置源码分析
SpringBoot 2.6.1
1. 依赖自动版本仲裁
打开 pom 文件,找到你的 SpringBoot 依赖,按住 ctrl 点击如下图所示的地方
点击后,我们就来到了 spring-boot-stater-parent-2.6.1.pom 文件,继续按 ctrl 点击如下图所示位置
点击后我们就来到了 spring-boot-dependencies-2.6.1.pom
关键的地方到了,在这个文件中我们可以看到里面定义了很多依赖的版本号(几乎包括了所有常用的依赖),这些版本号都是适配当前 SpringBoot 版本的,这就是SpringBoot 的自动版本仲裁机制
所以当我们想要导入一个新的依赖时,只要这个文件中定义了版本信息,我们就不需要写版本号了。
例如我们想要导入 actuator 时,根本就不需要指定 version,当然你也可以指定 version ,那么实际使用的版本号就是你所指定的。
指定版本号还有另一种方法就是写在 properties 里,比如我们写了一个 mysql.version(这里的名称要和 spring-boot-dependencies里的 properties 中的名称一致),那么就会以我们定义的版本号为准,替换掉父类中定义的版本号。
2. IOC容器
2.1 添加组件
- @Configuration
标注这是一个配置类
// 这里重点说一下proxyBeanMethods属性
// proxyBeanMethods = true表示返回的Bean是单例的
// proxyBeanMethods = false每次获取Bean都是重新创建的
@Configuration(proxyBeanMethods = false)
public class Test {
}
- @Bean
- @Component
- @Controller
- @Service
- @Repository
- @Import
// 添加xxx类型的组件
@Import(XXX.class)
2.2 @Conditional条件注入
比较常用的有
@ConditionalOnBean 当存在某个Bean时注入
@ConditionalOnMissingBean 当缺少某个Bean时注入
@ConditionalOnClass 当存在某个class时注入
2.3 @ImportResource引入原生配置文件(bean.xml)
@ImportResource 用于引入 Spring 时使用的 xml 配置文件,这样的好处就是老项目从Spring 升级到 SpringBoot 时,也可以继续使用之前的 xml 配置文件。
@ImportResource(填写路径)
public class Test {
}
2.4 绑定配置文件
2.4.1 @ConfigurationProperties
// 注意该注解不能单独使用,需要放到容器中才行所以加了@Component注解
@Component
// 如下表示该类中的属性和 application.yaml中以 myconfig 为前缀的属性相绑定
// 注意一定要记得添加get set 方法
@ConfigurationProperties(prefix = "myconfig")
public class Test {
public String name;
public Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Test{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
# 配置文件如下所示
myconfig:
name: zhangsan
age: 18
测试一下属性绑定是否成功,执行 SpringBoot 的启动方法
public static void main(String[] args) {
// 获取IOC容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
// 因为我们的类名是Test所以他的Bean的名称就是test
Test test = (Test) run.getBean("test");
System.out.println(test);
}
可以看到成功的打印出了我们在配置文件中设置的值,说明属性绑定成功
2.4.2 @EnableConfigurationProperties
// 开启Test类的配置绑定功能,Test中使用了@ConfigurationProperties注解
// 将Test注入到容器中,这时Test就不需要加@Component注解了
@EnableConfigurationProperties(Test.class)
public class MyConfig {
}
3. 自动配置原理
SpringBoot 的启动类上只有一个注解 @SpringBootApplication,所以自动配置的秘密就在这个注解中
按 ctrl 点击这个注解进去可以看到这是一个组合注解,这里面的重点就是下图红框中的三个注解,我们依次分析
3.1 @SpringBootConfiguration
虽然他也是一个组合注解,但是点进去可以看到它其实就是标记为了一个配置类,和自动配置无关
3.2 @ComponentScan
这个就是指定了要扫描哪些类,也和自动配置无关
3.3 @EnableAutoConfiguration
点进去可以看到它里面主要有以下两个注解
3.3.1 @AutoConfigurationPackage
点进去可以看到,这里面导入里Register类。正是Register类帮我们注册了一系列的组件,Register 的作用就是将 SpringBoot 启动类所在包以及其子包下所有的组件注册到容器中(比如我们自己加了 @Component @Bean 等注解的组件)
3.3.2 @Import({AutoConfigurationImportSelector.class})
AutoConfigurationImportSelector中导入了自动配置类
要导入的配置类是从 META-INF/spring.factories 中读取的,可以看一下源码,如下所示在spring.factories 配置的所有 xxxAutoConfiguration 都会被加载进来
3.4 自动配置按需开启
AutoConfigurationImportSelector 中其实帮我们导入了很多场景的自动配置类,但是并不是所有的都会生效,因为这些自动配置类大多都是有条件注入的,用到了@Conditional 注解
我们可以在spring-boot-autoconfigure-2.6.1.jar 的源码中随便找一个 AutoConfiguration,可以看到里面都使用了大量的@Conditional 注解,所以虽然自动配置类被加载了,但是并不一定生效,这就要看我们是否满足了它加载的条件
3.5 修改默认配置
可以看到一些类上使用了@ConditionalOnMissingBean
这也就是说如果我们自定义一个该组件,那么 AutoConfiguration 中的组件就不会被加载了,也就实现了自定义配置