SOFABoot源码解析之启动原理(2)-源码解析

        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc作为SOFABoot应用(其实也是SpringBoot应用)启动源码分析的案例。

        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。

        在该案例中,采用WEB环境下使用的Spring应用上下文环境org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext。

        在SofaBootRpcDemoApplication的main方法中,调用SpringApplication的静态方法(S   ofaBootRpcDemoApplication.class, args),启动应用: 

1.  publicstatic ConfigurableApplicationContext run(Object[] sources, String[] args) {
2.       return new SpringApplication(sources).run(args);
3.  }

一、  创建SpringApplication实例

        在run方法中,首先创建SpringApplication实例: 

1.  publicSpringApplication(Object... sources) {
2.       initialize(sources);
3.  }

        在SpringApplication构造函数中,调用initialize方法进行SpringApplication实例初始化工作: 

1.  privatevoid initialize(Object[] sources) {
2.       if(sources != null && sources.length > 0) {
3.           this.sources.addAll(Arrays.asList(sources));
4.       }
5.       this.webEnvironment= deduceWebEnvironment();
6.       setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
8.       setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
9.       this.mainApplicationClass= deduceMainApplicationClass();
10. }

        在SpringApplication实例初始化的时候,主要做以下几件事情:

        1.   根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型;

        2.   使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer;

        3.   使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener;

        4.   推断并设置main方法的定义类;

二、  启动SOFABoot应用

        SpringApplication实例初始化完成后,开始执行run方法,启动SOFABoot应用。 

1.  public ConfigurableApplicationContextrun(String... args) {
2.       StopWatchstopWatch = new StopWatch();
3.       stopWatch.start();
4.       ConfigurableApplicationContextcontext = null;
5.       FailureAnalyzersanalyzers = null;
6.       configureHeadlessProperty();
7.       SpringApplicationRunListenerslisteners = getRunListeners(args);
8.       listeners.started();
9.       try{
10.          ApplicationArgumentsapplicationArguments = new DefaultApplicationArguments(args);
12.          ConfigurableEnvironmentenvironment = prepareEnvironment(listeners,
13.                  applicationArguments);
14.          BannerprintedBanner = printBanner(environment);
15.          context = createApplicationContext();
16.          analyzers= new FailureAnalyzers(context);
17.          prepareContext(context, environment,listeners, applicationArguments,
18.                  printedBanner);
19.          refreshContext(context);
20.          afterRefresh(context,applicationArguments);
21.          listeners.finished(context,null);
22.          stopWatch.stop();
23.          if(this.logStartupInfo) {
24.              newStartupInfoLogger(this.mainApplicationClass)
25.                      .logStarted(getApplicationLog(),stopWatch);
26.          }
27.          returncontext;
28.      }
29.      catch(Throwable ex) {
30.          handleRunFailure(context,listeners, analyzers, ex);
31.          throw new IllegalStateException(ex);
32.      }
33. }

        启动SOFABoot应用的主要工作就是创建和刷新Spring应用上下文。此处采用AnnotationConfigEmbeddedWebApplicationContext作为Spring应用上下文的实现类。

        启动SOFABoot应用的主要步骤如下:

        (一)    创建StopWatch实例,并启动,记录任务的运行时间;

        (二)    设置系统属性java.awt.headless;

        (三)    通过SpringFactoriesLoader类loadFactoryNames方法,查找并加载所有spring.factories文件中定义的SpringApplicationRunListener接口的实现,并调用started方法启动监听器;

      (四)   创建Spring应用上下文AnnotationConfigEmbeddedWebApplicationContext:      
1.  protectedConfigurableApplicationContext createApplicationContext() {
2.       Class<?>contextClass = this.applicationContextClass;
3.       if(contextClass == null) {
4.           try{
5.               contextClass =Class.forName(this.webEnvironment
6.                       ?DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
7.           }
8.           catch(ClassNotFoundException ex) {
9.               thrownew IllegalStateException(……);
10.          }
11.      }
12.      return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass);
13. }

        此处是WEB环境,所以创建AnnotationConfigEmbeddedWebApplicationContext实例: 

1.  publicAnnotationConfigEmbeddedWebApplicationContext() {
2.       this.reader = new AnnotatedBeanDefinitionReader(this);
3.       this.scanner= new ClassPathBeanDefinitionScanner(this);
4.  }

        在AnnotationConfigEmbeddedWebApplicationContext构造函数中,创建AnnotatedBeanDefinitionReader实例,用来处理含有注解的类。创建ClassPathBeanDefinitionScanner实例,用来扫描指定路径下含有注解的类。由于SOFAbBoot主要采用JavaConfig的配置形式,所以此处主要看一下AnnotatedBeanDefinitionReader实例化过程,以了解注解相关处理器的注册过程: 

1.    publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environmentenvironment) {
2.            ……       
3.           AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
4.  }

    在Spring应用上下文中注册所有注解相关的Post Processors: 

1.  public staticSet<BeanDefinitionHolder> registerAnnotationConfigProcessors(
2.           BeanDefinitionRegistryregistry, Object source) {
3.   
4.       DefaultListableBeanFactorybeanFactory = unwrapDefaultListableBeanFactory(registry);
5.       ……   
6.       Set<BeanDefinitionHolder>beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
7.       if(!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)){
8.           RootBeanDefinitiondef = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
9.           def.setSource(source);
10.          beanDefs.add(registerPostProcessor(registry,def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
11.      }
12.  
13.      if(!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
14.          RootBeanDefinitiondef = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
15.          def.setSource(source);
16.          beanDefs.add(registerPostProcessor(registry,def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
17.      }
18.  
19.      if(!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
20.          RootBeanDefinitiondef = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
21.          def.setSource(source);
22.          beanDefs.add(registerPostProcessor(registry,def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
23.      }
24.  
25.      //Check for JSR-250 support, and if present add theCommonAnnotationBeanPostProcessor.
26.      if(jsr250Present &&!registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
27.          RootBeanDefinitiondef = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
28.          def.setSource(source);
29.          beanDefs.add(registerPostProcessor(registry,def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
30.      }
31.      ……   
32.      if(!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
33.          RootBeanDefinition def = newRootBeanDefinition(EventListenerMethodProcessor.class);
34.          def.setSource(source);
35.          beanDefs.add(registerPostProcessor(registry,def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
36.      }
37.      if(!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
38.          RootBeanDefinitiondef = new RootBeanDefinition(DefaultEventListenerFactory.class);
39.          def.setSource(source);
40.          beanDefs.add(registerPostProcessor(registry,def, EVENT_LISTENER_FACTORY_BEAN_NAME));
41.      }
42.  
43.      returnbeanDefs;
44. }

        与注解相关的PostProcessors主要包括ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,EventListenerMethodProcessor,PersistenceAnnotationBeanPostProcessor,DefaultEventListenerFactory。

        其中,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口。当刷新Spring上下文(调用AbstractApplicationContext类refresh方法)过程中,调用AbstractApplicationContext类invokeBeanFactoryPostProcessors方法时,被调用执行。ConfigurationClassPostProcessor解析@Configuration注解,调用ConfigurationClassParser类的parse方法,处理@ComponentScan、@Import、@ImportResource、@Bean注解。

        AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor实现了BeanPostProcessor接口,在创建Bean实例时被调用。例如:在刷新Spring上下文(调用AbstractApplicationContext类refresh方法)过程中,调用finishBeanFactoryInitialization方法时,在实例化所有单例Bean对象时被调用。

        EventListenerMethodProcessor,DefaultEventListenerFactory是事件监听器相关的PostProcessors。

        至此,创建AnnotationConfigEmbeddedWebApplicationContext实例的主要步骤完成。

         (五)   准备Spring应用上下文:      
1.  private voidprepareContext(ConfigurableApplicationContext context,
2.           ConfigurableEnvironmentenvironment, SpringApplicationRunListeners listeners,
3.           ApplicationArgumentsapplicationArguments, Banner printedBanner) {
4.       context.setEnvironment(environment);
5.       postProcessApplicationContext(context);
6.       applyInitializers(context);
7.       listeners.contextPrepared(context);
8.       if(this.logStartupInfo) {
9.           logStartupInfo(context.getParent()== null);
10.          logStartupProfileInfo(context);
11.      }
12.  
13.      //Add boot specific singleton beans
14.      context.getBeanFactory().registerSingleton("springApplicationArguments",
15.              applicationArguments);
16.      if(printedBanner != null) {
17.          context.getBeanFactory().registerSingleton("springBootBanner",printedBanner);
18.      }
19.  
20.      //Load the sources
21.      Set<Object>sources = getSources();
22.      Assert.notEmpty(sources,"Sources must not be empty");
23.      load(context, sources.toArray(newObject[sources.size()]));
24.      listeners.contextLoaded(context);
25. }

        1.   设置Spring应用上下文Enviroment;

        2.   设置Spring应用上下文属性,如beanNameGenerator、resourceLoader等;

        3.   依次调用通过SpringFactoriesLoader从spring.factories文件中加载的ApplicationContextInitializer接口的实现的initialize方法,完成Spring应用上下文的初始化工作; 

        4.   依次调用通过SpringFactoriesLoader从spring.factories文件中加载的SpringApplicationRunListener接口的实现的contextPrepared方法。该方法在Spring应用上下文创建完,并且前期准备工作完成,但加载资源以前,完成Spring应用上下文的一些处理工作;

        5.   创建BeanDefinitionLoader实例(构造函数中依次创建AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader、ClassPathBeanDefinitionScanner),然后调用该实例的load方法注册run方法中参数指定的source资源(此处为SofaBootRpcDemoApplication)到Spring应用上下文,这个资源是ConfigurationClassPostProcessor类处理的入口配置类,可以是一个或多个;

        6.   依次调用通过SpringFactoriesLoader从spring.factories文件中加载的SpringApplicationRunListener接口的实现的contextLoaded方法。该方法在Spring应用上下文已经被加载,但还没有刷新之前,完成Spring应用上下文的一些处理工作。

        (六)   刷新Spring应用上下文:
1.  public void refresh() throws BeansException,IllegalStateException {
2.       synchronized(this.startupShutdownMonitor) {
3.           //Prepare this context for refreshing.
4.           prepareRefresh();
5.   
6.           //Tell the subclass to refresh the internal bean factory.
7.           ConfigurableListableBeanFactorybeanFactory = obtainFreshBeanFactory();
8.   
9.           //Prepare the bean factory for use in this context.
10.          prepareBeanFactory(beanFactory);
11.  
12.          try{
13.              //Allows post-processing of the bean factory in context subclasses.
14.              postProcessBeanFactory(beanFactory);
15.  
16.              //Invoke factory processors registered as beans in the context.
17.              invokeBeanFactoryPostProcessors(beanFactory);
18.  
19.              //Register bean processors that intercept bean creation.
20.              registerBeanPostProcessors(beanFactory);
21.  
22.              //Initialize message source for this context.
23.              initMessageSource();
24.  
25.              //Initialize event multicaster for this context.
26.              initApplicationEventMulticaster();
27.  
28.              //Initialize other special beans in specific context subclasses.
29.              onRefresh();
30.  
31.              //Check for listener beans and register them.
32.              registerListeners();
33.  
34.              //Instantiate all remaining (non-lazy-init) singletons.
35.              finishBeanFactoryInitialization(beanFactory);
36.  
37.              //Last step: publish corresponding event.
38.              finishRefresh();
39.          }
40.  
41.          catch(BeansException ex) {
42.              if(logger.isWarnEnabled()) {
43.                  logger.warn("Exceptionencountered during context initialization - " +
44.                          "cancellingrefresh attempt: " + ex);
45.              }
46.  
47.              //Destroy already created singletons to avoid dangling resources.
48.              destroyBeans();
49.  
50.              //Reset 'active' flag.
51.              cancelRefresh(ex);
52.  
53.              //Propagate exception to caller.
54.              throwex;
55.          }
56.  
57.          finally{
58.              //Reset common introspection caches in Spring's core, since we
59.              //might not ever need metadata for singleton beans anymore...
60.              resetCommonCaches();
61.          }
62.      }
63. }

     看到这段代码,Spring开发人员都应该比较熟悉了。这段代码为Spring应用上下文的具体实现类调用父类AbstractApplicationContext的refresh方法进行刷新操作。对于整个Spring应用上下文刷新过程,大家应该都比较熟悉了,在此不详述了。

         此时,我们主要关注invokeBeanFactoryPostProcessors(beanFactory)方法:
1.  protected voidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2.       PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors());
3.   
4.       ……
5.  }

      该方法通过PostProcessorRegistrationDelegate调用所有实现BeanFactoryPostProcessor接口的实现类,完成beanFactory的一些处理工作。

1.  public static voidinvokeBeanFactoryPostProcessors(
2.           ConfigurableListableBeanFactorybeanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
3.   
4.       ……
5.   
6.           //First, invoke the BeanDefinitionRegistryPostProcessors that implementPriorityOrdered.
7.          ……
8.           invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors,registry);
9.   
10.          //Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
11.          ……
12.          invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors,registry);
13.  
14.          //Finally, invoke all other BeanDefinitionRegistryPostProcessors until no furtherones appear.
15.          ……
16.  
17.          //Now, invoke the postProcessBeanFactory callback of all processors handled sofar.
18.          invokeBeanFactoryPostProcessors(registryPostProcessors,beanFactory);
19.          invokeBeanFactoryPostProcessors(regularPostProcessors,beanFactory);
20.      }
21.  
22.      else{
23.          //Invoke factory processors registered with the context instance.
24.          invokeBeanFactoryPostProcessors(beanFactoryPostProcessors,beanFactory);
25.     }
26.  
27.      ……
28.      //Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
29.      //Ordered, and the rest.
30.      ……
31.      //First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
32.      ……
33.      invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors,beanFactory);
34.  
35.      //Next, invoke the BeanFactoryPostProcessors that implement Ordered.
36.      ……
37.      invokeBeanFactoryPostProcessors(orderedPostProcessors,beanFactory);
38.  
39.      //Finally, invoke all other BeanFactoryPostProcessors.
40.      ……
41.      invokeBeanFactoryPostProcessors(nonOrderedPostProcessors,beanFactory);
42.  
43.      ……
44. }
        在invokeBeanDefinitionRegistryPostProcessors方法中,调用实现了PriorityOrdered接口和BeanDefinitionRegistryPostProcessor接口的BeanFactoryPostProcessor的实现类ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法:
1.  public voidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
2.      
3.        RootBeanDefinition iabpp = newRootBeanDefinition(ImportAwareBeanPostProcessor.class);
4.       iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
5.       registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME,iabpp);
6.   
7.       RootBeanDefinitionecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
8.       ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
9.       registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME,ecbpp);
10.        ……
11.  
12.      processConfigBeanDefinitions(registry);
13. }

   Spring应用上下文中注册BeanPostProcessor接口的实现类ImportAwareBeanPostProcessor、EnhancedConfigurationBeanPostProcessor;

        调用processConfigBeanDefinitions方法,开始处理@Configuration配置类。

        注意 ,此处是整个应用中所有@Configuration配置类的处理入口。在整个@Configuration配置类处理过程中,循环处理所有@Configuration配置类,直至所有@Configuration配置类处理完。        
1.  public void processConfigBeanDefinitions(BeanDefinitionRegistryregistry) {
2.       List<BeanDefinitionHolder>configCandidates = new ArrayList<BeanDefinitionHolder>();
3.       String[]candidateNames = registry.getBeanDefinitionNames();
4.   
5.       for(String beanName : candidateNames) {
6.           BeanDefinitionbeanDef = registry.getBeanDefinition(beanName);
7.           if(ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
8.                   ConfigurationClassUtils.isLiteConfigurationClass(beanDef)){
9.               ……
10.          }
11.          elseif (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)) {
12.              configCandidates.add(newBeanDefinitionHolder(beanDef, beanName));
13.          }
14.      }
15.       ……
16.       ConfigurationClassParser parser = new ConfigurationClassParser(
17.              this.metadataReaderFactory,this.problemReporter, this.environment,
18.              this.resourceLoader,this.componentScanBeanNameGenerator, registry);
19.       ……
20.      do {
21.          parser.parse(candidates);
22.          parser.validate();
23.  
24.          ……
25.            // Read the model and create beandefinitions based on its content
26.          if(this.reader == null) {
27.              this.reader= new ConfigurationClassBeanDefinitionReader(
28.                      registry,this.sourceExtractor, this.resourceLoader, this.environment,
29.                      this.importBeanNameGenerator,parser.getImportRegistry());
30.          }
31.          this.reader.loadBeanDefinitions(configClasses);
32.          alreadyParsed.addAll(configClasses);
33.  
34.          candidates.clear();
35.          ……
36.            for (ConfigurationClassconfigurationClass : alreadyParsed) {
37.                  alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
38.              }
39.              for(String candidateName : newCandidateNames) {
40.                  if(!oldCandidateNames.contains(candidateName)) {
41.                      BeanDefinitionbeanDef = registry.getBeanDefinition(candidateName);
42.                      if(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory) &&
43.                              !alreadyParsedClasses.contains(beanDef.getBeanClassName())){
44.                          candidates.add(newBeanDefinitionHolder(beanDef, candidateName));
45.                      }
46.                  }
47.              }       
48.      }
49.      while (!candidates.isEmpty());
50.  
51.      ……
52. }

        @Configuration配置类主要处理步骤:

        1.   依次遍历DefaultListableBeanFactory中所有BeanDefinition,查找带有@Configuration注解的BeanDefinition,放入configCandidates。然后根据@order进行排序,此时只有一个包含@Configuration注解的类,即SofaBootRpcDemoApplication;

        2.   构造@Configuration注解的解析类ConfigurationClassParser;

        3.   依次遍历集合candidates中所有@Configuration配置类,逐一处理配置类中的注解,此时只有SofaBootRpcDemoApplication。
1.  public voidparse(Set<BeanDefinitionHolder> configCandidates) {
2.      
3.        this.deferredImportSelectors = newLinkedList<DeferredImportSelectorHolder>();
4.   
5.       for (BeanDefinitionHolder holder :configCandidates) {
6.           BeanDefinitionbd = holder.getBeanDefinition();
7.           try{
8.               if(bd instanceof AnnotatedBeanDefinition) {
9.                   parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
10.              }
11.              elseif (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
12.                  parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
13.              }
14.              else{
15.                  parse(bd.getBeanClassName(),holder.getBeanName());
16.              }
17.          }
18.          catch(BeanDefinitionStoreException ex) {
19.              throwex;
20.          }
21.          catch(Throwable ex) {
22.              thrownew BeanDefinitionStoreException(……);
23.          }
24.      }
25.      processDeferredImportSelectors();
26. }

          依次处理每个@Configuration配置类,具体处理操作在doProcessConfigurationClass方法中实现,由于该方法负责具体处理每个@Configuration配置类,稍后在后面具体介绍。

        处理完传入的@Configuration配置类以后,处理实现DeferredImportSelector接口的ImportSelector类,主要用于有条件的加载某些类,如使用@Conditional注解。
1.  private voidprocessDeferredImportSelectors() {
2.       List<DeferredImportSelectorHolder>deferredImports = this.deferredImportSelectors;
3.       ……
4.       for(DeferredImportSelectorHolder deferredImport : deferredImports) {
5.           ConfigurationClassconfigClass = deferredImport.getConfigurationClass();
6.           try{
7.               String[] imports =deferredImport.getImportSelector().selectImports(configClass.getMetadata());
8.               processImports(configClass,asSourceClass(configClass), asSourceClasses(imports), false);
9.           }
10.          catch(BeanDefinitionStoreException ex) {
11.              throwex;
12.          }
13.          catch(Throwable ex) {
14.              thrownew BeanDefinitionStoreException(……);
15.          }
16.      }
17. }

          依次处理所有实现DeferredImportSelector接口的ImportSelector类。

        第一次循环时,只有一个类,即由SofaBootRpcDemoApplication类导入的EnableAutoConfigurationImportSelector类,调用其selectImports方法,解析出所有支持自动配置的@Configuration配置类:
1.  public String[]selectImports(AnnotationMetadata metadata) {
2.       if(!isEnabled(metadata)) {
3.           returnNO_IMPORTS;
4.       }
5.       try{
6.           AnnotationAttributesattributes = getAttributes(metadata);
7.           List<String> configurations =getCandidateConfigurations(metadata,
8.                   attributes);
9.           configurations= removeDuplicates(configurations);
10.          Set<String>exclusions = getExclusions(metadata, attributes);
11.          configurations.removeAll(exclusions);
12.          configurations= sort(configurations);
13.          recordWithConditionEvaluationReport(configurations,exclusions);
14.          returnconfigurations.toArray(new String[configurations.size()]);
15.      }
16.      catch(IOException ex) {
17.          thrownew IllegalStateException(ex);
18.      }
19. }
          调用getCandidateConfigurations方法,获取所有@Configuration配置类的名字:        
1.  protected List<String>getCandidateConfigurations(AnnotationMetadata metadata,
2.           AnnotationAttributesattributes) {
3.       List<String> configurations =SpringFactoriesLoader.loadFactoryNames(
4.               getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
5.       ……
6.         return configurations;
7.  }
        通过SpringFactoriesLoader的loadFactoryNames方法,从所有的spring.fatories文件中,加载key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有@Configuration配置类的名字。
1.  public static List<String>loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
2.       StringfactoryClassName = factoryClass.getName();
3.       try{
4.           Enumeration<URL> urls = (classLoader !=null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
5.                   ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
6.           List<String>result = new ArrayList<String>();
7.           while (urls.hasMoreElements()) {
8.               URLurl = urls.nextElement();
9.               Propertiesproperties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
10.              StringfactoryClassNames = properties.getProperty(factoryClassName);
11.          result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
12.          }
13.          returnresult;
14.      }
15.      catch(IOException ex) {
16.          thrownew IllegalArgumentException(……);
17.      }
18. }
        获取所有@Configuration配置类的名字以后,进行去重、排序、筛选等操作。然后调用processImports方法,处理通过EnableAutoConfigurationImportSelector类导入的@Configuration配置类:
1.  private voidprocessImports(ConfigurationClass configClass, SourceClass currentSourceClass,
2.           Collection<SourceClass>importCandidates, boolean checkForCircularImports) throws IOException {
3.   
4.         ……
5.       if(checkForCircularImports && isChainedImportOnStack(configClass)) {
6.           ……
7.       }
8.       else{
9.           this.importStack.push(configClass);
10.          try{
11.              for (SourceClass candidate : importCandidates){
12.                  if(candidate.isAssignable(ImportSelector.class)) {
13.                      //Candidate class is an ImportSelector -> delegate to it to determine imports
14.                      Class<?>candidateClass = candidate.loadClass();
15.                      ImportSelectorselector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
16.                      ParserStrategyUtils.invokeAwareMethods(
17.                              selector,this.environment, this.resourceLoader, this.registry);
18.                      if(this.deferredImportSelectors != null && selector instanceofDeferredImportSelector) {
19.                          this.deferredImportSelectors.add(
20.                                  newDeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
21.                      }
22.                      else{
23.                          String[]importClassNames = selector.selectImports(currentSourceClass.getMetadata());
24.                          Collection<SourceClass>importSourceClasses = asSourceClasses(importClassNames);
25.                          processImports(configClass,currentSourceClass, importSourceClasses, false);
26.                      }
27.                  }
28.                  elseif (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
29.                      //Candidate class is an ImportBeanDefinitionRegistrar ->
30.                      //delegate to it to register additional bean definitions
31.                      Class<?>candidateClass = candidate.loadClass();
32.                      ImportBeanDefinitionRegistrarregistrar =
33.                              BeanUtils.instantiateClass(candidateClass,ImportBeanDefinitionRegistrar.class);
34.                      ParserStrategyUtils.invokeAwareMethods(
35.                              registrar,this.environment, this.resourceLoader, this.registry);
36.                      configClass.addImportBeanDefinitionRegistrar(registrar,currentSourceClass.getMetadata());
37.                  }
38.                  else{
39.                      //Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
40.                      //process it as an @Configuration class
41.                      this.importStack.registerImport(
42.                              currentSourceClass.getMetadata(),candidate.getMetadata().getClassName());
43.                      processConfigurationClass(candidate.asConfigClass(configClass));
44.                  }
45.              }
46.          }
47.          catch(BeanDefinitionStoreException ex) {
48.              throwex;
49.          }
50.          catch(Throwable ex) {
51.              ……
52.          }
53.          finally{
54.              this.importStack.pop();
55.          }
56.      }
57. }

        processImports方法主要逻辑:

        1)   如果导入的配置类实现了DeferredImportSelector接口,则创建DeferredImportSelectorHolder实例,并置入deferredImportSelectors链表中,待上述processConfigBeanDefinitions方法下一个do{*}while(*)循环中处理。

        2)   如果导入的配置类实现了ImportSelector接口,则调用该类的selectImports方法导入新的@Configuration配置类,并嵌套调用processImports方法,处理导入的@Configuration配置类。

        3)   如果导入的配置类实现了ImportBeanDefinitionRegistrar接口,则创建ImportBeanDefinitionRegistrar实例,并在处理@Configuration配置类过程中,委托该实例注册额外的BeanDefinition。

        4)   如果以上都不是,则导入的配置类为基本的@Configuration配置类,直接调用processConfigurationClass处理,最终具体解析操作在doProcessConfigurationClass方法中实现。

1.  protected final SourceClassdoProcessConfigurationClass(ConfigurationClass configClass, SourceClasssourceClass) throws IOException {
2.       //Recursively process any member (nested) classes first
3.       processMemberClasses(configClass,sourceClass);
4.   
5.       //处理@PropertySource注解
6.       for(AnnotationAttributes propertySource :AnnotationConfigUtils.attributesForRepeatable(
7.               sourceClass.getMetadata(),PropertySources.class, org.springframework.context.annotation.PropertySource.class)){
8.           if(this.environment instanceof ConfigurableEnvironment) {
9.               processPropertySource(propertySource);
10.          }
11.          else{
12.              logger.warn("Ignoring@PropertySource annotation on [" + sourceClass.getMetadata().getClassName()+
13.                      "].Reason: Environment must implement ConfigurableEnvironment");
14.          }
15.      }
16.  
17.      // 处理@ComponentScan注解
18.      Set<AnnotationAttributes>componentScans = AnnotationConfigUtils.attributesForRepeatable(
19.              sourceClass.getMetadata(),ComponentScans.class, ComponentScan.class);
20.      if(!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN)) {
21.          for(AnnotationAttributes componentScan : componentScans) {
22.              //The config class is annotated with @ComponentScan -> perform the scanimmediately
23.              Set<BeanDefinitionHolder>scannedBeanDefinitions =
24.                      this.componentScanParser.parse(componentScan,sourceClass.getMetadata().getClassName());
25.              //Check the set of scanned definitions for any further config classes and parserecursively if necessary
26.              for(BeanDefinitionHolder holder : scannedBeanDefinitions) {
27.                  if(ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(),this.metadataReaderFactory)) {
28.                      parse(holder.getBeanDefinition().getBeanClassName(),holder.getBeanName());
29.                  }
30.              }
31.          }
32.      }
33.  
34.      //处理@Import注解
35.      processImports(configClass, sourceClass,getImports(sourceClass), true);
36.  
37.      //处理@ImportResource注解
38.      if(sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
39.          AnnotationAttributesimportResource =
40.                  AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),ImportResource.class);
41.          String[]resources = importResource.getStringArray("locations");
42.          Class<?extends BeanDefinitionReader> readerClass =importResource.getClass("reader");
43.          for(String resource : resources) {
44.              StringresolvedResource = this.environment.resolveRequiredPlaceholders(resource);
45.              configClass.addImportedResource(resolvedResource,readerClass);
46.          }
47.      }
48.  
49.      //处理@Bean方法
50.      Set<MethodMetadata>beanMethods =sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
51.      for(MethodMetadata methodMetadata : beanMethods) {
52.          configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));
53.      }
54.  
55.      ……
56.  
57.      //No superclass -> processing is complete
58.      returnnull;
59. }

        针对每个@Configuration配置类,依次处理@Configuration配置类中的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean注解,主要解析过程如下:

        1)   @PropertySource处理过程:调用processPropertySource方法处理属性源,在此不详述;

        2)   @ComponentScan处理过程:解析@Configuration配置类中@ComponentScan、@ComponentScans注解,并根据设置的basePackages扫描指定的包路径,并加载、注册所有带有@Component注解及@Component衍生注解(如@Controller、@Service、@Repository、@Configuration等)Java类的Bean定义到Spring应用上下文;

        3)   @Import处理过程:参考上述processImports方法描述。需要注意,在处理某个配置类的@Import注解过程中,如果发现@Import导入的类实现了DeferredImportSelector接口,则创建DeferredImportSelectorHolder实例,并置入deferredImportSelectors链表中,待下一次循环处理。以此类推,直至所有的@Configuration配置类加载完毕。例如:在处理SofaBootRpcDemoApplication的@Import注解时,由于在SofaBootRpcDemoApplication类@SpringBootApplication注解中引用了@EnableAutoConfiguration注解,而它又引用了@Import(value={EnableAutoConfigurationImportSelector.class})。由于EnableAutoConfigurationImportSelector实现了DeferredImportSelector接口,所以在此创建DeferredImportSelectorHolder实例,并置入deferredImportSelectors链表中,待所有@Configuration注解类解析完成以后再处理。

        4)   @ImportResource处理过程:解析locations属性,并依次获取locations指定目录下Spring XML配置文件,设置configClass类的importedResource属性;

        5)   @Bean处理过程:读取@Configuration配置类中@Bean注解的方法,并增加到configClass的beanMethod集合。

        至此,处理完现有candidates中所有@Configuration配置类。

        在回看一下processConfigBeanDefinitions方法:
1.  public voidprocessConfigBeanDefinitions(BeanDefinitionRegistry registry) {
2.       List<BeanDefinitionHolder>configCandidates = new ArrayList<BeanDefinitionHolder>();
3.       String[]candidateNames = registry.getBeanDefinitionNames();
4.   
5.       for(String beanName : candidateNames) {
6.           BeanDefinitionbeanDef = registry.getBeanDefinition(beanName);
7.           if(ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
8.                   ConfigurationClassUtils.isLiteConfigurationClass(beanDef)){
9.               ……
10.          }
11.          elseif (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)) {
12.              configCandidates.add(newBeanDefinitionHolder(beanDef, beanName));
13.          }
14.      }
15.       ……
16.       ConfigurationClassParser parser = newConfigurationClassParser(
17.              this.metadataReaderFactory,this.problemReporter, this.environment,
18.              this.resourceLoader,this.componentScanBeanNameGenerator, registry);
19.       ……
20.      do {
21.          parser.parse(candidates);
22.          parser.validate();
23.  
24.          ……
25.            // Read the model and create beandefinitions based on its content
26.          if(this.reader == null) {
27.              this.reader= new ConfigurationClassBeanDefinitionReader(
28.                      registry,this.sourceExtractor, this.resourceLoader, this.environment,
29.                      this.importBeanNameGenerator,parser.getImportRegistry());
30.          }
31.          this.reader.loadBeanDefinitions(configClasses);
32.  
33.          alreadyParsed.addAll(configClasses);
34.          candidates.clear();
35.          ……
36.            for (ConfigurationClassconfigurationClass : alreadyParsed) {
37.                  alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
38.              }
39.              for(String candidateName : newCandidateNames) {
40.                  if(!oldCandidateNames.contains(candidateName)) {
41.                      BeanDefinitionbeanDef = registry.getBeanDefinition(candidateName);
42.                      if(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory) &&
43.                              !alreadyParsedClasses.contains(beanDef.getBeanClassName())){
44.                          candidates.add(newBeanDefinitionHolder(beanDef, candidateName));
45.                      }
46.                  }
47.              }       
48.      }
49.      while (!candidates.isEmpty());
50.  
51.      ……
52. }

        处理完现有candidates中所有@Configuration配置类以后,调用ConfigurationClassBeanDefinitionReader的loadBeanDefinitions方法加载、注册@Configuration配置类本身及其中的@Bean注解对应的类。

1.  public voidloadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
2.       TrackedConditionEvaluatortrackedConditionEvaluator = new TrackedConditionEvaluator();
3.       for(ConfigurationClass configClass : configurationModel) {
4.           loadBeanDefinitionsForConfigurationClass(configClass,trackedConditionEvaluator);
5.       }
6.  }
        @Configuration配置类的具体加载方法如下:
1.  private void loadBeanDefinitionsForConfigurationClass(ConfigurationClassconfigClass,
2.           TrackedConditionEvaluatortrackedConditionEvaluator) {
3.   
4.       ……
5.   
6.       if(configClass.isImported()) {
7.           registerBeanDefinitionForImportedConfigurationClass(configClass);
8.       }
9.       for(BeanMethod beanMethod : configClass.getBeanMethods()) {
10.          loadBeanDefinitionsForBeanMethod(beanMethod);
11.      }
12.      loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
13.      loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
14. }

        @Configuration配置类主要加载过程如下:

        1)   把@Configuration配置类自身注册到Spring应用上下文;

        2)   加载@Bean注解对应的BeanDefinition;

        3)   加载@ImportResource注解指定的XML文件或Groovy文件中配置的BeanDefinition;

        4)   从ImportBeanDefinitionRegistrar加载BeanDefinition,如AutoConfigurationPackages;

        在此就不详述注册过程,感兴趣的同学可以自己看看。

        接下来先清空candidates集合,然后从Spring应用上下文中获取所有已经注册的BeanDefinitionNames,然后与已经解析的@Configuration配置类对比,查找未处理的@Configuration配置类,并置入candidates集合,待下一次循环处理。此处循环处理下去,直至所有的@Configuration配置类处理完毕。

        至此,ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法执行完毕,加载完所有配置的BeanDefinition。

        不在详述AbstractApplicationContext的refresh方法中其它步骤,感兴趣的同学可以自己看看。

        (七)    Spring应用上下文刷新以后的处理:

        依次调用ApplicationRunner接口和CommandLineRunner接口的实现,完成刷新Spring上下文以后的一些处理操作。

        (八)    终止监听

        依次调用通过SpringFactoriesLoader从spring.factories文件中加载的SpringApplicationRunListener接口的实现的finished方法,结束监听器。

        (九)    结束run方法

        调用StopWatch实例的stop方法,结束记录任务的运行时间。

        到此为止,SOFABoot应用启动完成。

三、总结

        通过以上源码分析,可以总结出以下几个部分,作为基于SOFABoot框架进行开发时的基础和扩展的方向。

          (一) EnableAutoConfiguration

        基于SOFABoot框架开发的模块,通过在META-INF/spring.factories文件中配置EnableAutoConfiguration实现SOFABoot模块自动配置功能。

        在SOFABoot应用启动时,自动加载SOFABoot模块META-INF/spring.factories文件中配置的@Configuration配置类,以此作为模块加载的入口,把模块中相关的Bean加载到Spring应用上下文。

        参考配置格式为:

1.  # Auto Configure
2.  org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
3.  org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
4.  org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
5.  org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
6.  org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
7.  org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
8.  org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
9.  org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
10. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
11. org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

        这些支持自动配置的Bean在ApplicationContext刷新过程中被注册到Spring应用上下文,具体加载过程参考源码解析部分。

           (二)  ApplicationContextInitializer

        如果希望对Spring应用上下文进行一些个性化的初始化操作,则实现ApplicationContextInitializer接口,在initialize方法中完成个性化的初始化操作。

        在META-INF/spring.factories文件配置ApplicationContextInitializer接口的实现,格式为:

1.  org.springframework.context.ApplicationContextInitializer=\
2.  xxx.yyyy.zzz.XxxInitializer,\
3.  xxx.yyyy.zzz.YyyInitializer

        这些ApplicationContextInitializer接口的实现类在Spring应用上下文准备阶段被调用执行,即SpringApplication的prepareContext方法中。

         (三) ApplicationListener

        如果希望监听Spring应用的事件,当事件发生时,针对事件进行一些个性化操作,则实现ApplicationListener接口,在onApplicationEvent方法中处理发生的Application事件。

        在META-INF/spring.factories文件配置ApplicationListener接口的实现,格式为:

1.  org.springframework.context.ApplicationListener=\
2.  xxx.yyyy.zzz.XxxListener

        当ApplicationEvent事件发生时,这些ApplicationListener接口的实现被调用。

          (四) SpringApplicationRunListener

        如果希望监听SpringBoot的org.springframework.boot.SpringApplication类的run方法,当SpringApplication启动时,进行一些个性化操作,则实现SpringApplicationRunListener接口,针对具体情况实现相应的方法。

1.  public interfaceSpringApplicationRunListener {
2.   
3.  /**
4.   * SpringApplicationrun方法第一次启动时立即调用。
5.   */
6.  void started();
7.   
8.  /**
9.   * Environment准备好时调用,但在ApplicationContext被创建以前。
10.  */
11. void environmentPrepared(ConfigurableEnvironmentenvironment);
12.  
13. /**
14.  * Spring应用上下文被创建并准备好时调用,但在sources被加载之前。
15.  */
16. voidcontextPrepared(ConfigurableApplicationContext context);
17.  
18. /**
19.  * Spring应用上下文被加载但还没有刷新时调用。
20.  */
21. voidcontextLoaded(ConfigurableApplicationContext context);
22.  
23. /**
24.  * SpringApplicationrun方法完成时调用。
25.  */
26. void finished(ConfigurableApplicationContextcontext, Throwable exception);
27.  
28. }

          在SpringApplication的run方法中,通过SpringFactoriesLoader类loadFactoryNames方法,查找并加载所有spring.factories文件中定义的SpringApplicationRunListener接口的实现。

        SpringApplicationRunListener接口中各个方法的调用顺序为:

        1.   在SpringApplication的run方法中,调用started方法;

        2.   在SpringApplication的prepareEnvironment方法中,调用environmentPrepared方法;

        3.   在SpringApplication的prepareContext方法中,先调用contextPrepared方法,然后是Spring上下文资源加载,最后调用contextLoaded方法;

        4.   在SpringApplication的run方法中,调用finished方法。

猜你喜欢

转载自blog.csdn.net/beyondself_77/article/details/80831540