1. SpringBoot主动拆卸原理

接触过SpringBoot的同学必定都晓得在启动类上有一个@SpringBootApplication注解,他就是主动拆卸的神秘所在。

/** * Indicates a {@link Configuration configuration} class that declares one or more * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience * annotation that is equivalent to declaring {@code @Configuration}, * {@code @EnableAutoConfiguration} and {@code @ComponentScan}. * * @author Phillip Webb * @author Stephane Nicoll * @author Andy Wilkinson * @since 1.2.0 */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {  // 省略代码}

点开@SpringBootApplication注解,先看它的正文,粗心是:

示意一个申明了一个或多个由@Bean注解的办法的配置类,并触发了主动配置和组件扫描。
它是一个等价于@Configuration@EnableAutoConfiguration@ComponentScan的更不便的注解。

能够看到,它由多个注解组合而成,最次要的就是三个注解:

(1) @SpringBootConfiguration

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration@Indexedpublic @interface SpringBootConfiguration {  // 省略代码}

@SpringBootConfiguration其实就相当于@Configuration,就不做过多解释了。

(2) @EnableAutoConfiguration

这个注解是主动拆卸的外围注解:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {  // 省略代码}

它由@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)组成:

1) @AutoConfigurationPackage

/** * Registers packages with {@link AutoConfigurationPackages}. When no {@link #basePackages * base packages} or {@link #basePackageClasses base package classes} are specified, the * package of the annotated class is registered. * * @author Phillip Webb * @since 1.3.0 * @see AutoConfigurationPackages */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {  // 省略代码}

能够看下它的正文,粗心是:

应用@AutoConfigurationPackage注解来注册包。
当没有指定根底包或者根底包类时,被它所注解的类就会被注册。

它应用了@Import注解导入了AutoConfigurationPackages.Registrar这个外部类,它的作用是把扫描门路注册到容器的全局变量中,这样就能够提供给一些JPA框架用来查问到扫描门路。

2) @Import(AutoConfigurationImportSelector.class)

这里应用@Import导入了AutoConfigurationImportSelector类,这个才是最外围的注解。

AutoConfigurationImportSelector中有一个selectImports办法,它会返回所有须要加载到容器中的类的全门路,SpringBoot在获取到这些类的全门路的时候,会应用反射的形式将它们注入到容器中

@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {    if (!isEnabled(annotationMetadata)) {        return NO_IMPORTS;    }    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

selectImports是怎么做到返回这些类的全门路的呢?
重点在于getAutoConfigurationEntry办法:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {    if (!isEnabled(annotationMetadata)) {        return EMPTY_ENTRY;    }    AnnotationAttributes attributes = getAttributes(annotationMetadata);    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);    configurations = removeDuplicates(configurations);    Set<String> exclusions = getExclusions(annotationMetadata, attributes);    checkExcludedClasses(configurations, exclusions);    configurations.removeAll(exclusions);    configurations = getConfigurationClassFilter().filter(configurations);    fireAutoConfigurationImportEvents(configurations, exclusions);    return new AutoConfigurationEntry(configurations, exclusions);}

能够看到在getAutoConfigurationEntry办法中,最重要的就是应用getCandidateConfigurations办法获取所有候选的配置类:

/*** Return the auto-configuration class names that should be considered. By default* this method will load candidates using {@link SpringFactoriesLoader} with* {@link #getSpringFactoriesLoaderFactoryClass()}.* @param metadata the source metadata* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation* attributes}* @return a list of candidate configurations*/protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");    return configurations;}

能够看到,原来是应用了Spring的SPI机制来获取要加载的类的全门路的!

持续跟代码能够看到,在SpringFactorieLoader类中,通过类加载器去加载META-INF/spring.factories文件中的配置,轻易点开一个SpringBoot的jar,比方spring-boot-autoconfigure,能够看到果然有一个META-INF/spring.factories文件。

这个文件中配置了一系列key-value的值,这里咱们只关注EnableAutoConfiguration

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\// 省略配置

看到这里应该大略就明确了SpringBoot主动拆卸的原理了,其实就是通过读取各个jar包中的META-INF/spring.factories中的配置项,来获取类的全门路,而后通过@Configuration和@Bean注入到容器中。

(3) @ComponentScan

这个注解应该很相熟了,是用来设置扫描门路的,默认状况下,它会将以后包以及其子包中的Bean注入到容器中。