本文涉及主題
1. BeanFactoryPostProcessor呼叫過程原始碼剖析
2. 配置類的解析過程原始碼
3. 配置類@Configuration加與不加的區別
4. 重複beanName的覆蓋規則
5. @ComponentScan的解析原理
一. 研究目標: 解析spring如何載入配置類
我們經常會在一個類上打上@Configuration, @Component, @Bean等. 帶有這些註解的類, 就是我們所說的配置類. 那麼, spring啟動的時候,是如何載入這些配置類的呢?
下面就以此為目的, 分析spring原始碼. 本節的內容是對上一節內容的實戰分析, 同時更加詳細的解讀spring原始碼
我們知道, spring啟動的時候做了3件事, 就是上面的三件事.
第一件事: 呼叫this()自身的無參建構函式. 初始化了BeanDefinitionReader和BeanDefinitionScanner, 同時初始化了很多spring的原始後置處理器, 這些處理器是用來載入bean的
第二件事: 呼叫register(..) 註冊配置類
第三件事: refresh(..) 這裡包含了整個ioc建立bean的全生命週期, 今天重點看invokeBeanFactoryPostProcessors(beanFactory)載入配置類
二. 準備工作: 自定義配置類MainConfig
我們先定義好要分析載入的配置類
package com.lxl.www.iocbeanlifecicle; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * 這是一個配置類, * 在配置類裡面定義了掃描的包路徑com.lxl.www.iocbeanlifecicle * 這是會將這個包下配置了註解的類掃描到ioc容器裡面,成為一個成熟的bean */ @Configuration @ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"}) public class MainConfig { }
這個配置類很簡單, 使用@ComponentScan註解指定了掃描的包. @Configuration指定當前是一個配置類
接下來定義一個main方法, 載入配置類.
package com.lxl.www.iocbeanlifecicle; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainStarter { public static void main(String[] args) { // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); //context.addBeanFactoryPostProcessor(); Car car = (Car) context.getBean("car"); System.out.println(car.getName()); context.close(); } }
在main裡, 通過AnnotationConfigurationApplicationContext讀取配置類MainConfig.class.
配置類被傳進來以後, 到底是怎麼被解析的呢? 這就是我們分析的線索
始終不要忘記我們的整體架構圖. 對照這個圖來分析. 思路更清晰. 整體內容講解在這裡: https://www.cnblogs.com/ITPower/p/13677635.html
下面, 從入口進入. 我們的入口就是這裡
new AnnotationConfigApplicationContext(MainConfig.class);
下面進入AnnotationConfigApplicationContext的構造方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) { // 進入建構函式, 首先呼叫自身的構造方法this(); // 呼叫自身的構造方法之前, 要先呼叫父類的構造方法 this(); // register配置註冊類 register(componentClasses); // ioc容器shua新介面--非常重要 refresh(); }
三、讀取配置類後置處理器ConfigurationClassPostProcessor
3.1 呼叫this()無參建構函式
public AnnotationConfigApplicationContext() { /** * 建立了一個Bean定義的讀取器. * 完成了spring內部BeanDefinition的註冊(主要是後置處理器) * 讀取了很多spring自定義的配置(主要是後置處理器). 這些類都是spring 的原始類(也就是創世紀的類). */ this.reader = new AnnotatedBeanDefinitionReader(this); /** * 建立BeanDefinition掃描器 * 可以用來掃描包或者類, 進而轉換為bd * * Spring預設的掃描包不是這個scanner物件 * 而是自己new的一個ClassPathBeanDefinitionScanner * Spring在執行工程後置處理器ConfigurationClassPostProcessor時, 去掃描包時會new一個ClassPathBeanDefinitionScanner * * 這裡的scanner僅僅是為了程式設計師可以手動呼叫AnnotationConfigApplicationContext物件的scan方法 * 通過呼叫context.scan("package name");掃描處理配置類 * 掃描 */ this.scanner = new ClassPathBeanDefinitionScanner(this); }
在初始化AnnotatedBeanDefinitionReader(this);的時候, 註冊了很多後置處理器
/** * 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) { // 獲取到beanFactory DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); /** * 判斷beanFactory中是否有AnnotationAwareOrderComparator和ContextAnnotationAutowireCandidateResolver * 沒有則新增 */ if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } // BeanDefinitionHolder: 為BeanDefinition設定名字和別名 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 如果registry中沒有ConfigurationClassPostProcessor配置類後置處理器, 就新增一個 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並新增到beanDefs beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 如果rigistry中, 沒有AutowiredAnnotationBeanPostProcessor Autowired註解bean的後置處理器, 則新增一個 if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並新增到beanDefs beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. // 檢查對JSR-250的支援, 如果rigistry中沒有 CommonAnnotationBeanPostProcessor 通用註解後置處理器, 則新增一個 if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並新增到beanDefs beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. // 檢查對jpa的支援, 如果不包含 internalPersistenceAnnotationProcessor, 持久化註解處理器, 就新增一個 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)); } // 檢查對事件監聽的支援, 如果不包含事件監聽處理器 internalEventListenerProcessor, 就新增一個 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)); } // 如果不包含事件監聽工廠處理器 internalEventListenerFactory , 就新增一個 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; }
我們看到, 註冊了6個原始RootBeanDefinition, 這些bean是spring自己提前定義好的, 他們的載入是整個spring的基礎. 用於解析spring中其他的類
而這一次我們要研究配置類是如何被讀取的, 所以重點關注的是下面這個後置處理器
ConfigurationClassPostProcessor.class
這裡還有很多其他的原始類被註冊了, 但我們的目標是分析配置類是如何被讀取的, 所以, 其他的先忽略, 只看ConfigurationClassPostProcessor.
3.2 ConfigurationClassPostProcessor的繼承結構
可以看到ConfigurationClassPostProcessor是同時實現了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor. 這一點我們需要記住, 後面會使用到
2.3 ConfigurationClassPostProcessor是如何被註冊的
// 如果registry中沒有ConfigurationClassPostProcessor配置類後置處理器, 就新增一個 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); // 構建BeanDefinitionHolder, 並新增到beanDefs beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }
首先,構建了一個RootBeanDefinition. 然後呼叫了registerPostProcessor方法, 三個入參分別是
registry: BeanDefinitionRegistry註冊器, 用於註冊BeanDefinition
def: 剛剛構建的RootBeanDefinition
CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME: 構建BeanDefinition使用的beanName是org.springframework.context.annotation.internalConfigurationAnnotationProcessor
然後呼叫registerPostProcessor方法
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // 從BeanDefinition的一級快取BeanDefinitionMap中讀取BeanDefinition物件, 判斷是否已經存在 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); // 這裡,如果已經存在,說明被重複載入了, 那麼後面載入的會覆蓋前面載入的bean if (existingDefinition != null) { // 判斷是否允許BeanDefinition重寫 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } // 覆蓋一級快取的bean定義 this.beanDefinitionMap.put(beanName, beanDefinition); } else { // 處理迴圈引用的問題 if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } }
這裡面的關鍵程式碼是標紅的部分, 將ConfigurationClassPostProcessor放入到了beanDefinitionMap裡面
下面的else是處理迴圈引用的問題, 暫時先不要看.
3.3 對照整體框架, 我們知道ConfigurationClassPostProcessor被解析成beanDefinition放入到BeanDefinitionMap中了
3.4 初始化ClassPathBeanDefinitionScanner
在this()構造方法裡, 還初始化了ClassPathBeanDefinitionScanner, 這裡只說一句.
this.scanner = new ClassPathBeanDefinitionScanner(this);
我們在掃描配置類的時候, 確實使用的是ClassPathBeanDefinitionScanner, 但是, 不是this.scanner物件. 而是自己new的一個ClassPathBeanDefinitionScanner.
這裡的scanner僅僅是為了程式設計師可以手動呼叫AnnotationConfigApplicationContext物件的scan方法
通過呼叫context.scan("package name");掃描處理配置類
使用方式如下:
public static void main(String[] args) { // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); context.scan("package"); Car car = (Car) context.getBean("car"); System.out.println(car.getName()); context.close(); }
到目前為止完成了後置處理器註冊為BeanDefinition
備註:
ConfigurationClassPostProcessor是一個工具類, 這個類的作用是解析配置類.
工具類有了, 那麼還得有主角呀, 那就是我們上面的配置類. 下面看看配置類的載入
四. 讀取自定義配置類MainConfig
註冊配置類,入口自然是這裡了
public AnnotationConfigApplicationContext(Class<?>... componentClasses) { // 進入建構函式, 首先呼叫自身的構造方法this(); // 呼叫自身的構造方法之前, 要先呼叫父類的構造方法 this(); // register配置註冊類 register(componentClasses); // ioc容器shua新介面--非常重要 refresh(); }
跟蹤進去找到doRegisterBean(...)方法
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { // 將入參的配置類beanClass構建成AnnotatedGenericBeanDefinition物件 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(supplier); // 讀取配置類的後設資料 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // 處理主類通用定義註解 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) { for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } // 將MainConfig.java配置類進行解析.放到BeanDefinitionHolder BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
重點就是紅色這句話, 其他可以略過, 因為我們的配置類很簡單, 直接看BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
我們找到 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());方法, 進入到DefaultListableBeanFactory檢視方法, 這個方法之前我們已經呼叫過一次
就是在註冊ConfigurationClassPostProcessor的時候, 我們需要將其解析為BeanDefinition然後放到BeanDefinitionMap中, 這裡也是一樣的, 將我們的配置類MainConfig解析成BeanDefinition放入到BeanDefinitionMap中.
這裡的程式碼在整個框架中處於什麼位置呢? 將MainConfig解析為BeanDefinition放入到BeanDefinitionMap中
以上兩步, 一個是將ConfigurationClassPostProcessor配置類後置處理器, 也就是解析配置的工具類, 解析成BeanDefinition放入到BeanDefinitionMap中
另一個是將我們的目標配置類MainConfig載入到記憶體, 組裝成BeanDefinition放入到BeanDefinitionMap中.
到這裡,我們完成了兩步.
第一步: 準備工具類ConfigurationClassPostProcessor
第二步: 準備配置類MainConfig.
接下倆, 就是要使用工具類來解析配置類MainConfig了
五. 呼叫bean工廠的後置處理器invokeBeanFactoryPostProcessors(beanFactory);
public AnnotationConfigApplicationContext(Class<?>... componentClasses) { // 進入建構函式, 首先呼叫自身的構造方法this(); // 呼叫自身的構造方法之前, 要先呼叫父類的構造方法 this(); // register配置註冊類 register(componentClasses); // ioc容器重新整理介面--非常重要 refresh(); }
在refresh()中有很多步驟, 我們重點來看invokeBeanFactoryPostProcessors(beanFactory);
/** * refresh是spring最核心的方法, 裡面包含了整個spring ioc的全過程, 包括spring載入bean到銷燬bean的全過程 * 學習spring, 就是學習裡面的13個方法, 如果13個方法都學完了, 基本上就打通了 * @throws BeansException * @throws IllegalStateException */ @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. 準備重新整理上下文環境 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //2. 獲取告訴子類初始化bean工廠, 不同工廠不同實現 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //3. 對bean工廠進行填充屬性 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 4. 留個子類去實現該介面 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. /* * * 呼叫bean工廠的後置處理器 * 我們之前在Reader的時候讀取了很多創世紀的PostProcessor後置處理器. * 這裡要呼叫bean工廠的後置處理器. 這麼多創世紀的PostProcessor, 只有一個PostProcessor實現了 * BeanFactoryPostProcessor. 那個類就是 ConfigurationClassPostProcessor * 前面已經將ConfigurationClassPostProcessor放入到BeanDefinitionMap中了, * 對應的BeanDefinitionName 是 internalConfigurationAnnotationProcessor * * * */ invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 註冊bean後置處理器 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 初始化國際化資源處理器 initMessageSource(); // Initialize event multicaster for this context. // 建立事件多播放器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 這個方法通用也是留個子類實現的, spring boot也是從這個方法進行啟動 onRefresh(); // Check for listener beans and register them. // 將事件監聽器註冊到多播放器上 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 例項化剩餘的單例項bean /** * 這個方法就是迴圈遍歷BeanDefinitionMap, 呼叫getBean, 去生產bean */ finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //最後容器重新整理 釋出重新整理時間(spring cloud是從這裡啟動的 ) finishRefresh(); } ........ }
invokeBeanFactoryPostProcessors(beanFactory);看名字, 呼叫的是Bean工廠的後置處理器, 上面分析了, 初始化的時候初始化了很多spring原生的後置處理器, 這麼多後置處理器, 其實, 只有一個後置處理器實現了BeanFactoryPostProcessor, 它就是ConfigurationClassPostProcessor, 還記得上面的結構圖麼, 拿下來, 再看一遍.
這裡呼叫的時候, 原生處理器只會呼叫ConfigurationClassPostProcessor
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { /** * 獲取兩處儲存BeanFactoryPostProcessor的物件, 傳入供接下來呼叫 * 1. 當前bean工廠 * 2. 和我們自己呼叫addBeanFacoryPostProcessor自定義BeanFactoryPostProcessor * * 引數: getBeanFactoryPostProcessors() 傳了一個工廠的後置處理器的List, 這個時候list是空的 * getBeanFactoryPostProcessors()裡面的值是怎麼來的呢? * 通過在自定義main方法中呼叫context.addBeanFactoryPostProcessor(...);來新增 * * public static void main(String[] args) { * // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類 * AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); * context.addBeanFactoryPostProcessor(...); * Car car = (Car) context.getBean("car"); * System.out.println(car.getName()); * context.close(); * } */ PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } ...... }
這裡要呼叫bean工廠的後置處理器了. 看上面的註釋, 註釋寫的很清晰.
在呼叫PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());的時候呼叫了getBeanFactoryPostProcessors()方法.
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
getBeanFactoryPostProcessors() 返回的是一個工廠的後置處理器的List, 這個時候list是空的 getBeanFactoryPostProcessors()裡面的值是怎麼來的呢? 通過在自定義main方法中呼叫context.addBeanFactoryPostProcessor(...);來新增. 也就是通過main方法手動新增的beanFactoryPostProcessor. 如下所示
public static void main(String[] args) { // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); context.addBeanFactoryPostProcessor(...); Car car = (Car) context.getBean("car"); System.out.println(car.getName()); context.close(); }
接下來重點來了. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); 方法實現一共分為兩大步:
第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. (BeanDefinitionRegistryPostProcessor帶註冊功能的後置處理器)
第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器
第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義.
來看看原始碼是如何定義的. 重點看程式碼的註釋, 每一部分的功能都有明確標出, 註釋寫的很詳細
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { /** * 首先,呼叫BeanDefinitionRegistryPostProcessors的後置處理器 * 定義已處理的後置處理器 */ // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<>(); /** * 這裡一共分為兩大步: * 第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. (BeanDefinitionRegistryPostProcessor帶註冊功能的後置處理器) * 第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器 */ /**********************第一步: 呼叫所有實現了BeanDefinitionRegistryPostProcessor介面的bean定義 begin****************************/ // 判斷beanFactory是否實現了BeanDefinitionRegistry, 實現了該結構就有註冊和獲取Bean定義的能力 if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // Separate between BeanDefinitionRegistryPostProcessors that implement // PriorityOrdered, Ordered, and the rest. /** * 這是一個集合, 存馬上即將要被呼叫的BeanDefinitionRegistryPostProcessor */ List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // 第一步, 呼叫實現了PriorityOrdered的BeanDefinitionRegistryPostProcessors // 在所有創世紀的後置處理器中, 只有 internalConfigurationAnnotationProcessor 實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 判斷beanFactory是否實現了PriorityOrdered介面. 如果實現了,是最優先呼叫. // 在整個載入過程中,會呼叫四次BeanDefinitionRegistryPostProcessor, 而實現了PriorityOrdered的介面最先呼叫 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 呼叫beanFactory.getBean例項化創世界的類ppName currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第一次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 處理完了,清空currentRegistryProcessors currentRegistryProcessors.clear(); // 第二步: 呼叫實現 Ordered 的 BeanDefinitionRegistryPostProcessors。 // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 這時實現了PriorityOrdered.class的postProcessor就不會再被載入進來了, 因為processedBeans.contains(ppName) == true if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { // 將其放入到currentRegistryProcessors, 馬上就要被呼叫 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } // 對所有的處理器進行排序. 呼叫了Ordered的方法, 會返回排序(一個數字), 然後根據數字排序即可 sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第二次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // 第三步. 呼叫沒有實現任何優先順序介面的 BeanDefinitionRegistryPostProcessor // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. boolean reiterate = true; while (reiterate) { reiterate = false; // 獲取 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 已處理過的postProcessor不再處理 if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第三次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. /* * 第四步:呼叫bean工廠的後置處理器 * registryProcessors: 帶有註冊功能的bean工廠的後置處理器 * regularPostProcessors: 不帶註冊功能的bean工廠的後置處理器 */ invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { /* * 如果當前的beanFactory沒有實現BeanDefinitionRegistry 說明沒有註冊Bean定義的能力 * 那麼就直接呼叫 BeanDefinitionRegistryPostProcessor.postProcessBeanFactory方法 */ // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } /**********************第一步: 呼叫所有實現了BeanDefinitionRegistryPostProcessor介面的bean定義 end****************************/ /**********************第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器 begin****************************/ // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. // 優先排序的後置處理器 List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // 首先, 呼叫有優先順序排序的後置處理器 // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // 第二, 呼叫實現了Ordered排序的後置處理器 // Next, invoke the BeanFactoryPostProcessors that implement Ordered. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // 最後, 呼叫沒有實現任何排序介面的beanFactory後置處理器 // Finally, invoke all other BeanFactoryPostProcessors. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); /**********************第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器 end****************************/ // Clear cached merged bean definitions since the post-processors might have // modified the original metadata, e.g. replacing placeholders in values... beanFactory.clearMetadataCache(); }
下面我們就來分析上圖所示的內容.
1. 對照原始碼和上圖, 我們來看第一次呼叫
// 第一次, 呼叫實現了PriorityOrdered的BeanDefinitionRegistryPostProcessors // 在所有創世紀的後置處理器中, 只有 internalConfigurationAnnotationProcessor 實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 判斷beanFactory是否實現了PriorityOrdered介面. 如果實現了,是最優先呼叫. // 在整個載入過程中,會呼叫四次BeanDefinitionRegistryPostProcessor, 而實現了PriorityOrdered的介面最先呼叫 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 呼叫beanFactory.getBean例項化創世界的類ppName currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第一次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 處理完了,清空currentRegistryProcessors currentRegistryProcessors.clear();
首先, 拿到了所有實現了BeanDefinitionRegistryPostProcessor的後置處理器, 上面我們做過鋪墊,只有ConfigurationClassPostProcessor實現了BeanDefinitionRegistryPostProcessor後置處理器
所以,這裡過濾出來的postProcessorNames只有一個,就是ConfigurationClassPostProcessor, 接下來, 判斷這個類是否實現了PriorityOrdered 優先排序的介面, 如果實現了, 那麼放入到currentRegistryProcessors中, 後面會進行呼叫.
接下來, 執行invokeBeanDefinitionRegistryPostProcessors
這是第一次呼叫BeanDefinitionRegistryPostProcessors
2. 第二次呼叫BeanDefinitionRegistryPostProcessors
// 第二步: 呼叫實現 Ordered 的 BeanDefinitionRegistryPostProcessors。 // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 這時實現了PriorityOrdered.class的postProcessor就不會再被載入進來了, 因為processedBeans.contains(ppName) == true if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { // 將其放入到currentRegistryProcessors, 馬上就要被呼叫 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } // 對所有的處理器進行排序. 呼叫了Ordered的方法, 會返回排序(一個數字), 然後根據數字排序即可 sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第二次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear();
第二次呼叫的時候 ,依然是獲取所有的實現了BeanDefinitionRegistryPostProcessor介面的後置處理器, 且這個處理器沒有實現過PriorityOrdered也就是沒有被上面呼叫過. 且實現了Ordered介面
這一類新增到currentRegistryProcessors集合中, 然後呼叫invokeBeanDefinitionRegistryPostProcessors處理
這是第二次呼叫BeanDefinitionRegistryPostProcessor
3. 第三次呼叫BeanDefinitionRegistryPostProcessor
// 第三步. 呼叫沒有實現任何優先順序介面的 BeanDefinitionRegistryPostProcessor // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. boolean reiterate = true; while (reiterate) { reiterate = false; // 獲取 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 已處理過的postProcessor不再處理 if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第三次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); }
第三次呼叫的是沒有實現過任何排序介面的後置處理器. 並將其放入到currentRegistryProcessors, 然後執行invokeBeanDefinitionRegistryPostProcessors
4. 第四次呼叫
// Now, invoke the postProcessBeanFactory callback of all processors handled so far. /* * 呼叫bean工廠的後置處理器 * registryProcessors: 帶有註冊功能的bean工廠的後置處理器 * regularPostProcessors: 不帶註冊功能的bean工廠的後置處理器 */ // 呼叫BeanDefinitionRegistryPostProcessor.postProcessBeanFactory方法----為什麼是呼叫BeanDefinitionRegistryPostProcessor? 因為 // ConfigurationClassPostProcessor 實現了 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessors invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); // 呼叫BeanFactoryPostProcessor 自設的(ConfigurationClassPostProcessor沒有) invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
ConfigurationClassPostProcessor同時實現了BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessors, 呼叫的是invokeBeanFactoryPostProcessors
一共進行了4次呼叫
總結: 優先處理的是實現了PriorityOrdered的後置處理器, 然後呼叫實現了Order介面的後置處理器, 最後呼叫了沒有實現任何排序方法的後置處理器. 最後呼叫工廠類方法.
下面我們來具體分析invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
5. 提問: 檢驗一下是否理解了上面四個步驟
1. ConfigurationClassPostProcessor會呼叫1234哪幾步? 因為ConfigurationClassPostProcessor實現了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor,PriorityOrdered, 因此會呼叫1,4 2. 如果自己定義了一個MyBeanFactoryPostProcessor會呼叫1234那幾步? package com.lxl.www.iocbeanlifecicle; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.stereotype.Component; @Component public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } } 因為MyBeanFactoryPostProcessor是自定義的, 沒有實現任何PriorityOrdered 或者 Order, 因此, 會呼叫3,4
二. 詳細研究第四步, invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);的邏輯.
我們在這一步打個斷點, 然後跟著斷點一步一步點選進去
這是registryProcessors裡面只有一個後置處理器, 就是ConfigurationClassPostProcessor.
然後進入到ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } // 使用 cglib 配置類進行代理, 因為@Bean方法到時候要進行建立Bean的例項. enhanceConfigurationClasses(beanFactory); beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }
這裡先看enhanceConfigurationClasses(beanFactory);個方法
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) { Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>(); for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE); MethodMetadata methodMetadata = null; if (beanDef instanceof AnnotatedBeanDefinition) { methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata(); } if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) { // Configuration class (full or lite) or a configuration-derived @Bean method // -> resolve bean class at this point... AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef; if (!abd.hasBeanClass()) { try { abd.resolveBeanClass(this.beanClassLoader); } catch (Throwable ex) { throw new IllegalStateException( "Cannot load configuration class: " + beanDef.getBeanClassName(), ex); } } } /** * 只有full版配置才會建立cglib代理 * full是怎麼來的呢? 我們使用@Configuration註解了, 在載入的時候, 就會設定為full * 當設定為full以後, 我們在呼叫的時候, 就會建立一個cglib動態代理. * * 為什麼要建立動態代理呢? * 動態代理可以保證, 每次建立的bean物件只有一個 * * 那麼加@Configuration和不加本質上的區別是什麼? * 當在配置類中一個@Bean使用方法的方式引入另一個Bean的時候, 如果不加@Configuration註解, 就會重複載入Bean * 如果加了@Configuration, 則會在這裡建立一個cglib代理, 當呼叫了@Bean方法是會先檢測容器中是否存在這個Bean, 如果不存在則建立, 存在則直接使用. */ if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) { if (!(beanDef instanceof AbstractBeanDefinition)) { throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" + beanName + "' since it is not stored in an AbstractBeanDefinition subclass"); } else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) { logger.info("Cannot enhance @Configuration bean definition '" + beanName + "' since its singleton instance has been created too early. The typical cause " + "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " + "return type: Consider declaring such methods as 'static'."); } configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); } } if (configBeanDefs.isEmpty()) { // nothing to enhance -> return immediately return; } ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(); for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) { AbstractBeanDefinition beanDef = entry.getValue(); // If a @Configuration class gets proxied, always proxy the target class beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); // Set enhanced subclass of the user-specified bean class Class<?> configClass = beanDef.getBeanClass(); Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader); if (configClass != enhancedClass) { if (logger.isTraceEnabled()) { logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " + "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName())); } beanDef.setBeanClass(enhancedClass); } } }
粗體部分就是判斷是否需要進行cglib代理. 進行cglib代理的條件是, beanDefinition中屬性configurationClass的值是full. 只有full版配置才會建立cglib代理
那麼有下面幾個問題:
問題1: full版本配置是什麼呢?
我們使用@Configuration註解了, 在載入的時候, 就會將configurationClass屬性設定為full.當設定為full以後, 我們在呼叫的時候, 就會建立一個cglib動態代理.
問題2: 為什麼要建立動態代理呢?
動態代理可以保證, 每次建立的bean物件只有一個
問題3:那麼加@Configuration和不加本質上的區別是什麼?
當在配置類中一個@Bean使用方法的方式引入另一個Bean的時候, 如果不加@Configuration註解, 就會重複載入Bean.如果加了@Configuration, 則會在這裡建立一個cglib代理, 當呼叫了@Bean方法是會先檢測容器中是否存在這個Bean, 如果不存在則建立, 存在則直接使用.
問題4:full是怎麼來的呢?
這是在上面呼叫invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);介面的時候, 標記的是full還是Lite
下面來看一下原始碼
在這裡一步,執行的時候,進行了這個類是full的還是lite,繼續忘下看
此時滿足條件的postProcessor只有一個, 那就是ConfigurationClassPostProcessor. 下面直接看ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法
前面都是一些條件判斷, 重點看processConfigBeanDefinitions(registry);
在這裡,這個方法判斷了, 這個類是full的還是lite的. 下面直接上程式碼
/** * Check whether the given bean definition is a candidate for a configuration class * (or a nested component class declared within a configuration/component class, * to be auto-registered as well), and mark it accordingly. * @param beanDef the bean definition to check * @param metadataReaderFactory the current factory in use by the caller * @return whether the candidate qualifies as (any kind of) configuration class */ public static boolean checkConfigurationClassCandidate( BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { String className = beanDef.getBeanClassName(); if (className == null || beanDef.getFactoryMethodName() != null) { return false; } AnnotationMetadata metadata; // 獲取後設資料 if (beanDef instanceof AnnotatedBeanDefinition && className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) { // Can reuse the pre-parsed metadata from the given BeanDefinition... metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata(); } else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) { // Check already loaded Class if present... // since we possibly can't even load the class file for this Class. Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass(); if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) || BeanPostProcessor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass) || EventListenerFactory.class.isAssignableFrom(beanClass)) { return false; } metadata = AnnotationMetadata.introspect(beanClass); } else { try { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className); metadata = metadataReader.getAnnotationMetadata(); } catch (IOException ex) { if (logger.isDebugEnabled()) { logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex); } return false; } } // 判斷後設資料中是否包含Configuration註解 Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName()); /** * 判斷, proxyBeanMethods屬性是否為true, 如果為true就是一個完全的類, * 也就是帶有@Configuration註解, 設定Configuration_class屬性為full * * proxyBeanMethods配置類是用來指定@Bean註解標註的方法是否使用代理, * 預設是true使用代理,直接從IOC容器之中取得物件; * 如果設定為false,也就是不使用註解,每次呼叫@Bean標註的方法獲取到的物件和IOC容器中的都不一樣,是一個新的物件,所以我們可以將此屬性設定為false來提高效能。 */ if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } // 判斷是不是帶了@Component, @ComponentScan @Import @ImportResource @Bean註解, // 如果帶有這幾種註解, 就將其Configuration_class屬性為lite型別的配置類 else if (config != null || isConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { return false; } // It's a full or lite configuration candidate... Let's determine the order value, if any. Integer order = getOrder(metadata); if (order != null) { beanDef.setAttribute(ORDER_ATTRIBUTE, order); } return true; }
上面主要是獲取後設資料, 然後判斷後設資料中是否有Configuration註解. 如果有,返回其屬性. 我們判斷其屬性中proxyBeanMethods是否true, 如果是true, 那麼將其設定為full.
如果配置中帶有@Component, @ComponentScan @Import @ImportResource @Bean這幾種屬性之一, 那麼就將其設定為lite.
問題5: cglib動態代理做了什麼事情呢?
不看原始碼的情況下, 簡單可以理解為, 去ioc工廠裡面通過getBean("car") 查詢了看ioc中是否有這個物件, 如果有就取出來, 不再另建立.
這也是@Configuration 和其他註解類似@Component和@ComponentScan的本質區別:
當在配置類中一個@Bean使用方法的方式引入另一個Bean的時候, 如果不加@Configuration註解, 就會重複建立Bean
如果加了@Configuration, 則會在這裡建立一個cglib代理, 當呼叫了@Bean方法是會先檢測容器中是否存在這個Bean, 如果不存在則建立, 存在則直接使用.
下面來看個例子
基礎類: public class Car { private String name; private Tank tank; public String getName() { return name; } public void setName(String name) { this.name = name; } public Tank getTank() { return tank; } public void setTank(Tank tank) { this.tank = tank; } } public class Tank { private String name; public Tank() { System.out.println("建立一個tank"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
這是定義的car和tank的基礎類
@Configuration @ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"}) public class MainConfig { @Bean("car") public Car car() { Car car = new Car(); car.setName("zhangsan"); // 這裡呼叫了Tank類, tank是通過@Bean註解注入的. car.setTank(tank()); return car; } @Bean public Tank tank() { return new Tank(); } }
當配置類使用了@Configuration註解的時候, 執行main方法
public class MainStarter { public static void main(String[] args) { // 第一步: 通過AnnotationConfigApplicationContext讀取一個配置類 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); context.scan("package"); //context.addBeanFactoryPostProcessor(); Car car = (Car) context.getBean("car"); Car car2 = (Car) context.getBean("car"); System.out.println(car.getName()); context.close(); } }
當去掉@Configuration註解的時候, 再次執行, 我們看到建立了兩次tank
//@Configuration @ComponentScan(basePackages = {"com.lxl.www.iocbeanlifecicle"}) public class MainConfig { @Bean("car") public Car car() { Car car = new Car(); car.setName("zhangsan"); // 這裡呼叫了Tank類, tank是通過@Bean註解注入的. car.setTank(tank()); return car; } @Bean public Tank tank() { return new Tank(); } }
在main方法中呼叫了兩次(Car) context.getBean("car");
在new一個物件的時候, 如果不取ioc容器中取, 那麼每一次都會建立一個新的.
在ioc容器中, car物件只有一個, 但是在構建car的時候, 呼叫了tank, tank在ioc容器中卻不一定只有一份. 只有使用了@Configuration, 表示需要使用cglib動態代理查詢tank類, 保證ioc容器中只有一份.
7. 詳細研究四次呼叫中的第一次呼叫. 通過分析跟蹤@ComponentScan註解是如何解析的,
通過跟蹤@ComponentScan註解是如何解析的, 分來理解BeanDefinitionScan, BeanDefinitionRegistry, BeanDefinitionReader是如何工作的.
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { /** * 首先,呼叫BeanDefinitionRegistryPostProcessors 的後置處理器 * 定義已處理的後置處理器 */ // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<>(); /** * 這裡一共分為兩大步: * 第一步: 呼叫所有實現了 BeanDefinitionRegistryPostProcessor 介面的bean定義. (BeanDefinitionRegistryPostProcessor帶註冊功能的後置處理器) * 第二步: 呼叫BeanFactoryPostProcessor Bean工廠的後置處理器 */ /**********************第一步: 呼叫所有實現了BeanDefinitionRegistryPostProcessor介面的bean定義 begin****************************/ // 判斷beanFactory是否實現了BeanDefinitionRegistry, 實現了該結構就有註冊和獲取Bean定義的能力 if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // Separate between BeanDefinitionRegistryPostProcessors that implement // PriorityOrdered, Ordered, and the rest. /** * 這是一個集合, 存馬上即將要被呼叫的BeanDefinitionRegistryPostProcessor */ List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // 首先, 呼叫實現了PriorityOrdered的BeanDefinitionRegistryPostProcessors // 在所有創世紀的後置處理器中, 只有 internalConfigurationAnnotationProcessor 實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 判斷beanFactory是否實現了PriorityOrdered介面. 如果實現了,是最優先呼叫. // 在整個載入過程中,會呼叫四次BeanDefinitionRegistryPostProcessor, 而實現了PriorityOrdered的介面最先呼叫 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 呼叫beanFactory.getBean例項化配置類的後置處理器(創世界的類ppName), 也就是初始化, 例項化, 賦值屬性. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); /** * 第一次呼叫BeanDefinitionRegistryPostProcessors * 在這裡典型的BeanDefinitionRegistryPostProcessors就是ConfigurationClassPostProcessor * 用於進行bean定義的載入 比如我們的包掃描 @import 等 */ invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 處理完了,清空currentRegistryProcessors currentRegistryProcessors.clear();
這裡也有兩大步
第一步: 初始化bean工廠的後置處理器
通過呼叫beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class) 初始化了bean工廠的後置處理器,
第二步: 解析配置
呼叫invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);呼叫beanDefinitionRegistry的後置處理器. 篩選出符合條件的配置類.
如上圖所示, 最後篩選出的配置類只有MainConfig配置類. 也就是說configCandidates配置候選集合中只有一個MainConfig
// 建立一個ConfigurationClassParser物件, 解析@Configuration class 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();
然後, 接下來建立了一個物件ConfigurationClassParser, 這是一個配置類解析器. 下面將使用這個解析器解析配置類.
重點是如何解析的, 程式碼已重點標註出來了.
// 執行解析
parser.parse(candidates);
我們這裡是通過註解解析的, 所以直接看下面的程式碼
public void parse(Set<BeanDefinitionHolder> configCandidates) { // 迴圈配置類 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { // 真正的解析bean定義:通過註解後設資料解析 if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } ...... }
解析主要做了幾件事呢?如下圖:
解析配置類, 看看配置類是否含有如上標記的註解, 如果有, 則呼叫響應的返回對其進行解析,處理.
下面來看看原始碼. 是如何處理這一塊的.
/** * 在這裡會解析@Component @PropertySources @ComponentScan @ImportResource * @param configClass * @param sourceClass * @param filter * @return * @throws IOException */ @Nullable protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { // 1. 處理@Component註解,判斷後設資料是否帶有Component註解 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass, filter); } // Process any @PropertySource annotations // 2. 處理@PropertySource 註解, 判斷後設資料是否帶有@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.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations // 3. 處理@ComponentScan註解, 判斷後設資料是否帶有@ComponentScan註解 /** * 這裡mainConfig配置類中有兩個註解,一個是@Configuration ,一個是@ComponentScan. 在這裡, 我們看一下@ComponentScan */ //componentScans 拿到的就是ComponentScan註解裡的屬性 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); 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 // 解析掃描出來的類, 將其解析為BeanDefinitionHolder物件, 並放入到scannedBeanDefinitions中 // 這正的解析ComponentScans和ComponentScan中的配置 Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // 迴圈處理包掃描出來的bean定義 // 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()); } } } } // 4. 處理@Import註解 // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), filter, true); // 5. 處理@ImportResource註解 // Process any @ImportResource annotations 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); } } // 6. 處理@Bean註解 // Process individual @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; }
下面我們重點看對@ComponentScan和@ComponentScans註解的解析, 為什麼看他呢? 因為很多註解都標記了@Component註解.
比如@Service註解,本身使用@Component
再來看@Controller註解, 其實質也是一個@Component註解
我們在自定義配置類的時候, 會使用@ComponentScan註解. 並傳遞一個包, 作為掃描包. 如MainConfig配置
這就會掃描包下所有的配置類.
它主要的邏輯如下:
在拿到@ComponentScan註解以後, 會對其進行parse. 主要解析裡面的註解. 並對每一個註解進行處理. 處理後將其新增到scanner屬性中. 最後呼叫scanner.doScan(....)方法.
原始碼如下:
// 解析配置 public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { // 定義了一個類路徑掃描器ClassPathBeanDefinitionScanner // 這裡的scanner用於讀取配置類 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); // 1. 判斷是否有nameGenerator註解 // 為掃描器設定beanName的生成器物件, 並賦值給scanner, BeanNameGenerator的作用是為bean definitions生成Bean名字的介面 Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); // 2. 判斷是否有scopedProxy註解 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")); // 3. 判斷屬性中是否有includeFilters屬性, 有的話就新增到scanner中 // 設定componentScan中包含的過濾器 -- 在使用註解的時候配置了包含和排除的過濾器, 這裡進行處理 for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } // 4. 判斷屬性總是否有excludeFilters屬性, 有的話放到scnanner中 // 設定componentScan中排除的過濾器 for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); } } // 5. 判斷是否有lazyInit屬性 // 獲取配置類中懶載入初始化的屬性 boolean lazyInit = componentScan.getBoolean("lazyInit"); if (lazyInit) { scanner.getBeanDefinitionDefaults().setLazyInit(true); } Set<String> basePackages = new LinkedHashSet<>(); // 6. 判斷是否有basePackages屬性 // 獲取basePackages屬性, 也就是我們定義的包掃描路徑 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); } }); // 呼叫scanner.doScan()方法, 掃描basePackages包 return scanner.doScan(StringUtils.toStringArray(basePackages)); }
呼叫doScan方法掃描配置類. 我們來看看主要做了哪些事情
第一步: 找到所有候選的BeanDefinition.
上面解析出了@ComponentScan註解傳遞過來的basePackages包. 掃描包中所有的類, 得到候選類.
掃描的時候做了幾件事呢? 看最上圖最右側部分. 這掃描出來就是我們的目標類.
第二步: 解析這些準目標類.
第三步: 設定預設的beanDefinition屬性
/** * 設定預設的bean定義的資訊 * Apply the provided default values to this bean. * @param defaults the default settings to apply * @since 2.5 */ public void applyDefaults(BeanDefinitionDefaults defaults) { // 設定這個類是不是懶載入的 Boolean lazyInit = defaults.getLazyInit(); if (lazyInit != null) { setLazyInit(lazyInit); } // 設定預設的自動裝配方式 setAutowireMode(defaults.getAutowireMode()); setDependencyCheck(defaults.getDependencyCheck()); // 設定初始化方法的名稱 setInitMethodName(defaults.getInitMethodName()); // 是否可以呼叫InitMethod方法 setEnforceInitMethod(false); setDestroyMethodName(defaults.getDestroyMethodName()); // 是否可以呼叫DestroyMethod方法 setEnforceDestroyMethod(false); }
第四步: 將解析出來的bean定義註冊到ioc容器中
這裡就呼叫了BeanDefinitionReaderUtils.registerBeanDefinition註冊bean定義. 之前註冊過配置類, 這裡和其是一樣的. 所以不再贅述了
到此為止, 就將MainConfig配置類解析完並註冊到ioc容器中了.