以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方法启动监听器;
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实例的主要步骤完成。
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应用上下文刷新过程,大家应该都比较熟悉了,在此不详述了。
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. }
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. }
1. protected List<String>getCandidateConfigurations(AnnotationMetadata metadata,
2. AnnotationAttributesattributes) {
3. List<String> configurations =SpringFactoriesLoader.loadFactoryNames(
4. getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
5. ……略
6. return configurations;
7. }
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. }
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. }
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. * 当SpringApplication的run方法第一次启动时立即调用。
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. * 当SpringApplication的run方法完成时调用。
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方法。