spring boot 源码分析

一、spring boot 执行流程

例子:

1
2
3
4
   public static void main(String[] args) {
       SpringApplication.run(SampleWebFluxApplication.class);
   }

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 /**
 	 * Static helper that can be used to run a {@link SpringApplication} from the
 	 * specified source using default settings.
 	 * @param primarySource the primary source to load
 	 * @param args the application arguments (usually passed from a Java main method)
 	 * @return the running {@link ApplicationContext}
 	 */
 	public static ConfigurableApplicationContext run(Class<?> primarySource,
 			String... args) {
 		return run(new Class<?>[] { primarySource }, args);
 	}
 
 	/**
 	 * Static helper that can be used to run a {@link SpringApplication} from the
 	 * specified sources using default settings and user supplied arguments.
 	 * @param primarySources the primary sources to load
 	 * @param args the application arguments (usually passed from a Java main method)
 	 * @return the running {@link ApplicationContext}
 	 */
 	public static ConfigurableApplicationContext run(Class<?>[] primarySources,
 			String[] args) {
 		return new SpringApplication(primarySources).run(args);
 	}

二. SpringApplication 构造,进行初始化操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  public SpringApplication(Class<?>... primarySources) {
       this(null, primarySources);
   }

   /**
    * Create a new {@link SpringApplication} instance. The application context will load
    * beans from the specified primary sources (see {@link SpringApplication class-level}
    * documentation for details. The instance can be customized before calling
    * {@link #run(String...)}.
    * @param resourceLoader the resource loader to use
    * @param primarySources the primary bean sources
    * @see #run(Class, String[])
    * @see #setSources(Set)
    */
   @SuppressWarnings({ "unchecked", "rawtypes" })
   public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
       this.resourceLoader = resourceLoader;
       Assert.notNull(primarySources, "PrimarySources must not be null");
       this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
       this.webApplicationType = deduceWebApplicationType();
       //spring boot实现自己SPI,在META-INF/spring.factories中查询定义ApplicationContextInitializer
       setInitializers((Collection) getSpringFactoriesInstances(
               ApplicationContextInitializer.class));
       //监听集合ApplicationListener
       setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
       //运用异常堆栈跟踪(RuntimeException().getStackTrace())查询main类的Class
       this.mainApplicationClass = deduceMainApplicationClass();
   }

1.deduceWebApplicationType 获取应用类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  private WebApplicationType deduceWebApplicationType() {
      if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
              && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
              && !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
          return WebApplicationType.REACTIVE;
      }
      for (String className : WEB_ENVIRONMENT_CLASSES) {
          if (!ClassUtils.isPresent(className, null)) {
              return WebApplicationType.NONE;
          }
      }
      return WebApplicationType.SERVLET;
  }  

(1).REACTIVE_WEB_ENVIRONMENT_CLASS ==> org.springframework.web.reactive.DispatcherHandler

三. SpringApplication run

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
   public ConfigurableApplicationContext run(String... args) {
       //记录执行时间
       StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       ConfigurableApplicationContext context = null;
       Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
       //调用configureHeadlessProperty设置系统属性java.awt.headless,这里设置为true,
       // 表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能,显示服务器端运行
       configureHeadlessProperty();
       //1.创建SpringApplicationRunListener集合,做事件广播
       SpringApplicationRunListeners listeners = getRunListeners(args);
       // 触发starting
       listeners.starting();
       try {
           //2.解析运行参数;提供对用于运行{@link SpringApplication}的参数的访问。
           ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                   args);
           //3.ConfigurableEnvironment
           ConfigurableEnvironment environment = prepareEnvironment(listeners,
                   applicationArguments);
           configureIgnoreBeanInfo(environment);
           //4.Banner
           Banner printedBanner = printBanner(environment);
           //5.根据webApplicationType创建不同的ApplicationContext;
           //  默认:AnnotationConfigApplicationContext
           //  SERVLET:AnnotationConfigServletWebServerApplicationContext
           //  REACTIVE:AnnotationConfigReactiveWebServerApplicationContext
           context = createApplicationContext();
           //6.异常上报分析;
           // # Error Reporters
           //   org.springframework.boot.SpringBootExceptionReporter=\
           //   org.springframework.boot.diagnostics.FailureAnalyzers
           exceptionReporters = getSpringFactoriesInstances(
                   SpringBootExceptionReporter.class,
                   new Class[] { ConfigurableApplicationContext.class }, context);
           //7.准备ApplicationContext
           prepareContext(context, environment, listeners, applicationArguments,
                   printedBanner);
           //8.调用ApplicationContext.refresh方法
           refreshContext(context);
           //9.钩子方法
           afterRefresh(context, applicationArguments);
           stopWatch.stop();
           if (this.logStartupInfo) {
               new StartupInfoLogger(this.mainApplicationClass)
                       .logStarted(getApplicationLog(), stopWatch);
           }
           //10.触发started事件
           listeners.started(context);
           //11.BeanFactory查询ApplicationRunner和CommandLineRunner集合触发run方法
           callRunners(context, applicationArguments);
       }
       catch (Throwable ex) {
           handleRunFailure(context, ex, exceptionReporters, listeners);
           throw new IllegalStateException(ex);
       }

       try {
           listeners.running(context);
       }
       catch (Throwable ex) {
           handleRunFailure(context, ex, exceptionReporters, null);
           throw new IllegalStateException(ex);
       }
       return context;
   }

1. SpringApplicationRunListener

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
   public interface SpringApplicationRunListener {
   
       /**
        * Called immediately when the run method has first started. Can be used for very
        * early initialization.
        * 首次启动run方法时立即调用。, 可用于非常早期的初始化。
        */
       void starting();
   
       /**
        * Called once the environment has been prepared, but before the
        * {@link ApplicationContext} has been created.
        * 一旦准备好环境,但在创建{@link ApplicationContext}之前调用。
        * @param environment the environment
        */
       void environmentPrepared(ConfigurableEnvironment environment);
   
       /**
        * Called once the {@link ApplicationContext} has been created and prepared, but
        * before sources have been loaded.
        * 一旦{@link ApplicationContext}被创建并准备好,但在加载源之前调用。
        * @param context the application context
        */
       void contextPrepared(ConfigurableApplicationContext context);
   
       /**
        * Called once the application context has been loaded but before it has been
        * refreshed.
        * 在应用程序上下文加载之后但在刷新之前调用。
        * @param context the application context
        */
       void contextLoaded(ConfigurableApplicationContext context);
   
       /**
        * The context has been refreshed and the application has started but
        * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
        * ApplicationRunners} have not been called.
        * 上下文已刷新且应用程序已启动,但尚未调用{@link CommandLineRunner CommandLineRunners}
        * 和{@link ApplicationRunner ApplicationRunners}。
        * @param context the application context.
        * @since 2.0.0
        */
       void started(ConfigurableApplicationContext context);
   
       /**
        * Called immediately before the run method finishes, when the application context has
        * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
        * {@link ApplicationRunner ApplicationRunners} have been called.
        * 在run方法完成之前立即调用,刷新应用程序上下文并调用所有{@link CommandLineRunner CommandLineRunners}
        * 和{@link ApplicationRunner ApplicationRunners}。
        * @param context the application context.
        * @since 2.0.0
        */
       void running(ConfigurableApplicationContext context);
   
       /**
        * Called when a failure occurs when running the application.
        * 在运行应用程序时发生故障时调用。
        * @param context the application context or {@code null} if a failure occurred before
        * the context was created
        * @param exception the failure
        * @since 2.0.0
        */
       void failed(ConfigurableApplicationContext context, Throwable exception);
   
   }

从接口方法描述来看,SpringApplicationRunListener就是启动事件监听;在在META-INF/spring.factories中查询定义ApplicationContextInitializer

EventPublishingRunListener实现SpringApplicationRunListener接口;

(1).EventPublishingRunListener

1
2
3
4
5
6
7
8
   public EventPublishingRunListener(SpringApplication application, String[] args) {
       this.application = application;
       this.args = args;
       this.initialMulticaster = new SimpleApplicationEventMulticaster();
       for (ApplicationListener<?> listener : application.getListeners()) {
           this.initialMulticaster.addApplicationListener(listener);
       }
   }

从EventPublishingRunListener构造来看,主要用到spring的事件广播做事件触发,这里主要观察模式,实现事件触发;监听ApplicationListener接口;

(2).getListeners()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  // spring.factories

# Application Listeners
org.springframework.context.ApplicationListener=\
# 接受ContextRefreshedEvent事件,清楚缓存
org.springframework.boot.ClearCachesApplicationListener,\
# ParentContextAvailableEvent,关闭父类上下文
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
# ApplicationEnvironmentPreparedEvent environment环境做验证
org.springframework.boot.context.FileEncodingApplicationListener,\
# ApplicationEnvironmentPreparedEvent
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
# ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
org.springframework.boot.context.config.ConfigFileApplicationListener,\
# ApplicationEnvironmentPreparedEvent
org.springframework.boot.context.config.DelegatingApplicationListener,\
# ApplicationEnvironmentPreparedEvent ApplicationFailedEvent 日志打印
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
# ApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
org.springframework.boot.context.logging.LoggingApplicationListener,\
# ApplicationStartingEvent
# Liquibase 是一个用于跟踪,管理和应用数据库变化的开源的数据库重构工具
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

这里在构造初始化就加载;

2. ApplicationArguments

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public interface ApplicationArguments {

  /**
   * Return the raw unprocessed arguments that were passed to the application.
   * 返回传递给应用程序的原始未处理参数。
   * @return the arguments
   */
  String[] getSourceArgs();

  /**
   * Return the names of all option arguments. For example, if the arguments were
   * "--foo=bar --debug" would return the values {@code ["foo", "debug"]}.
   * 返回所有选项参数的名称。, 例如,如果参数为“--foo = bar --debug”,则返回值{@code [“foo”,“debug”]}。
   * @return the option names or an empty set
   */
  Set<String> getOptionNames();

  /**
   * Return whether the set of option arguments parsed from the arguments contains an
   * option with the given name.
   * 返回从参数解析的选项参数集是否包含具有给定名称的选项。
   * @param name the name to check
   * @return {@code true} if the arguments contain an option with the given name
   */
  boolean containsOption(String name);

  /**
   * Return the collection of values associated with the arguments option having the
   * given name.
   * 返回与具有给定名称的arguments选项关联的值集合。
   * <ul>
   * <li>if the option is present and has no argument (e.g.: "--foo"), return an empty
   * collection ({@code []})</li>
   * 如果选项存在但没有参数(例如:“ -  foo”),则返回一个空的集合({@code []}
   * <li>if the option is present and has a single value (e.g. "--foo=bar"), return a
   * collection having one element ({@code ["bar"]})</li>
   * 如果该选项存在并且具有单个值(例如“--foo = bar”),则返回具有一个元素的集合({@code [“bar”]})
   * <li>if the option is present and has multiple values (e.g. "--foo=bar --foo=baz"),
   * return a collection having elements for each value ({@code ["bar", "baz"]})</li>
   * 如果该选项存在且具有多个值(例如“--foo = bar --foo = baz”),返回一个包含每个值元素的集合({@code [“bar”,“baz”]})
   * <li>if the option is not present, return {@code null}</li>
   * 如果该选项不存在,请返回{@code null}
   * </ul>
   * @param name the name of the option
   * @return a list of option values for the given name
   */
  List<String> getOptionValues(String name);

  /**
   * Return the collection of non-option arguments parsed.
   * 返回已解析的非选项参数的集合。
   * @return the non-option arguments or an empty list
   */
  List<String> getNonOptionArgs();
  }

DefaultApplicationArguments实现ApplicationArguments接口;

(1). DefaultApplicationArguments

1
2
3
4
5
   public DefaultApplicationArguments(String[] args) {
       Assert.notNull(args, "Args must not be null");
       this.source = new Source(args);
       this.args = args;
   }

从DefaultApplicationArguments构造看出,委托Source处理运行参数解析;最终用SimpleCommandLineArgsParser解析运行参数解析;

3. prepareEnvironment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
  private ConfigurableEnvironment prepareEnvironment(
          SpringApplicationRunListeners listeners,
          ApplicationArguments applicationArguments) {
      // Create and configure the environment
      //创建和配置环境,根据web类型创建不同的ConfigurableEnvironment;
      ConfigurableEnvironment environment = getOrCreateEnvironment();
      //配置ConfigurableEnvironment
      // 运行参数添加到配置环境中
      // 配置Profiles
      configureEnvironment(environment, applicationArguments.getSourceArgs());
      //触发environmentPrepared事件,ApplicationEnvironmentPreparedEvent
      listeners.environmentPrepared(environment);
      bindToSpringApplication(environment);
      if (!this.isCustomEnvironment) {
          environment = new EnvironmentConverter(getClassLoader())
                  .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
      }
      ConfigurationPropertySources.attach(environment);
      return environment;
  }

(1).根据不同类型获取不同的Environment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
   private ConfigurableEnvironment getOrCreateEnvironment() {
       if (this.environment != null) {
           return this.environment;
       }
       switch (this.webApplicationType) {
       case SERVLET:
           return new StandardServletEnvironment();
       case REACTIVE:
           return new StandardReactiveWebEnvironment();
       default:
           return new StandardEnvironment();
       }
   } 

(2). prepareEnvironment触发ApplicationEnvironmentPreparedEvent事件,触发ConfigFileApplicationListener监听

EnvironmentPostProcessor,通过从众所周知的文件位置加载属性来配置上下文环境。默认情况下, 属性将从以下位置的“application.properties”和/或“application.yml”文件加载:

classpath: file:./ classpath:config/ file:./config/:

可以使用setSearchLocations(String)和setSearchNames(String)指定备用搜索位置和名称。

还将根据活动配置文件加载其他文件。例如,如果“web”配置文件处于活动状态,则会考虑“application-web.properties”和“application-web.yml”。

‘spring.config.name’属性可用于指定要加载的备用名称,‘spring.config.location’属性可用于指定备用搜索位置或特定文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Override
  public void onApplicationEvent(ApplicationEvent event) {
      if (event instanceof ApplicationEnvironmentPreparedEvent) {
          //触发环境配置事件
          onApplicationEnvironmentPreparedEvent(
                  (ApplicationEnvironmentPreparedEvent) event);
      }
      if (event instanceof ApplicationPreparedEvent) {
          onApplicationPreparedEvent(event);
      }
  }

  private void onApplicationEnvironmentPreparedEvent(
          ApplicationEnvironmentPreparedEvent event) {
      //从META-INF/spring.factories查询EnvironmentPostProcessor
      //# Environment Post Processors
      //  org.springframework.boot.env.EnvironmentPostProcessor=\
      //  org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
      //  org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
      //  org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
      List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
      postProcessors.add(this);
      AnnotationAwareOrderComparator.sort(postProcessors);
      for (EnvironmentPostProcessor postProcessor : postProcessors) {
          postProcessor.postProcessEnvironment(event.getEnvironment(),
                  event.getSpringApplication());
      }
  }

  List<EnvironmentPostProcessor> loadPostProcessors() {
      return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,
              getClass().getClassLoader());
  }
  • CloudFoundryVcapEnvironmentPostProcessor

    处理CloudFoundry.则将vcap.application., vcap.services. 的配置加入到Properties中. 接下来判断 environment中是否有commandLineArgs的Sources.如果有的话,则添加到commandLineArgs中, 否则添加名为vcap的PropertiesPropertySource.

  • SpringApplicationJsonEnvironmentPostProcessor

    将spring.application.json,SPRING_APPLICATION_JSON的值转化为Map保存配置中;

  • SystemEnvironmentPropertySourceEnvironmentPostProcessor

    将systemEnvironment配置转化为SystemEnvironmentPropertySource

  • ConfigFileApplicationListener实现EnvironmentPostProcessor接口,ConfigFileApplicationListener.Loader类实现

    获得ActiveProfiles.将未激活的Profiles加入到profiles中.如果profiles为空的话,就将spring.profiles.default配置的profile添加到profiles中. 依次遍历profiles中的profile.依次在classpath:/,classpath:/config/,file:./,file:./config/中加载application的配置.调用ConfigFileApplicationListener$Loader#load进行加载.

3.FailureAnalyzers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

   FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
       Assert.notNull(context, "Context must not be null");
       this.classLoader = (classLoader != null) ? classLoader : context.getClassLoader();
       this.analyzers = loadFailureAnalyzers(this.classLoader);
       prepareFailureAnalyzers(this.analyzers, context);
   }

   private List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
      //# Failure Analyzers
      //  org.springframework.boot.diagnostics.FailureAnalyzer=\
      //  org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\处理BeanCurrentlyInCreationException异常
      //  org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\处理BeanNotOfRequiredTypeException
      //  org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\处理BindException
      //  org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\处理BindValidationException
      //  org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\UnboundConfigurationPropertiesException
      //  org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ConnectorStartFailedException
      //  org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\NoSuchMethodError
      //  org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\NoUniqueBeanDefinitionException
      //  org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\PortInUseException
      //  org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\ValidationException
      //  org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\InvalidConfigurationPropertyNameException
      //  org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer:InvalidConfigurationPropertyValueException
       List<String> analyzerNames = SpringFactoriesLoader
               .loadFactoryNames(FailureAnalyzer.class, classLoader);
       List<FailureAnalyzer> analyzers = new ArrayList<>();
       for (String analyzerName : analyzerNames) {
           try {
               Constructor<?> constructor = ClassUtils.forName(analyzerName, classLoader)
                       .getDeclaredConstructor();
               ReflectionUtils.makeAccessible(constructor);
               analyzers.add((FailureAnalyzer) constructor.newInstance());
           }
           catch (Throwable ex) {
               logger.trace("Failed to load " + analyzerName, ex);
           }
       }
       AnnotationAwareOrderComparator.sort(analyzers);
       return analyzers;
   }

   private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
           ConfigurableApplicationContext context) {
       for (FailureAnalyzer analyzer : analyzers) {
           prepareAnalyzer(context, analyzer);
       }
   }

   private void prepareAnalyzer(ConfigurableApplicationContext context,
           FailureAnalyzer analyzer) {
       if (analyzer instanceof BeanFactoryAware) {
           ((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
       }
       if (analyzer instanceof EnvironmentAware) {
           ((EnvironmentAware) analyzer).setEnvironment(context.getEnvironment());
       }
   }

构造方法主要作用添加FailureAnalyzer集合,做错误分析;从META-INF/spring.factories查找FailureAnalyzer;

(1).reportException方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  @Override
  public boolean reportException(Throwable failure) {
      FailureAnalysis analysis = analyze(failure, this.analyzers);
      return report(analysis, this.classLoader);
  }

  private FailureAnalysis analyze(Throwable failure, List<FailureAnalyzer> analyzers) {
      for (FailureAnalyzer analyzer : analyzers) {
          try {
              FailureAnalysis analysis = analyzer.analyze(failure);
              if (analysis != null) {
                  return analysis;
              }
          }
          catch (Throwable ex) {
              logger.debug("FailureAnalyzer " + analyzer + " failed", ex);
          }
      }
      return null;
  }

  private boolean report(FailureAnalysis analysis, ClassLoader classLoader) {
  //# FailureAnalysisReporters
  //  org.springframework.boot.diagnostics.FailureAnalysisReporter=\
  //  org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
      List<FailureAnalysisReporter> reporters = SpringFactoriesLoader
              .loadFactories(FailureAnalysisReporter.class, classLoader);
      if (analysis == null || reporters.isEmpty()) {
          return false;
      }
      for (FailureAnalysisReporter reporter : reporters) {
          reporter.report(analysis);
      }
      return true;
  }

分析异常处理,上报FailureAnalysisReporter,进行相应处理,这里默认LoggingFailureAnalysisReporter,上报日志输出;

4.prepareContext

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

   private void prepareContext(ConfigurableApplicationContext context,
           ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
           ApplicationArguments applicationArguments, Banner printedBanner) {
       // 1. 上下文设置配置环境
       context.setEnvironment(environment);
       //2. 调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)
       postProcessApplicationContext(context);
       //3. SpringApplication构造时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化
       applyInitializers(context);
       //4. 触发contextPrepareds事件
       listeners.contextPrepared(context);
       //5. 打印启动日志
       if (this.logStartupInfo) {
           logStartupInfo(context.getParent() == null);
           logStartupProfileInfo(context);
       }

       // Add boot specific singleton beans
       //6. bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象
       context.getBeanFactory().registerSingleton("springApplicationArguments",
               applicationArguments);
       if (printedBanner != null) {
           //7. bean的名字是springBootBanner,bean的实例是之前实例化的printedBanner对象
           context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
       }

       // Load the sources
       // 启动类调用SpringApplication.run(Application.class, args),run第一个参数;
       Set<Object> sources = getAllSources();
       Assert.notEmpty(sources, "Sources must not be empty");
       // 8. SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法
       load(context, sources.toArray(new Object[0]));
       // 9. 触发contextLoaded事件; 调用listeners的contextLoaded方法,说明上下文已经加载,
       // 该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,
       // 那么在这一步会调用它的setApplicationContext方法,设置context
       listeners.contextLoaded(context);
   }

(1).BeanDefinitionLoader

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
   
  BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
      Assert.notNull(registry, "Registry must not be null");
      Assert.notEmpty(sources, "Sources must not be empty");
      this.sources = sources;
      //创建一个读取注解的Bean定义读取器,并将其设置到容器中 
      this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
      //解析xml配置
      this.xmlReader = new XmlBeanDefinitionReader(registry);
      if (isGroovyPresent()) {
          this.groovyReader = new GroovyBeanDefinitionReader(registry);
      }
      //创建一个扫描指定类路径中注解Bean定义的扫描器,并将其设置到容器中  
      this.scanner = new ClassPathBeanDefinitionScanner(registry);
      //添加排除过滤器类
      this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
  

(2).BeanDefinitionLoader.load

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public int load() {
       int count = 0;
       for (Object source : this.sources) {
           count += load(source);
       }
       return count;
   }

   private int load(Object source) {
       Assert.notNull(source, "Source must not be null");
       if (source instanceof Class<?>) {
           return load((Class<?>) source);//AnnotatedBeanDefinitionReader
       }
       if (source instanceof Resource) {
           return load((Resource) source);//XmlBeanDefinitionReader
       }
       if (source instanceof Package) {
           return load((Package) source);//ClassPathBeanDefinitionScanner
       }
       if (source instanceof CharSequence) {
           return load((CharSequence) source);
       }
       throw new IllegalArgumentException("Invalid source type " + source.getClass());
   }

   private int load(Class<?> source) {
       if (isGroovyPresent()
               && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
           // Any GroovyLoaders added in beans{} DSL can contribute beans here
           GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                   GroovyBeanDefinitionSource.class);
           load(loader);
       }
       if (isComponent(source)) {
           //调用AnnotatedBeanDefinitionReader
           this.annotatedReader.register(source);
           return 1;
       }
       return 0;
   }

四、AnnotatedBeanDefinitionReader 解说

1.构造

1
2
3
4
5
6
7
  public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
      Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
      Assert.notNull(environment, "Environment must not be null");
      this.registry = registry;
      this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  }  

(1).AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

注册注解相应的processors

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
    * Register all relevant annotation post processors in the given registry.
    * @param registry the registry to operate on
    * @param source the configuration source element (already extracted)
    * that this registration was triggered from. May be {@code null}.
    * @return a Set of BeanDefinitionHolders, containing all bean definitions
    * that have actually been registered by this call
    */
   public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
           BeanDefinitionRegistry registry, @Nullable Object source) {

       DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
       if (beanFactory != null) {
           //注解排序
           if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
               beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
           }
           if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
               beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
           }
       }

       Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
       //@Configuration @Bean解析,这个是注解BeanDefinitionRegistryPostProcessor的核心
       if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
       // 处理@Autowired,以及javax.inject.Inject
       if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
       //处理@Required
       if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
       //JSR-250 支持@PostConstruct,@PreDestroy已经Resource注解
       // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
       if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
        //JPA支持
       // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
       if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition();
           try {
               def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                       AnnotationConfigUtils.class.getClassLoader()));
           }
           catch (ClassNotFoundException ex) {
               throw new IllegalStateException(
                       "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
           }
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
       }
       //@EventListener注解支持
       if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
       }
       //创建DefaultEventListenerFactory,创建ApplicationListenerMethodAdapter
       if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
           RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
           def.setSource(source);
           beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
       }

       return beanDefs;
   }

五、ConfigurationClassPostProcessor 解说

ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor已经BeanFactoryPostProcessor接口,先触发postProcessBeanDefinitionRegistry,再触发postProcessBeanFactory

1.postProcessBeanDefinitionRegistry

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
       int registryId = System.identityHashCode(registry);
       if (this.registriesPostProcessed.contains(registryId)) {
           throw new IllegalStateException(
                   "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
       }
       if (this.factoriesPostProcessed.contains(registryId)) {
           throw new IllegalStateException(
                   "postProcessBeanFactory already called on this post-processor against " + registry);
       }
       this.registriesPostProcessed.add(registryId);

       processConfigBeanDefinitions(registry);
   }

(1).processConfigBeanDefinitions 贯穿所有核心

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
  /**
   * Build and validate a configuration model based on the registry of
   * {@link Configuration} classes.
   */
  public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
      List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
      String[] candidateNames = registry.getBeanDefinitionNames();
      //1.第一次只有@SpringBootApplication注解main类
      for (String beanName : candidateNames) {
          BeanDefinition beanDef = registry.getBeanDefinition(beanName);
          if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                  ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
              if (logger.isDebugEnabled()) {
                  logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
              }
          }
          //注解判断,分两类:
          // 1.Configuration  设置属性configurationClass -> full
          // 2.Component,ComponentScan,Import,ImportResource,Bean 设置属性configurationClass -> lite
          else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
              configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
          }
      }

      // Return immediately if no @Configuration classes were found
      if (configCandidates.isEmpty()) {
          return;
      }

      // Sort by previously determined @Order value, if applicable
      configCandidates.sort((bd1, bd2) -> {
          int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
          int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
          return Integer.compare(i1, i2);
      });

      // Detect any custom bean name generation strategy supplied through the enclosing application context
      SingletonBeanRegistry sbr = null;
      if (registry instanceof SingletonBeanRegistry) {
          sbr = (SingletonBeanRegistry) registry;
          if (!this.localBeanNameGeneratorSet) {
              BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
              if (generator != null) {
                  this.componentScanBeanNameGenerator = generator;
                  this.importBeanNameGenerator = generator;
              }
          }
      }

      if (this.environment == null) {
          this.environment = new StandardEnvironment();
      }

      // Parse each @Configuration class
     //到ConfigurationClassParser.parse 核心解析注解
      ConfigurationClassParser parser = new ConfigurationClassParser(
              this.metadataReaderFactory, this.problemReporter, this.environment,
              this.resourceLoader, this.componentScanBeanNameGenerator, registry);

      Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
      Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
      do {
          parser.parse(candidates);
          parser.validate();

          Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
          configClasses.removeAll(alreadyParsed);

          // Read the model and create bean definitions based on its content
          if (this.reader == null) {
              this.reader = new ConfigurationClassBeanDefinitionReader(
                      registry, this.sourceExtractor, this.resourceLoader, this.environment,
                      this.importBeanNameGenerator, parser.getImportRegistry());
          }
          this.reader.loadBeanDefinitions(configClasses);
          alreadyParsed.addAll(configClasses);

          candidates.clear();
          if (registry.getBeanDefinitionCount() > candidateNames.length) {
              String[] newCandidateNames = registry.getBeanDefinitionNames();
              Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
              Set<String> alreadyParsedClasses = new HashSet<>();
              for (ConfigurationClass configurationClass : alreadyParsed) {
                  alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
              }
              for (String candidateName : newCandidateNames) {
                  if (!oldCandidateNames.contains(candidateName)) {
                      BeanDefinition bd = registry.getBeanDefinition(candidateName);
                      if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                              !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                          candidates.add(new BeanDefinitionHolder(bd, candidateName));
                      }
                  }
              }
              candidateNames = newCandidateNames;
          }
      }
      while (!candidates.isEmpty());

      // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
      if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
          sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
      }

      if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
          // Clear cache in externally provided MetadataReaderFactory; this is a no-op
          // for a shared cache since it'll be cleared by the ApplicationContext.
          ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
      }
  }  

2.ConfigurationClassParser 解说

(1).parse

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   public void parse(Set<BeanDefinitionHolder> configCandidates) {
       this.deferredImportSelectors = new LinkedList<>();

       for (BeanDefinitionHolder holder : configCandidates) {
           BeanDefinition bd = holder.getBeanDefinition();
           try {
               if (bd instanceof AnnotatedBeanDefinition) {
                   parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
               }
               else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                   parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
               }
               else {
                   parse(bd.getBeanClassName(), holder.getBeanName());
               }
           }
           catch (BeanDefinitionStoreException ex) {
               throw ex;
           }
           catch (Throwable ex) {
               throw new BeanDefinitionStoreException(
                       "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
           }
       }

       processDeferredImportSelectors();
   } 
a.processConfigurationClass
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
      //@condition 注解处理
       if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
           return;
       }

       ConfigurationClass existingClass = this.configurationClasses.get(configClass);
       if (existingClass != null) {
           if (configClass.isImported()) {
               if (existingClass.isImported()) {
                   existingClass.mergeImportedBy(configClass);
               }
               // Otherwise ignore new imported config class; existing non-imported class overrides it.
               return;
           }
           else {
               // Explicit bean definition found, probably replacing an import.
               // Let's remove the old one and go with the new one.
               this.configurationClasses.remove(configClass);
               this.knownSuperclasses.values().removeIf(configClass::equals);
           }
       }

       // Recursively process the configuration class and its superclass hierarchy.
       SourceClass sourceClass = asSourceClass(configClass);
       do {
           sourceClass = doProcessConfigurationClass(configClass, sourceClass);
       }
       while (sourceClass != null);

       this.configurationClasses.put(configClass, configClass);
   } 
b.doProcessConfigurationClass
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
   /**
    * Apply processing and build a complete {@link ConfigurationClass} by reading the
    * annotations, members and methods from the source class. This method can be called
    * multiple times as relevant sources are discovered.
    * @param configClass the configuration class being build
    * @param sourceClass a source class
    * @return the superclass, or {@code null} if none found or previously processed
    */
   @Nullable
   protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
           throws IOException {

       // Recursively process any member (nested) classes first
       //处理内部类
       processMemberClasses(configClass, sourceClass);

       // Process any @PropertySource annotations
       //处理@PropertySource
       for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
               sourceClass.getMetadata(), PropertySources.class,
               org.springframework.context.annotation.PropertySource.class)) {
           if (this.environment instanceof ConfigurableEnvironment) {
               processPropertySource(propertySource);
           }
           else {
               logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                       "]. Reason: Environment must implement ConfigurableEnvironment");
           }
       }

       // Process any @ComponentScan annotations
       // 处理@ComponentScan ===> ComponentScanAnnotationParser.parse
       Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
               sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
       // conditionEvaluator进行@condition
       if (!componentScans.isEmpty() &&
               !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
           for (AnnotationAttributes componentScan : componentScans) {
               // The config class is annotated with @ComponentScan -> perform the scan immediately
               Set<BeanDefinitionHolder> scannedBeanDefinitions =
                       this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
               // Check the set of scanned definitions for any further config classes and parse recursively if needed
               for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                   BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                   if (bdCand == null) {
                       bdCand = holder.getBeanDefinition();
                   }
                   if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                       parse(bdCand.getBeanClassName(), holder.getBeanName());
                   }
               }
           }
       }

       // Process any @Import annotations
       // @Import 处理 
       //getImports(sourceClass) 收集@Import注解的处理的Class
       processImports(configClass, sourceClass, getImports(sourceClass), true);

       // Process any @ImportResource annotations
       // @ImportResource,处理XML
       AnnotationAttributes importResource =
               AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
       if (importResource != null) {
           String[] resources = importResource.getStringArray("locations");
           Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
           for (String resource : resources) {
               String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
               configClass.addImportedResource(resolvedResource, readerClass);
           }
       }

       // Process individual @Bean methods
       // @Bean methods
       Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
       for (MethodMetadata methodMetadata : beanMethods) {
           configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
       }

       // Process default methods on interfaces
       processInterfaces(configClass, sourceClass);

       // Process superclass, if any
       //处理父类
       if (sourceClass.getMetadata().hasSuperClass()) {
           String superclass = sourceClass.getMetadata().getSuperClassName();
           if (superclass != null && !superclass.startsWith("java") &&
                   !this.knownSuperclasses.containsKey(superclass)) {
               this.knownSuperclasses.put(superclass, configClass);
               // Superclass found, return its annotation metadata and recurse
               return sourceClass.getSuperClass();
           }
       }

       // No superclass -> processing is complete
       return null;
   } 
c.ComponentScanAnnotationParser.parse==>ClassPathBeanDefinitionScanner.doScan
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
       ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
               componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

       Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
       boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
       scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
               BeanUtils.instantiateClass(generatorClass));

       ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
       if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
           scanner.setScopedProxyMode(scopedProxyMode);
       }
       else {
           Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
           scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
       }

       scanner.setResourcePattern(componentScan.getString("resourcePattern"));

       for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
           for (TypeFilter typeFilter : typeFiltersFor(filter)) {
               scanner.addIncludeFilter(typeFilter);
           }
       }
       for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
           for (TypeFilter typeFilter : typeFiltersFor(filter)) {
               scanner.addExcludeFilter(typeFilter);
           }
       }

       boolean lazyInit = componentScan.getBoolean("lazyInit");
       if (lazyInit) {
           scanner.getBeanDefinitionDefaults().setLazyInit(true);
       }

       Set<String> basePackages = new LinkedHashSet<>();
       String[] basePackagesArray = componentScan.getStringArray("basePackages");
       for (String pkg : basePackagesArray) {
           String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                   ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
           Collections.addAll(basePackages, tokenized);
       }
       for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
           basePackages.add(ClassUtils.getPackageName(clazz));
       }
       if (basePackages.isEmpty()) {
           basePackages.add(ClassUtils.getPackageName(declaringClass));
       }

       scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
           @Override
           protected boolean matchClassName(String className) {
               return declaringClass.equals(className);
           }
       });
       return scanner.doScan(StringUtils.toStringArray(basePackages));
   }


d.processImports
转化为对象,分两类,ImportSelector和ImportBeanDefinitionRegistrar
  • ImportSelector 为DeferredImportSelector添加到deferredImportSelectors缓存中
  • ImportBeanDefinitionRegistrar 添加到ConfigurationClass缓存中
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
   private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
           Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

       if (importCandidates.isEmpty()) {
           return;
       }

       if (checkForCircularImports && isChainedImportOnStack(configClass)) {
           this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
       }
       else {
           this.importStack.push(configClass);
           try {
               for (SourceClass candidate : importCandidates) {
                   if (candidate.isAssignable(ImportSelector.class)) {
                       // Candidate class is an ImportSelector -> delegate to it to determine imports
                       Class<?> candidateClass = candidate.loadClass();
                       ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                       ParserStrategyUtils.invokeAwareMethods(
                               selector, this.environment, this.resourceLoader, this.registry);
                       if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                           this.deferredImportSelectors.add(
                                   new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
                       }
                       else {
                           String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                           Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                           processImports(configClass, currentSourceClass, importSourceClasses, false);
                       }
                   }
                   else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                       // Candidate class is an ImportBeanDefinitionRegistrar ->
                       // delegate to it to register additional bean definitions
                       Class<?> candidateClass = candidate.loadClass();
                       ImportBeanDefinitionRegistrar registrar =
                               BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                       ParserStrategyUtils.invokeAwareMethods(
                               registrar, this.environment, this.resourceLoader, this.registry);
                       configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                   }
                   else {
                       // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                       // process it as an @Configuration class
                       this.importStack.registerImport(
                               currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                       processConfigurationClass(candidate.asConfigClass(configClass));
                   }
               }
           }
           catch (BeanDefinitionStoreException ex) {
               throw ex;
           }
           catch (Throwable ex) {
               throw new BeanDefinitionStoreException(
                       "Failed to process import candidates for configuration class [" +
                       configClass.getMetadata().getClassName() + "]", ex);
           }
           finally {
               this.importStack.pop();
           }
       }
   } 

(2).processDeferredImportSelectors

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   private void processDeferredImportSelectors() {
       List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
       this.deferredImportSelectors = null;
       if (deferredImports == null) {
           return;
       }

       deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
       Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
       Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
       for (DeferredImportSelectorHolder deferredImport : deferredImports) {
           Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
           DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
                   (group != null ? group : deferredImport),
                   key -> new DeferredImportSelectorGrouping(createGroup(group)));
           grouping.add(deferredImport);
           configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                   deferredImport.getConfigurationClass());
       }
       for (DeferredImportSelectorGrouping grouping : groupings.values()) {
           grouping.getImports().forEach(entry -> {
               ConfigurationClass configurationClass = configurationClasses.get(entry.getMetadata());
               try {
                   processImports(configurationClass, asSourceClass(configurationClass),
                           asSourceClasses(entry.getImportClassName()), false);
               }
               catch (BeanDefinitionStoreException ex) {
                   throw ex;
               }
               catch (Throwable ex) {
                   throw new BeanDefinitionStoreException(
                           "Failed to process import candidates for configuration class [" +
                           configurationClass.getMetadata().getClassName() + "]", ex);
               }
           });
       }
   } 

3.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
   /**
    * Read {@code configurationModel}, registering bean definitions
    * with the registry based on its contents.
    */
   public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
       TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
       for (ConfigurationClass configClass : configurationModel) {
           loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
       }
   }

   /**
    * Read a particular {@link ConfigurationClass}, registering bean definitions
    * for the class itself and all of its {@link Bean} methods.
    */
   private void loadBeanDefinitionsForConfigurationClass(
           ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

       if (trackedConditionEvaluator.shouldSkip(configClass)) {
           String beanName = configClass.getBeanName();
           if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
               this.registry.removeBeanDefinition(beanName);
           }
           this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
           return;
       }

       if (configClass.isImported()) {
           registerBeanDefinitionForImportedConfigurationClass(configClass);
       }
       for (BeanMethod beanMethod : configClass.getBeanMethods()) {
           loadBeanDefinitionsForBeanMethod(beanMethod);
       } 

       loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
       // 触发ImportBeanDefinitionRegistrar
       loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
   }

六、ImportBeanDefinitionRegistrar接口自动配置

1.@SpringBootApplication

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@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 {

   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   @AliasFor(annotation = EnableAutoConfiguration.class)
   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
    */
   @AliasFor(annotation = EnableAutoConfiguration.class)
   String[] excludeName() default {};

   /**
    * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
    * for a type-safe alternative to String-based package names.
    * @return base packages to scan
    * @since 1.3.0
    */
   @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
   String[] scanBasePackages() default {};

   /**
    * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
    * scan for annotated components. The package of each class specified will be scanned.
    * <p>
    * Consider creating a special no-op marker class or interface in each package that
    * serves no purpose other than being referenced by this attribute.
    * @return base packages to scan
    * @since 1.3.0
    */
   @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
   Class<?>[] scanBasePackageClasses() default {};

}

2.@EnableAutoConfiguration,@AutoConfigurationPackage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@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 {};

} 

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

}

3.AutoConfigurationImportSelector.selectImports 获取自动配置信息进行管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  	@Override
  	public String[] selectImports(AnnotationMetadata annotationMetadata) {
  		if (!isEnabled(annotationMetadata)) {
  			return NO_IMPORTS;
  		}
        //META-INF/spring-autoconfigure-metadata.properties 这个配置
  		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  				.loadMetadata(this.beanClassLoader);
  		AnnotationAttributes attributes = getAttributes(annotationMetadata);
       //# 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,\....太多了
  		List<String> configurations = getCandidateConfigurations(annotationMetadata,
  				attributes);
  		configurations = removeDuplicates(configurations);
  		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  		checkExcludedClasses(configurations, exclusions);
  		configurations.removeAll(exclusions);
  		configurations = filter(configurations, autoConfigurationMetadata);
  		fireAutoConfigurationImportEvents(configurations, exclusions);
  		return StringUtils.toStringArray(configurations);
  	}

七、ConditionEvaluator处理@Conditional

1
2
3
4
 //配置
this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)
//bean
this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)

1.shouldSkip

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

   /**
    * Determine if an item should be skipped based on {@code @Conditional} annotations.
    * @param metadata the meta data
    * @param phase the phase of the call
    * @return if the item should be skipped
    */
   public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
       if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
           return false;
       }

       if (phase == null) {
           if (metadata instanceof AnnotationMetadata &&
                   ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
               return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
           }
           return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
       }

       List<Condition> conditions = new ArrayList<>();
       for (String[] conditionClasses : getConditionClasses(metadata)) {
           for (String conditionClass : conditionClasses) {
               Condition condition = getCondition(conditionClass, this.context.getClassLoader());
               conditions.add(condition);
           }
       }

       AnnotationAwareOrderComparator.sort(conditions);

       for (Condition condition : conditions) {
           ConfigurationPhase requiredPhase = null;
           if (condition instanceof ConfigurationCondition) {
               requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
           }
          //获取类型意义,已经比较matches
           if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
               return true;
           }
       }

       return false;
   }

2.Condition 接口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@FunctionalInterface
public interface Condition {

   /**
    * Determine if the condition matches.
    * @param context the condition context
    * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
    * or {@link org.springframework.core.type.MethodMetadata method} being checked
    * @return {@code true} if the condition matches and the component can be registered,
    * or {@code false} to veto the annotated component's registration
    */
   boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

} 

3.spring注解

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下。
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下。
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean 。
  • @ConditionalOnClass:当类路径下有指定类的条件下。
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下。
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件。
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web项 目的条件下。
  • @Profile

八、ConditionEvaluator处理@Conditional