springboot自动加载--自定义启动类

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Springboot自动加载原理

@SpringBootApplication

首先需要说明@SpringBootApplication它是一个复合型注解里面包含了三个很重要的注解

@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 {
  • @SpringBootConfiguration其实就是一个@Configuration注解而已它只是告诉 spring 这是一个配置类可以被加载到 spring IOC 容器中。
  • @ComponentScan自动扫描并加载符合条件的组件如@Component、@Controller、@Service、@Repository等或者 bean 定义最终将这些 bean 定义加载到IOC容器中。可以指定目录默认所在类的 package 进行扫描
  • @EnableAutoConfiguration自动配置重点下面详细说明。扫描所有 jar 包下面的 META-INF/spring.factories将所有符合自动配置类加载到IOC容器中也是自动配置的核心

@EnableAutoConfiguration

@EnableAutoConfiguration源码

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

@AutoConfigurationPackage源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

@EnableAutoConfiguration包含两个注解

  • @AutoConfigurationPackage借助 @Import 注解导入符合自动配置的类集合加载到IOC容器。
  • @Import(EnableAutoConfigurationImportSelector.class)借助 EnableAutoConfigurationImportSelector 父类 AutoConfigurationImportSelectorselectImports方法来读取所有依赖的jar包下面 META-INF/spring.factories 文件并且根据加载条件来加载项目所需要的类这样就完成了 springboot 的自动加载。

EnableAutoConfigurationImportSelector

@EnableAutoConfigurationImportSelector.selectImports()源码

       /**
        * 最主要的方法
        * annotationMetadata
        * [@org.springframework.boot.autoconfigure.SpringBootApplication
        * (scanBasePackageClasses=[], excludeName=[], exclude=[], scanBasePackages=[])]
        * @param annotationMetadata
        * @return
        */
       @Override
       public String[] selectImports(AnnotationMetadata annotationMetadata) {
              if (!isEnabled(annotationMetadata)) {
                     return NO_IMPORTS;
              }
              /**
               * 
               */
              AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                           .loadMetadata(this.beanClassLoader);
              /**
               * 得到注解中的所有属性信息{excludeName=[], exclude=[]}
               */
              AnnotationAttributes attributes = getAttributes(annotationMetadata);
              /**
               *加载META-INF/spring-autoconfigure-metadata.properties获取所有支持自动配置的信息
               * 获取所有支持EnableAutoConfiguration的组件信息这部分信息配置在spring-boot-autoconfig包下的spring.factories下
               *
               *  使用了内部工具使用SpringFactoriesLoader查找classpath上所有jar包中的
               *  META-INF\spring.factories找出其中key为
               *  org.springframework.boot.autoconfigure.EnableAutoConfiguration
               *  的属性定义的工厂类名称。
               */
              List<String> configurations = getCandidateConfigurations(annotationMetadata,
                           attributes);
              configurations = removeDuplicates(configurations);
              /**
               * 去除不需要的
               * @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, RedisAutoConfiguration.class,
                     DataSourceTransactionManagerAutoConfiguration.class, })
               */
              Set<String> exclusions = getExclusions(annotationMetadata, attributes);
              checkExcludedClasses(configurations, exclusions);
              configurations.removeAll(exclusions);
              /**
               * 然后使用AutoConfigurationImportFilter进行过滤过滤的方式基本上是判断现有系统是否引入了某个组件系统是否使用哪个组件是在pom定义的时候就确定了的
               * 如果有的话则进行相关配置。比如ServletWebServerFactoryAutoConfiguration
               * 会在ServletRequest.class等条件存在的情况下进行配置
               * 而EmbeddedTomcat会在Servlet.class, Tomcat.class存在的情况下创建TomcatServletWebServerFactory
               *
               * org.springframework.boot.autoconfigure.condition.OnClassCondition
               * 总而言之此过滤器会检查候选配置类的注解@ConditionalOnClass如果要求的类在classpath 中不存在则这个候选配置类会被排除掉
               */
              configurations = filter(configurations, autoConfigurationMetadata);
               /**
                * 现在已经找到所有需要被应用的候选配置类
                * 广播事件AutoConfigurationImportEvent
                */
              fireAutoConfigurationImportEvents(configurations, exclusions);
              return StringUtils.toStringArray(configurations);
       }
 
 
private void fireAutoConfigurationImportEvents(List<String> configurations,
                     Set<String> exclusions) {
              List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
              if (!listeners.isEmpty()) {
                     AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
                                  configurations, exclusions);
                     for (AutoConfigurationImportListener listener : listeners) {
                           invokeAwareMethods(listener);
                           listener.onAutoConfigurationImportEvent(event);
                     }
              }
 }

getCandidateConfigurations方法会读取到所有依赖 jar 包下面的 META-INF/spring.factories并将 spring.factories 中的配置类的全名称获取到。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

springboot 之所以能拿到 spring.factories 就是通过SpringFactoriesLoader来读取的SpringFactoriesLoader 会将依赖包所有的 spring.factories 读取出来并用一个 map 来封装读取出来的 vaule。SpringFactoriesLoader 是 spring 提供的一种扩张方案其主要功能就是从指定的配置文件 META-INF/spring.factories 加载配置。

spring.factories

说了半天 META-INF/spring.factories 那这到底是个什么文件我们打开一个启动器的spring.factories文件

参考文章
Springboot自动加载的原理
深入理解springboot工作原理

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring