众所周知,SpringBoot的自动装配是其一大特色,也是我们使用的最多的部分,那么他的底层是如何实现的呢?今天来探寻一下。
自动配置的作用 主要是启动类的@SpringBootApplication注解发挥作用
打开看@SpringBootApplication的源码看一下
除了元注解 里面还包括了@ComponentScan注解组件扫描
以及@SpringBootConfiguration 和@EnableAutoConfiguration
@SpringBootConfiguration 中除了三个元注解
就只剩一个@Configuration(用于标识是一个 配置类) 和 @Indexed(加速应用启动)
@EnableAutoConfiguration注解
可以发现 这就是上面 解决方案2 中提到的 @Enablexxxx系列的注解
一般该类注解内部都封装了 @Import注解 事实上也的确
该注解中 @Import 了一个 Auto.....ImportSelector.class 即导入了一个普通类 并且是一个ImportSelector接口的实现类 结合之前的 解决方案2
我们可以知道 这个注解的作用应该就是 自动配置了
进入到该类 然后查看其实现的一个接口 DeferredImportSelector
发现该接口即 ImportSelector的子接口 直接查看 ImportSelector接口源码
因为 ImportSelector 接口中有个方法的返回值为String数组 该数组封装了要导入自动封装的类名 底层上即:
selectImports(AnnotationMetadata importingClassMetadata);
找到该方法的实现
发现该类的返回值即是将
autoConfigurationEntry.getConfigurations()
的返回值通过StringUtils转为了String数组
该 ... Entry对象 是通过上一行的 get...方法获取的 那么我们再次跟踪该方法到Entry对象的创建上 发现Entry对象的创建又和 configurations相关 configurations是一个List集合 再次进去看看该集合的内容
我们看到getCandidateCanfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
/*重点看上面红色的断言部分 即
如果 configurations为空 则输出在METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
META-INF/spring.factories
两个文件中没有对应的自动配置类
*/
return configurations;
}
在外部库中找到这两个文件并且查看
可以看到 我们找到的这两个对应的文件
里面全是一些类的全类名
所以Spring Boot的自动配置实质就是 将这些需要自动配置的类的全类名先保存在这些文件中 然后读取到List集合里面 然后通过@Import注解读取导入
@Conditional系列注解
我们稍微对比一下IOC容器里面的bean对象和储存全类名的文件就可以发现
其实并不是所有类都创建了对应bean对象存储到了IOC中 可以发现启动即创建bean对象的类都有个@Conditional....注解
@Conditional注解的作用:按照一定的条件进行判断 当条件满足后才会将该类注册对应的bean对象到IOC容器中 可以作用于方法/类 要配合@Bean或者@Component注解一起使用
他是一个父注解 衍生出很多子注解
@ConditionalOnClass
判断环境中是否有对应的字节码文件,才注册Bean对象到IOC容器
有两个属性:String[] name 属性值为 全类名
class<?>[] value 属性值为 字节码文件对象
把相关依赖注释掉后 运行测试方法 发现的确没有创建对应的bean对象
就是因为 jwt 的类不存在 所以不会去配置对应的bean对象
@ConditionalOnMissingBean:
判断环境中没有对应的bean对象的时候,才注册bean到 IOC中
这个注解的功能就很直白 默认情况下是判断本类(即被注解标记的类) 无则创建 但是该直接也可以 自己指定类型(value属性)/名称(name属性)来判断 即判断指定名称/类型的bean对象是否存在
@ConditionalOnProperty:
判断配置文件中对应的属性和值,才注册bean到IOC
该注解有两个重要的属性 name="A" havingValue="B"
即判断 配置文件中(yml ymal properties)是否存在属性A并且值为B
当没有/值不存在/属性不存在
当属性和值都存在
还有很多
综上,就是对SpringBoot自动装配的相关介绍,有其他想法的请私聊或者评论区交流