天天看點

Spring系列(三) 從refresh看createBean源碼解析

createBean解析

spring當中單例bean的建立原理,其中涉及到了非常多階段及各種處理器的調用

啟動代碼

通過注解配置類AppConfig啟動一個容器,其中添加了一個自定義的beanFactoryPostProcessor, 注意:這個類是直接添加到beanFactoryPostProcessors中的,沒有被spring當成bean放到單例map中

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        ac.addBeanFactoryPostProcessor(new CustomBeanFactoryPostProcessor());
        ac.register(AppConfig.class);
        ac.refresh();
           

new AnnotationConfigApplicationContext

完成的初始化:

this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
           

初始化了AnnotatedBeanDefinitionReader又完成了spring内置幾大處理器的注冊

生成了對應RootBeanDefinition,并通過registry加到了map中

beanName beanClass
org.springframework.context.annotation.internalConfigurationAnnotationProcessor ConfigurationClassPostProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor AutowiredAnnotationBeanPostProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor CommonAnnotationBeanPostProcessor
org.springframework.context.event.internalEventListenerProcessor EventListenerMethodProcessor
org.springframework.context.event.internalEventListenerFactory DefaultEventListenerFactory

register 注冊了自己的配置類

通過構造ApplicationContext時産生的reader解讀這個注解類,并把配置類當成一個AnnotatedGenericBeanDefinition放入map中等待後續執行個體化。中間處理了一些common的注解資訊并填沖到bd裡,比如@Lazy,@Primary,@Role,@DependsOn, @Description等

refresh 方法解析

refresh方法中是個模闆方法,裡面定義了很多階段操作,其中主要分析以下幾個

invokeBeanFactoryPostProcessors(beanFactory)

主要完成了下面一個操作,其中getBeanFactoryPostProcessors()拿的就是我們手動add進去的那個processor清單,是以目前隻有一個

第一步:優先周遊這個list,并加入到對應清單中

BeanDefinitionRegistryPostProcessor -> List<BeanDefinitionRegistryPostProcessor> registryProcessors
BeanFactoryPostProcessor -> List<BeanFactoryPostProcessor> regularPostProcessors
           

注意 這裡對BeanDefinitionRegistryPostProcessor 會先觸發 postProcessBeanDefinitionRegistry 因為可能在這個方法裡面需要引入額外的banFactoryPostProcessor類,等待下一步執行

接下來開始按優先級順序查找并執行beanFactory中目前的registryPostProcessor

此刻bd map中已經有了如下幾個内置類:5個内置+1個自己注解類

Spring系列(三) 從refresh看createBean源碼解析

第二步:從beanFactory中拿出所有PriorityOrdered BeanDefinitionRegistryPostProcessor的beanName

此時滿足條件的隻有

ConfigurationClassPostProcessor

, beanFactory.getBean會将它産生出來并放到緩存中

Spring系列(三) 從refresh看createBean源碼解析

并執行 處理器對registry的實作邏輯,這裡的配置處理器會将目前所有的bd拿出來判斷解析,構造所有需要産生的bd并存放起來 (執行了 )

for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
step -> ConfigurationClassPostProcessor
      processConfigBeanDefinitions
           

判斷beanDefinition中屬性org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass是否有值(不成立,目前還沒被設定過值)

然後checkConfigurationClassCandidate(看是不是候選的配置類)

  • 如果是配置類,産生的bd是AnnotatedGenericBean,會滿足第一個條件設定好metaData
  • 如果這個bean是自己注冊的,有可能是AbstractBeanDefinition類型,那麼再看是不是BeanFactoryPostProcessor,BeanPostProcessor,AopInfrastructureBean,EventListenerFactory等特殊類型,不是的化也設定metadata否則直接結束

拿出Configuration注解的屬性資訊,允許代理bean方法情況下,設定注解屬性為full(就是這個時候才添加了标記,對應前面第一次拿是空);如果沒有@Configuration,拿出來的config是null,但是目前有@Bean method,else if中标記為lite

Spring系列(三) 從refresh看createBean源碼解析

然後用ConfigurationClassParser 去解析配置類的相關資訊,包括Component, PropertySources,ComponentScans,ComponentScan, @Import, ImportResource,

等,最終存在ConfigurationClass包裝類中

private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
	private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
	private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
			new LinkedHashMap<>();
	private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
			new LinkedHashMap<>();
	final Set<String> skippedBeanMethods = new HashSet<>();
           

接着ConfigurationClassBeanDefinitionReader 去加載這些資訊loadBeanDefinitions到bd map中

再通過registry直接往容器中的singletonObjects中注冊一個處理Import注解的處理類 ,沒有走beanDefinition->create邏輯

beanName beanClass
org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry org.springframework.context.annotation.ConfigurationClassParser.ImportStack

完成所有import和其他相關注解資訊的處理後,相關需要被掃面加載的bd都已經被存放到beanFactory中的bd map中等待被建立了

第三步 再從容器中找出所有beanFactoryPostProcessor (還是隻有一個被執行過的configuration處理類)

如果未被執行過或不是Order優先級的,跳過

第四步 從容器中找出所有beanFactoryPostProcessor,不對接口限制

處理所有未處理的process方法,并繼續循環擷取防止目前又産生新的處理器

第五步 對所有後置處理器(包括特殊的registry和普通beanFactoryPostprocessor)調用接口方法

postProcessBeanFactory

invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
           

ConfigurationClassPostProcessor postProcessBeanFactory

會對目前所有bd找出可能的注解類,隻對full屬性的類進行如下邏輯

  • CGLIB 增強@Configuration的類 , enhanceConfigurationClasses

    對标記為full的進行ConfigurationClassEnhancer enhance (保證@Bean method都為單例的,如果在方法調用中有多次)

  • 添加 ImportAwareBeanPostProcessor到beanFactory中的list

第六步 最後從容器中找出所有beanFactoryPostProcessor,防止再postProcessBeanFactory時有

新産生并且未處理過

的處理器

如果有的化依然按照優先級順序加入執行,執行結果隻有一個

Spring系列(三) 從refresh看createBean源碼解析
registerBeanPostProcessors

與執行beanFactoryPostProcessor方法類似,已然按照優先級順序從目前容器中找出來所有name執行,沒有自定義的化預設隻有這兩個内置的,且都是PriorityOrder的

List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>();

Spring系列(三) 從refresh看createBean源碼解析

把上述處理器找出來并加入到beanFactory中(實際上隻是加到了list中,後續可以直接從目前list中擷取,不用從容器裡拿)----

registerBeanPostProcessors

接着又直接加了一個ApplicationListenerDetector到集合中,未存在singletonObjects中(該類修飾符是預設的,不可在包外通路執行個體化)

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
           
finishBeanFactoryInitialization

這是真正建立非懶加載單例bean的方法,調用beanFactory.preInstantiateSingletons()

非FactoryBean的情況下,直接去getBean

先允許提前從提早緩存對象中拿,提早暴露的objects或objectFactories,對于自定義的單例第一次拿不到

Spring系列(三) 從refresh看createBean源碼解析

接着經過一系列判斷後,開始建立

if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
				
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
           

getSingleton中會再次嘗試從緩存單例池中拿,将目前bean标記為正在建立中,然後調用對象工廠方法createBean構造bean,将它加入到單例對象池中,并将提早引用池和工廠池中移除目前bean

Spring系列(三) 從refresh看createBean源碼解析

在工廠方法中,先嘗試是否可以有處理器提早生成一個對象(預設還是null),調用

applyBeanPostProcessorsBeforeInstantiation ->有值 再applyBeanPostProcessorsAfterInitialization

執行目前所有(beanFactory中的處理器集合)後置處理器的postProcessBeforeInstantiation

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
           

doCreateBean 去執行真正建立bean的過程

createBeanInstance -> 執行個體化bean對應的class

applyMergedBeanDefinitionPostProcessors

->

  • 兩個内置後置處理器CommonAnnotationBeanPostProcessor -> 處理PostConstruct,Predestroy, Resource等注解資訊的封裝
  • AutowiredAnnotationBeanPostProcessor->

    處理Autowired,Value等注解對應的file,method封裝起來

判斷是否需要提前暴露該對象引用(用于

解決循環依賴

),加到singletonFactories

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
           

populateBean ->填充bean的屬性

  • InstantiationAwareBeanPostProcessor postProcessAfterInstantiationr處理器的調用
  • 判斷注入模式resolvedAutowireMode ,AutowireCapableBeanFactory中的幾種
  • InstantiationAwareBeanPostProcessor postProcessProperties 用于處理上一步封裝好的InjectedElement的資訊。包括common的ResourceElement, autowired的AutowiredFieldElement,AutowiredMethodElement等,如果沒有要設定進來的對象,會從bean工廠中找,開始進行依賴對象bean的生命周期的建立

initializeBean ->調用初始化方法及生命周期回調

InitDestroyAnnotationBeanPostProcessor 是CommonAnnotationBeanPostProcessor的父接口

Spring系列(三) 從refresh看createBean源碼解析
  • invokeAwareMethods -> BeanNameAware、BeanClassLoaderAware,BeanFactoryAware隻有這三個接口,那麼其他的aware接口是在哪裡調用的呢?ApplicationContextAwareProcessor
  • applyBeanPostProcessorsBeforeInitialization

    ->

    注意 這裡會調用InitDestroyAnnotationBeanPostProcessor 解析的PostConstruct方法

    ,以及ApplicationContextAwareProcessor 執行所有invoke Aware接口方法
    Spring系列(三) 從refresh看createBean源碼解析
  • invokeInitMethods -> 實作了InitializingBean的方法,調用afterPropertiesSet;同時看bd中是否有自定義不重名的init method也調用
  • applyBeanPostProcessorsAfterInitialization

    -> AbstractAutoProxyCreator 會在這裡進行aop動态代理包裝

至此,bean的建立就已經結束了!