二、如何实现SpringBoot的自动装配SpringBoot定义了一套接口规范,在这套规范中SpringBoot启动的时候会扫描外部导入的各种start中的meta-INF/spring.factories文件,将文件中的配置信息加载到Spring容器中。即可以理解为:通过注解或者一些简单的配置就能在Spring Boot的帮助下实现某块功能
- 首先从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 configurations = getCandidateConfigurations(annotationmetadata, attributes);
configurations = removeDuplicates(configurations);
Set 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包的坐标。



