SpringBoot自动装配原理
一、什么是自动装配
SpringBoot定义了一套接口规范,在这套规范中SpringBoot启动的时候会扫描外部导入的各种start中的META-INF/spring.factories文件,将文件中的配置信息加载到Spring容器中。即可以理解为:通过注解或者一些简单的配置就能在Spring Boot的帮助下实现某块功能
二、如何实现SpringBoot的自动装配
- 首先从SpringBoot的核心注解
@SpringBootApplication
入手 - 点击
@SpringBootApplication
可知该注解有以下注解组成:
//前四个是java的元注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//后三个是spring的注解
@SpringBootConfiguration //类似于@Configuration表示该类是配置类
@EnableAutoConfiguration //启用SpringBoot 的自动配置机制(核心)
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //扫描组件
- 重点分析
@EnableAutoConfiguration
注解:
3.1@EnableAutoConfiguration组成:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //将main包下所有组件注册到容器中
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {...}
3.2 重点分析AutoConfigurationImportSelector:自动加载配置类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered
该类实现了DeferredImportSelector接口,因此实现了selectImports()方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//判断自动装配开关是否打开
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//获取所有需要装配的bean
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
因此分析getAutoConfigurationEntry(annotationMetadata)方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
//1.判断是否可以自动装配(默认是true)
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//2.获取EnableAutoConfiguration注解中的 exclude 和 excludeName
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//3.从各个META-INF/spring.factories文件中获取到所有配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
4.
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
对以上2、3、4步dubug图示:
第二步:用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName
第三步:从各个META-INF/spring.factories文件中获取到所有配置类
第四步:根据注解@ConditionalOnXXX进行过滤,满足条件的类才会生效
4. SpringBoot中常见的条件注解:
@ConditionalOnBean:当容器里有指定 Bean 的条件下
@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
@ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选Bean
@ConditionalOnClass:当类路径下有指定类的条件下
@ConditionalOnMissingClass:当类路径下没有指定类的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnExpression:基于 SpEL 表达式作为判断条件
@ConditionalOnJava:基于 Java 版本作为判断条件
@ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
@ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
@ConditionalOnWebApplication:当前项目是 Web 项 目的条件下
三、实现自定义start
- 创建一个mycustomer-spring-boot-start模块,定义好Person类,PersonService、MyConfig这三个类
- 在resources目录下创建一个META-INF目录,并创建一个spring.factories文件,仿照spring-boot-autoconfigure中的spring.factories文件去定义。
- 通过maven中的install命令将模块进行打包,发布到本地仓库中。
- 测试,创建一个模块进行测试,引入刚才打成jar包的坐标。