sprigboot 自动配置 启动

1127

Springboot

springboot 2.7.10

自动配置

@SpringBootApplication

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {
        @Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}),
        @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class})}
)

@SpringBootApplication

@SpringBootConfiguration

@Configuration

spring 注解,用于定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器

@Indexed

​ 加快springboot的启动速度

@EnableAutoConfiguration

启用自动配置

@AutoConfigurationPackage

AutoConfigurationPackages.Registrar.class 注入到容器中

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfigurationPackages.Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}
  • AutoConfigurationPackages.Registrar.class

注入后由其他调用 registerBeanDefinitions

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }
	
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(
        registry,
        (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0])
        );
    }

    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new PackageImports(metadata));
    }
}
  • 方法register

将AutoConfigurationPackages这个类注入到容器中

private static final String BEAN = AutoConfigurationPackages.class.getName();
//org.springframework.boot.autoconfigure.AutoConfigurationPackages

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
    if (registry.containsBeanDefinition(BEAN)) {
        BasePackagesBeanDefinition beanDefinition = 				  
            (BasePackagesBeanDefinition)registry.getBeanDefinition(BEAN);
        beanDefinition.addBasePackages(packageNames);
    } else {
        registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
    }
  • BasePackagesBeanDefinition 添加扫描基础包(springboot注解所在的包)

addBasePackages(basePackages);

static final class BasePackagesBeanDefinition extends GenericBeanDefinition {

   private final Set<String> basePackages = new LinkedHashSet<>();

   BasePackagesBeanDefinition(String... basePackages) {
      setBeanClass(BasePackages.class);
      setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
       
      addBasePackages(basePackages);
   }


}
@Import({AutoConfigurationImportSelector.class})
public class AutoConfigurationImportSelector implements 

    
DeferredImportSelector, 

/**
 Spring 容器在初始化主动检测当前 bean 是否实现了 Aware 接口,如果实现了则回调其 set 方法将相应的参数设置给该 bean ,这个时候该 bean 就从 Spring 容器中取得相应的资源。
*/
BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, 
//执行优先级
Ordered {
    
}
  • DeferredImportSelector

public interface DeferredImportSelector extends ImportSelector {

   @Nullable
   default Class<? extends Group> getImportGroup() {
      return null;
   }

   interface Group {

      void process(AnnotationMetadata metadata, DeferredImportSelector selector);

      
      Iterable<Entry> selectImports();

      class Entry {

         private final AnnotationMetadata metadata;

         private final String importClassName;

         public Entry(AnnotationMetadata metadata, String importClassName) {
            this.metadata = metadata;
            this.importClassName = importClassName;
         }


         public AnnotationMetadata getMetadata() {
            return this.metadata;
         }

         public String getImportClassName() {
            return this.importClassName;
         }

        
     
      }
   }

}
  • process()
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
   Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
         () -> String.format("Only %s implementations are supported, got %s",
               AutoConfigurationImportSelector.class.getSimpleName(),
               deferredImportSelector.getClass().getName()));
   AutoConfigurationEntry autoConfigurationEntry =
       ((AutoConfigurationImportSelector) deferredImportSelector)
      .getAutoConfigurationEntry(annotationMetadata);
   this.autoConfigurationEntries.add(autoConfigurationEntry);
   for (String importClassName : autoConfigurationEntry.getConfigurations()) {
      this.entries.putIfAbsent(importClassName, annotationMetadata);
   }
}
  • getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    //获取注解的attribute  exclude excludeName
    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);
}
  • getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { 
    
   //读取 META-INF/spring.factories
   List<String> configurations = 
       new ArrayList<>(SpringFactoriesLoader.
                       loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
    
   //读取 META-INF/spring/%s.imports
   ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
       .forEach(configurations::add);
    
   Assert.notEmpty(configurations,
         "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
               + "are using a custom packaging, make sure that file is correct.");
   return configurations;
}
  • SpringFactoriesLoader.loadFactoryNames()

    兼容老版本的 META-INF/spring.factories

    适配springboot2.7.0以下

    # springboot2.6.13
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
    org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
    org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
    ............
    
    
  • ImportCandidates.load

    2.7.0新版本读取 META-INF/spring/%s.imports

public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
   Assert.notNull(annotation, "'annotation' must not be null");
   ClassLoader classLoaderToUse = decideClassloader(classLoader);
   String location = String.format(LOCATION, annotation.getName());
    // META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
   Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
   List<String> importCandidates = new ArrayList<>();
   while (urls.hasMoreElements()) {
      URL url = urls.nextElement();
      importCandidates.addAll(readCandidateConfigurations(url));
   }
   return new ImportCandidates(importCandidates);
}

image-20230414181533857

@ComponentScan

组件包扫描

SpringBoot-autoConfiguration

启动过程

@SpringBootApplication
public class SourcecodeApplication {
    public static void main(String[] args) {
        SpringApplication.run(SourcecodeApplication.class, args);
    }
}
  • 跟进run()

    可以发现又调用了新的run()

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
   return run(new Class<?>[] { primarySource }, args);
}
  • 跟进run()

    这个方法主要做了两件事

    • 创建SpringApplication实例
    • 执行实例的run()方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}

创建SpringApplication实例

  • 调用其他构造方法
public SpringApplication(Class<?>... primarySources) {
   this(null, primarySources);
}
  • 跟进
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   //初始化resourceLoader
   this.resourceLoader = resourceLoader;
   //断言 primarySources不为空
   Assert.notNull(primarySources, "PrimarySources must not be null");
   // primarySources 的变量提升
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   /**
   		判断应用的类型
   			- NONE
   			- SERVLET
   			- REACTIVE
   */ 
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   //获取 BootstrapRegistryInitializer 类型的参数集合
   this.bootstrapRegistryInitializers = new ArrayList<>(
         getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
   // 获取所有的 ApplicationContextInitializer 实例	
   setInitializers((Colection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   // 获取所有监听器实例
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   //确定应用程序的主类
   this.mainApplicationClass = deduceMainApplicationClass();
}
  • WebApplicationType.deduceFromClasspath()
static WebApplicationType deduceFromClasspath() {
   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
   for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
   return WebApplicationType.SERVLET;
}
  • getSpringFactoriesInstances
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
   ClassLoader classLoader = getClassLoader();
   // 获取spring.fatories
   Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
   // 实例化类
   List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
   return instances;
}

运行示例run

public ConfigurableApplicationContext run(String... args) {
   // 启动计时
   long startime = System.nanoTime();
   // 创建一个引导类的上下文
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   //ioc 容器声明
   ConfigurableApplicationContext context = null;
   // 用于配置是否运行在无头模式 headless mode
   configureHeadlessProperty();
   // 获取监听器列表
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 启动监听器
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
      //创建一个 ApplicationArguments 对象,表示应用程序启动时的命令行参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 准备应用程序的环境,包括加载配置文件、解析命令行参数等。
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      // 配置是否忽略 JavaBean 的信息
      configureIgnoreBeanInfo(environment);
      // 打印Banner,
      Banner printedBanner = printBanner(environment);
      // 创建应用程序上下文对象
      context = createApplicationContext();
      
      context.setApplicationStartup(this.applicationStartup);
       // 配置context的基本信息
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      /**
      刷新context
      里面包括了spring 容器的qidong
      springboot自动配置
      初始化web容器
      */
      refreshContext(context);
      // 刷新的后置处理
      afterRefresh(context, applicationArguments);
      //打印运行时间
      Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
      }
       // 发布监听应用并启动事件
      listeners.started(context, timeTakenToStartup);
       // 执行runners (回调)初始化参数
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }
   try {
      Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
      listeners.ready(context, timeTakenToReady);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

SpringBootRUN