SpringBoot 启动原理浅析

846 阅读2分钟

这里注释的是 springboot2.3.0 的源码


SpringBoot运行机制

主要是依靠几个注解

@SpringBootApplication 下有3个重点注解

  1. @SpringBootConfiguration 相当于spring中的 Configuration,用来标注类为配置类

  2. @ComponentScan:将指定包下需要装配的组件注册到容器中

  3. @EnableAutoConfiguration:进入之后包含两个重要注解

    1. @AutoConfigurationPackage:将主配置类所在的包,作为自动配置的包进行管理

    2. @Import:导入类到ioc容器中

    其实就是spring 装配所属依赖的类,再用动态代理的方式注入到Spring容器中


run方法

@SpringBootApplication
@EnableJms
public class SampleActiveMQApplication {

   @Bean
   public Queue queue() {
      return new ActiveMQQueue("sample.queue");
   }

   public static void main(String[] args) {
      SpringApplication.run(SampleActiveMQApplication.class, args);
   }

}


点开 @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 {
    .......
}


点开 @SpringBootApplication  查看 AutoConfigurationImportSelector.class

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

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   Class<?>[] exclude() default {};

   /**
    * Exclude specific auto-configuration class names such that they will never be
    * applied.
    * @return the class names to exclude
    * @since 1.3.0
    */
   String[] excludeName() default {};

}


selectImport 方法

/*
*这个方法的返回值包含所有需要注入到容器中的类名
 */
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   //非空判断
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}


getAutoConfigurationEntry  方法

/**
 * 获取打破所有自动配置类,从包的路径中查询所有  META-INF/spring.factories的配置文件  读取里面的内容
 */
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   // 这个方法下调用 spring.factories 进行读取
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   //这个方法 new 了一个 LinkedHashSet 用来做数据的去重
   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);
}


getCandidateConfigurations 方法

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   //这个方法中读取并解析了spring.factory
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;
}


loadFactoryNames

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
   String factoryTypeName = factoryType.getName();
   return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
   // 这里为了提升扫描效率,会先扫描一次缓存
   MultiValueMap<String, String> result = cache.get(classLoader);
   if (result != null) {
      return result;
   }

   try {
      // FACTORIES_RESOURCE_LOCATION  就是 META-INF/spring.factories  需要扫描的配置文件

      Enumeration<URL> urls = (classLoader != null ?
            classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      result = new LinkedMultiValueMap<>();

      //扫描 spring.factories 的过程
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         UrlResource resource = new UrlResource(url);
         Properties properties = PropertiesLoaderUtils.loadProperties(resource);
         for (Map.Entry<?, ?> entry : properties.entrySet()) {
            String factoryTypeName = ((String) entry.getKey()).trim();
            for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
               result.add(factoryTypeName, factoryImplementationName.trim());
            }
         }
      }

    //扫描出来的内容添加到缓存中
      cache.put(classLoader, result);
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}


总结:简单描述了几个重要注解的作用,以及扫描 spring.factory 的过程 ,扫描之后为了读取效率会将结果添加到 cache 缓存中