springboot的自动装配实际上就是为了从spring工厂文件中获取到对应的需要进行自动装配的类,并生成相应的Bean对象,然后将它们交给spring容器来帮我们进行管理。
众所周知,@SpringBootApplication注解标明这个类是主配置类,它是一个组合注解,springboot通过运行这个类里面的main()方法来启动程序。
@SpringBootApplication
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}
这个注解主要由三个子注解组成:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
j进入到SpringBootConfiguration类中发现,它被@Configuration注解标明,说明其实它就是个配置类
指定要扫描哪些包
也是一个合成注解
自动配置包
给容器注入Register组件
通过Register给容器导入一系列组件,那么是怎么做到的呢,见下方step分解
step1:
AnnotationMetadata metadata
参数传的是这个注解的源信息,比如这个注解标注在哪里。
step2:
(String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0])
获取到标注的主类的包名
也就是通过registerBeanDefinitions这个方法,将某个包下的所有组件,全部注入进去。MainApplication所在包下。
step1:要给容器里面导入哪些,看这个selectImports方法返回的string数组里面有哪些,就导入哪些。
step2:
利用getAutoConfigurationEntry(annotationMetadata)]给容器批量导入组件
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
这127个全类名组件就是默认要导入到容器中的。
那么怎么知道这127个组件就是这个导入规则呢?
step3:进入到getCandidateConfigurations方法中,再层层向内进入,最终由loadSpringFactories方法加载得来所有组件。那么究竟是从哪里加载得来这些组件呢,继续往下看
step4:
从"META-INF/spring.factories"位置来加载一个文件,
所以就会默认扫描当前系统下,所有"META-INF/spring.factories"目录下的文件。
并不是所有的包下面都有这个目录,例如:
最核心的是这个包
spring-boot-autoconfigure-2.3.4.RELEASE.jar。那127个需要加载的组件,实际上是在这里写死的。
文件里面写死了,只要springboot一起动,就要给容器加载的类
其实就是在配置文件里面写死了,springboot一起动就要给容器中加载的所有配置类。
step4:虽然127个场景的自动配置springboot一股脑全加载了,但是哪些生效哪些不生效,按照条件装配规则(@Conditional),最终会按需配置,那么接下来就要了解下“按需配置”了。
用两个案例来解释下
step1:
@ConditionalOnProperty(prefix = “spring.aop”, name = “auto”, havingValue = “true”, matchIfMissing = true)
判断配置文件中是否存在spring.aop.auto这个配置,并且它的值是true,那么AopAutoConfiguration这个类里面的代码就会生效。
matchIfMissing = true默认为就算用户没把havingValue = "true"配置成true,我也默认是true
step2:@ConditionalOnClass(Advice.class)
由于Advice这个包没有导入进来,所以AspectJAutoProxyingConfiguration这个类下的方法都没生效。
step3:
@ConditionalOnMissingClass(“org.aspectj.weaver.Advice”)
@ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “true”,matchIfMissing = true)
如果没有配置org.aspectj.weaver.Advice,则会检查spring.aop中是否有proxy-target-class这个配置,matchIfMissing = true即使没有也默认加载
step4:可以检查一下容器里面是否有这个组件
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 根据类型查看容器里面的组件
String[] beanNamesForType = run.getBeanNamesForType(AopAutoConfiguration.class);
System.out.println("beanNamesForType===>" + beanNamesForType.length);