Spring筆記(6) - Spring的BeanFactoryPostProcessor探究
一.背景
在說BeanFactoryPostProcessor之前,先來說下BeanPostProcessor,在前文Spring筆記(2) - 生命週期/屬性賦值/自動裝配及部分原始碼解析中講解了BeanPostProcessor是一個bean後置處理器(bean建立物件初始化前後進行攔截工作)。
BeanPostProcessor的執行流程如下:
1)Spring IOC容器例項化Bean;
2)呼叫BeanPostProcessor的postProcessBeforeInitialization方法;
3)呼叫bean例項的初始化方法;
4)呼叫BeanPostProcessor的postProcessAfterInitialization方法;
實現BeanPostProcessor介面可以在Bean(例項化之後)初始化的前後做一些自定義的操作,但是拿到的引數只有BeanDefinition例項和BeanDefinition的名稱,也就是無法修改BeanDefinition元資料,這裡說的Bean的初始化是:
1)bean實現了InitializingBean介面,對應的方法為afterPropertiesSet
2)在bean定義的時候,通過init-method設定的方法
Spring中Bean的例項化過程圖示:
那麼BeanFactoryPostProcessor顧名思義就是bean工廠的後置處理器,說通俗一些就是可以管理我們的bean工廠內所有的BeanDefinition(未例項化
Spring容器初始化時,從資源中讀取到bean的相關定義後,儲存在beanFactory的成員變數中(參考DefaultListableBeanFactory類的成員變數beanDefinitionMap),在例項化bean的操作就是依據這些bean的定義來做的,而在例項化之前,Spring允許我們通過自定義擴充套件來改變bean的定義,定義一旦變了,後面的例項也就變了,而beanFactory後置處理器,即BeanFactoryPostProcessor就是用來改變bean定義的;如果業務需要,可以配置多個BeanFactoryPostProcessor的實現類,通過”order”控制執行次序(要實現Ordered介面)。
註冊一個BeanFactoryPostProcessor例項需要定義一個Java類來實現BeanFactoryPostProcessor介面,並重寫該介面的postProcessorBeanFactory方法。通過beanFactory可以獲取bean的定義資訊,並可以修改bean的定義資訊。(這點是和BeanPostProcessor最大區別)
所以通過上面的介紹可以總結出有兩種方式可以對bean做控制(例如修改某個成員變數):
1. 只改變例項化的物件(BeanPostProcessor介面);
2. 改變bean的定義(BeanFactoryPostProcessor介面) ,可以想象成修改了class檔案,這樣例項化出來的每個物件都變了;
PS:BeanFactoryPostProcessor回撥會先於BeanPostProcessor
下面是BeanFactoryPostProcessor的原始碼:
public interface BeanFactoryPostProcessor { /** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for overriding or adding * properties even to eager-initializing beans. * @param beanFactory the bean factory used by the application context * @throws org.springframework.beans.BeansException in case of errors */ //在ioc容器的bean Factory標準初始化之後可以對它們進行修改。所有的bean定義被載入了,但還沒有被例項化。 //允許進行過載或新增屬性即使在eager-initializing beans void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
BeanFactoryPostProcessor此介面只提供了一個方法,方法引數為ConfigurableListableBeanFactory,下面是該類的原始碼:
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { void ignoreDependencyType(Class<?> type); void ignoreDependencyInterface(Class<?> ifc); void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue); boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException; BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; Iterator<String> getBeanNamesIterator(); void clearMetadataCache(); void freezeConfiguration(); boolean isConfigurationFrozen(); void preInstantiateSingletons() throws BeansException; }
其中有個方法名為getBeanDefinition的方法,我們可以根據此方法,找到我們定義bean的BeanDefinition物件。然後我們可以對定義的屬性進行修改,以下是BeanDefinition中的方法:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { /** * Scope identifier for the standard singleton scope: "singleton". * <p>Note that extended bean factories might support further scopes. * @see #setScope */ String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; /** * Scope identifier for the standard prototype scope: "prototype". * <p>Note that extended bean factories might support further scopes. * @see #setScope */ String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /** * Role hint indicating that a {@code BeanDefinition} is a major part * of the application. Typically corresponds to a user-defined bean. */ int ROLE_APPLICATION = 0; /** * Role hint indicating that a {@code BeanDefinition} is a supporting * part of some larger configuration, typically an outer * {@link org.springframework.beans.factory.parsing.ComponentDefinition}. * {@code SUPPORT} beans are considered important enough to be aware * of when looking more closely at a particular * {@link org.springframework.beans.factory.parsing.ComponentDefinition}, * but not when looking at the overall configuration of an application. */ int ROLE_SUPPORT = 1; /** * Role hint indicating that a {@code BeanDefinition} is providing an * entirely background role and has no relevance to the end-user. This hint is * used when registering beans that are completely part of the internal workings * of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}. */ int ROLE_INFRASTRUCTURE = 2; // Modifiable attributes /** * Set the name of the parent definition of this bean definition, if any. */ void setParentName(@Nullable String parentName); /** * Return the name of the parent definition of this bean definition, if any. */ @Nullable String getParentName(); /** * Specify the bean class name of this bean definition. * <p>The class name can be modified during bean factory post-processing, * typically replacing the original class name with a parsed variant of it. * @see #setParentName * @see #setFactoryBeanName * @see #setFactoryMethodName */ void setBeanClassName(@Nullable String beanClassName); /** * Return the current bean class name of this bean definition. * <p>Note that this does not have to be the actual class name used at runtime, in * case of a child definition overriding/inheriting the class name from its parent. * Also, this may just be the class that a factory method is called on, or it may * even be empty in case of a factory bean reference that a method is called on. * Hence, do <i>not</i> consider this to be the definitive bean type at runtime but * rather only use it for parsing purposes at the individual bean definition level. * @see #getParentName() * @see #getFactoryBeanName() * @see #getFactoryMethodName() */ @Nullable String getBeanClassName(); /** * Override the target scope of this bean, specifying a new scope name. * @see #SCOPE_SINGLETON * @see #SCOPE_PROTOTYPE */ void setScope(@Nullable String scope); /** * Return the name of the current target scope for this bean, * or {@code null} if not known yet. */ @Nullable String getScope(); /** * Set whether this bean should be lazily initialized. * <p>If {@code false}, the bean will get instantiated on startup by bean * factories that perform eager initialization of singletons. */ void setLazyInit(boolean lazyInit); /** * Return whether this bean should be lazily initialized, i.e. not * eagerly instantiated on startup. Only applicable to a singleton bean. */ boolean isLazyInit(); /** * Set the names of the beans that this bean depends on being initialized. * The bean factory will guarantee that these beans get initialized first. */ void setDependsOn(@Nullable String... dependsOn); /** * Return the bean names that this bean depends on. */ @Nullable String[] getDependsOn(); /** * Set whether this bean is a candidate for getting autowired into some other bean. * <p>Note that this flag is designed to only affect type-based autowiring. * It does not affect explicit references by name, which will get resolved even * if the specified bean is not marked as an autowire candidate. As a consequence, * autowiring by name will nevertheless inject a bean if the name matches. */ void setAutowireCandidate(boolean autowireCandidate); /** * Return whether this bean is a candidate for getting autowired into some other bean. */ boolean isAutowireCandidate(); /** * Set whether this bean is a primary autowire candidate. * <p>If this value is {@code true} for exactly one bean among multiple * matching candidates, it will serve as a tie-breaker. */ void setPrimary(boolean primary); /** * Return whether this bean is a primary autowire candidate. */ boolean isPrimary(); /** * Specify the factory bean to use, if any. * This the name of the bean to call the specified factory method on. * @see #setFactoryMethodName */ void setFactoryBeanName(@Nullable String factoryBeanName); /** * Return the factory bean name, if any. */ @Nullable String getFactoryBeanName(); /** * Specify a factory method, if any. This method will be invoked with * constructor arguments, or with no arguments if none are specified. * The method will be invoked on the specified factory bean, if any, * or otherwise as a static method on the local bean class. * @see #setFactoryBeanName * @see #setBeanClassName */ void setFactoryMethodName(@Nullable String factoryMethodName); /** * Return a factory method, if any. */ @Nullable String getFactoryMethodName(); /** * Return the constructor argument values for this bean. * <p>The returned instance can be modified during bean factory post-processing. * @return the ConstructorArgumentValues object (never {@code null}) */ ConstructorArgumentValues getConstructorArgumentValues(); /** * Return if there are constructor argument values defined for this bean. * @since 5.0.2 */ default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } /** * Return the property values to be applied to a new instance of the bean. * <p>The returned instance can be modified during bean factory post-processing. * @return the MutablePropertyValues object (never {@code null}) */ MutablePropertyValues getPropertyValues(); /** * Return if there are property values values defined for this bean. * @since 5.0.2 */ default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } /** * Set the name of the initializer method. * @since 5.1 */ void setInitMethodName(@Nullable String initMethodName); /** * Return the name of the initializer method. * @since 5.1 */ @Nullable String getInitMethodName(); /** * Set the name of the destroy method. * @since 5.1 */ void setDestroyMethodName(@Nullable String destroyMethodName); /** * Return the name of the destroy method. * @since 5.1 */ @Nullable String getDestroyMethodName(); /** * Set the role hint for this {@code BeanDefinition}. The role hint * provides the frameworks as well as tools with an indication of * the role and importance of a particular {@code BeanDefinition}. * @since 5.1 * @see #ROLE_APPLICATION * @see #ROLE_SUPPORT * @see #ROLE_INFRASTRUCTURE */ void setRole(int role); /** * Get the role hint for this {@code BeanDefinition}. The role hint * provides the frameworks as well as tools with an indication of * the role and importance of a particular {@code BeanDefinition}. * @see #ROLE_APPLICATION * @see #ROLE_SUPPORT * @see #ROLE_INFRASTRUCTURE */ int getRole(); /** * Set a human-readable description of this bean definition. * @since 5.1 */ void setDescription(@Nullable String description); /** * Return a human-readable description of this bean definition. */ @Nullable String getDescription(); // Read-only attributes /** * Return a resolvable type for this bean definition, * based on the bean class or other specific metadata. * <p>This is typically fully resolved on a runtime-merged bean definition * but not necessarily on a configuration-time definition instance. * @return the resolvable type (potentially {@link ResolvableType#NONE}) * @since 5.2 * @see ConfigurableBeanFactory#getMergedBeanDefinition */ ResolvableType getResolvableType(); /** * Return whether this a <b>Singleton</b>, with a single, shared instance * returned on all calls. * @see #SCOPE_SINGLETON */ boolean isSingleton(); /** * Return whether this a <b>Prototype</b>, with an independent instance * returned for each call. * @since 3.0 * @see #SCOPE_PROTOTYPE */ boolean isPrototype(); /** * Return whether this bean is "abstract", that is, not meant to be instantiated. */ boolean isAbstract(); /** * Return a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ @Nullable String getResourceDescription(); /** * Return the originating BeanDefinition, or {@code null} if none. * Allows for retrieving the decorated bean definition, if any. * <p>Note that this method returns the immediate originator. Iterate through the * originator chain to find the original BeanDefinition as defined by the user. */ @Nullable BeanDefinition getOriginatingBeanDefinition(); }View Code
我們可以在上面程式碼中發現裡面的方法名字類似bean標籤的屬性,setBeanClassName對應bean標籤中的class屬性,所以當我們拿到BeanDefinition物件時,我們可以手動修改bean標籤中所定義的屬性值。
具體這個BeanDefinition是個什麼物件,當我們在xml中定義了bean標籤時,Spring會把這些bean標籤解析成一個javabean,這個BeanDefinition就是bean標籤對應的javabean。
所以當我們呼叫BeanFactoryPostProcess方法時,這時候bean還沒有例項化,此時bean剛被解析成BeanDefinition物件。
Spring容器初始化bean大致過程 :
1)定義bean標籤
2)將bean標籤解析成BeanDefinition
3)呼叫構造方法例項化(IOC)
4)屬性值得依賴注入(DI)
所以可以看出BeanFactoryPostProcess方法的執行是發生在第二步之後,第三步之前。
綜上所述BeanPostProcessor和BeanFactoryPostProcess都是為Spring提供的後處理bean的介面,只是兩者執行的時機不一樣。BeanPostProcessor為例項化之後,BeanFactoryPostProcess是例項化之前。功能上,BeanFactoryPostProcess對bean的處理功能更加強大。
二.案例
1.配置類:進行包掃描將類載入到容器中
@ComponentScan("com.hrh.ext") @Configuration public class ExtConfig { @Bean public Person person() { return new Person("張三", "男"); } }
2.實體類:
public class Person implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware { private String name; private String sex; public Person() { System.out.println("Person無參構造器"); } public Person(String name, String sex) { System.out.println("Person有參構造器:[name=" + name + ",sex=" + sex + "]"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("[Person]呼叫了BeanFactoryAware的setBeanFactory方法了:" + beanFactory); } @Override public void setBeanName(String name) { System.out.println("[Person]呼叫了BeanNameAware的setBeanName方法了:" + name); } @Override public void destroy() throws Exception { System.out.println("[Person]呼叫了DisposableBean的destroy方法了"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("[Person]呼叫了Initailization的afterPropertiesSet方法了"); } @Override public String toString() { return "Person [name=" + name + ", sex=" + sex + "]"; } }
3.自定義BeanFactoryPostProcessor類:
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("[MyBeanFactoryPostProcessor]呼叫了postProcessBeanFactory"); int count = beanFactory.getBeanDefinitionCount(); System.out.println("[MyBeanFactoryPostProcessor]當前beanFactory共有" + count + "個bean"); String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); System.out.println("[MyBeanFactoryPostProcessor]當前beanFactory有下面元件" + Arrays.asList(beanDefinitionNames)); //獲取容器中所有的beanDefinition for (String beanName : beanDefinitionNames) { if ("person".equals(beanName)) { //獲取PersonDefinition物件 BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); System.out.println(propertyValues.toString()); //修改定義中的name屬性值 propertyValues.addPropertyValue("name", "趙四"); System.out.println("[MyBeanFactoryPostProcessor]postProcessBeanFactory方法中修改了name屬性初始值了"); System.out.println(propertyValues.toString()); } } } }
4.自定義BeanPostProcessor類:
@Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("[MyBeanPostProcessor]後置處理器處理bean=【" + beanName + "】開始"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("[MyBeanPostProcessor]後置處理器處理bean=【" + beanName + "】完畢!"); return bean; } }
5.測試:
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtConfig.class); Person bean = context.getBean(Person.class); System.out.println(bean.toString()); context.close(); } ======執行結果====== [MyBeanFactoryPostProcessor]呼叫了postProcessBeanFactory [MyBeanFactoryPostProcessor]當前beanFactory共有9個bean [MyBeanFactoryPostProcessor]當前beanFactory有下面元件[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, extConfig, myBeanFactoryPostProcessor, myBeanPostProcessor, person] PropertyValues: length=0 [MyBeanFactoryPostProcessor]postProcessBeanFactory方法中修改了name屬性初始值了 PropertyValues: length=1; bean property 'name' [MyBeanPostProcessor]後置處理器處理bean=【extConfig】開始 [MyBeanPostProcessor]後置處理器處理bean=【extConfig】完畢! Person有參構造器:[name=張三,sex=男] [Person]呼叫了BeanNameAware的setBeanName方法了:person [Person]呼叫了BeanFactoryAware的setBeanFactory方法了:org.springframework.beans.factory.support.DefaultListableBeanFactory@e45f292: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,extConfig,myBeanFactoryPostProcessor,myBeanPostProcessor,person]; root of factory hierarchy [MyBeanPostProcessor]後置處理器處理bean=【person】開始 [Person]呼叫了Initailization的afterPropertiesSet方法了 [MyBeanPostProcessor]後置處理器處理bean=【person】完畢! Person [name=趙四, sex=null] [Person]呼叫了DisposableBean的destroy方法了
從上面的執行結果可以看出:
1)Person的name值由"張三"變為"趙四";
2)BeanFactoryPostProcessor方法執行順序先於BeanPostProcessor介面中方法,且在bean例項化之前執行;
3)BeanFactoryPostProcessor改變bean的定義,例項化出來的物件變了:“Person有參構造器:[name=張三,sex=男] ”變成了“Person [name=趙四, sex=null]”
4)BeanPostProcessor在bean建立物件例項化後,初始化(bean執行afterPropertiesSet方法或init-method方法)前後進行攔截工作;
三.原理
接下來我們通過debug程式碼來檢視BeanFactoryPostProcessor的執行流程,從AbstractApplicationContext類的構造器方法看起,這裡面對應著容器初始化的基本操作;
1.在測試main方法中下面的程式碼打斷點:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtConfig.class);
2.從下圖可以看出容器先註冊配置類ExtConfig的定義資訊,然後進行refresh重新整理容器;
3.先來看看register(componentClasses)註冊流程:從class檔案讀取資訊解析成beanDefinition
AnnotationConfigApplicationContext: public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); this.reader.register(componentClasses); } AnnotatedBeanDefinitionReader:註冊beanDefinition public void register(Class<?>... componentClasses) { for (Class<?> componentClass : componentClasses) { registerBean(componentClass); } } public void registerBean(Class<?> beanClass) { doRegisterBean(beanClass, null, null, null, null); } //Register a bean from the given bean class, deriving its metadata from class-declared annotations. //從class檔案中讀取bean的定義資訊,並註冊到容器中 private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { //得到bean的所有定義資訊:元資料metadata、作用域scope、初始化方法名字initMethodName等等 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } //為bean例項建立一個特殊的回撥訊號 abd.setInstanceSupplier(supplier); //獲取作用域的資料:單例 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); //設定bean為單例 abd.setScope(scopeMetadata.getScopeName()); //獲取beanName String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); //處理一些註釋資訊:lazyInit、primary、dependsOn、role、description AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) {//qualifiers = nul 跳過 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) {//customizers = null跳過 for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } //建立一個BeanDefinitionHolder BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); //容器中註冊beanDefinition BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
4.refresh重新整理容器:invokeBeanFactoryPostProcessors方法用來找出所有beanFactory後置處理器,並且呼叫這些處理器來改變bean的定義
public void refresh() throws BeansException, IllegalStateException { //來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛 synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //容器重新整理前的處理方法:獲取啟動的系統時間、設定active活躍標識、開始列印日誌、設定環境變數、設定容器監聽器、設定容器事件 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //重新整理bean工廠並獲取到bean工廠 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // bean工廠的初始化操作:設定類載入器、設定bean表示式解析器、設定bean後置處理器等等; prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此介面, // 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。】 // 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化 // 具體的子類可以在這步的時候根據自身業務新增或修改一些特殊的 beanFactory屬性 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //找出所有beanFactory後置處理器,並且呼叫這些處理器來改變bean的定義 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.
//是個空殼方法,在AnnotationApplicationContex上下文中沒有實現,可能在spring後面的版本會去擴充套件。
//與Web上下文有關 onRefresh(); // Check for listener beans and register them. //註冊監聽器 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //物件的建立:初始化剩下所有的(非懶載入的)單例項物件【從這裡可以看出beanFactory後置處理器在初始化其他元件之前執行】 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
//重新整理完成工作,包括初始化LifecycleProcessor,釋出重新整理完成事件等 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources.
//銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源 destroyBeans(); // Reset 'active' flag.
//取消重新整理的標誌 cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
5.開啟invokeBeanFactoryPostProcessors方法,如下所示,實際操作是委託PostProcessorRegis
trationDelegate去完成的:呼叫getBeanFactoryPostProcessors()方法獲取手工註冊到ApplicationCon
text的容器後置處理器集合
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { 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())); } }
1)在呼叫PostProcessorRegistrationDelegate類的invokeBeanFactoryPostProcessors方法時,注意第二個入參是getBeanFactoryPostProcessors()方法,該方法返回的是applicationContext的成員變數beanFactoryPostProcessors,該成員變數的值來自AbstractApplicationContext.addBeanFactoryPostProcessor方法被呼叫的時候:
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>(); @Override public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) { Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null"); this.beanFactoryPostProcessors.add(postProcessor); } public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() { return this.beanFactoryPostProcessors; }
2)AbstractApplicationContext.addBeanFactoryPostProcessor方法是留給業務擴充套件時呼叫的,例如在springboot初始化時,ConfigurationWarningsApplicationContextInitializer類的initialize方法中就有呼叫:
@Override public void initialize(ConfigurableApplicationContext context) { context.addBeanFactoryPostProcessor( new ConfigurationWarningsPostProcessor(getChecks())); }
6.看過了如何新增BeanFactoryPostProcessor,再回到PostProcessorRegistrationDelegate.invok
eBeanFactoryPostProcessors方法:例項化並呼叫所有已註冊的BeanFactoryPostProcessor bean;
流程是:
1)beanFactory是BeanDefinitionRegistry型別時,此條件下完成如下流程:
1.遍歷傳入後置處理器集合查詢型別為BeanDefinitionRegistryPostProcessor的後置處理器,呼叫後置處理器的postProcessBeanDefinitionRegistry方法;
2.在容器中查詢所有的實現了PriorityOrdered介面的BeanDefinition
RegistryPostProcessor集合,對後置處理器集合排序,遍歷,執行後置處理的postProcessBeanDefinitionRegistry方法;
3.在容器中查詢所有實現了Ordered介面的BeanDefinitionRegistryPostProcessor集合,對後置處理器集合排序,遍歷,執行後置處理的postProcessBeanDefinitionRegistry方法;
4.在容器中查詢其它(未實現排序介面)的BeanDefinitionRegistryPostProcessor並新增到集合nonOrderedPostProcessors中,對後置處理器集合排序,遍歷,執行後置處理的postProcessBeanDefinitionRegistry方法;
5.當前所有的BeanDefinitionRegistryPostProcessor處理器的方法postProcessBeanD
efinitionRegistry 執行完畢後,執行其父類postProcessBeanFactory方法;
6.執行所有非BeanDefinitionRegistryPostProcessor型別的後置處理器的postProcessB
eanFactory方法;
2)beanFactory非BeanDefinitionRegistry型別時,此條件下完成如下流程:
1.遍歷傳入後置處理器集合,執行後置處理器的postProcessBeanFactory方法;
2.在容器中(beanFactory.getBeanNamesForType)查詢所有的實現了PriorityOrdered介面的BeanFactoryPostProcessor集合,對後置處理器集合排序,遍歷,執行後置處理;
3.在容器中查詢所有實現了Ordered介面的BeanFactoryPostProcessor集合,對後置處理器集合排序,遍歷,執行後置處理;
4.在容器中查詢其它(未實現排序介面)的BeanFactoryPostProcessor並新增到集合nonOrderedPostProcessors中,對後置處理器集合排序,遍歷,執行後置處理;
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<>(); //如果beanFactory實現了BeanDefinitionRegistry if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { //如果beanFactoryPostProcessor實現了BeanDefinitionRegistryPostProcessor,分別放入兩個集合:registryProcessors 和 regularPostProcessors 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. List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. //找出所有實現了BeanDefinitionRegistryPostProcessor介面和PriorityOrdered介面的bean,放入registryProcessors集合, //放入根據Set介面來排序,然後這些bean會被invokeBeanDefinitionRegistryPostProcessors方法執行; String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. //找出所有實現了BeanDefinitionRegistryPostProcessor介面和Ordered介面的bean,放入registryProcessors集合, //放入根據Set介面來排序,然後這些bean會被invokeBeanDefinitionRegistryPostProcessors方法執行; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. //對於那些實現了BeanDefinitionRegistryPostProcessor介面,但是沒有實現PriorityOrdered和Ordered的bean也被找出來, //然後這些bean會被invokeBeanDefinitionRegistryPostProcessors方法執行; boolean reiterate = true; while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. //registryProcessors和regularPostProcessors集合被invokeBeanFactoryPostProcessors執行 invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { // Invoke factory processors registered with the context instance. //入參中的BeanFactoryPostProcessor,沒有實現BeanDefinitionRegistryPostProcessor的那些bean,被invokeBeanFactoryPostProcessors執行 invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } // 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. //找出實現了BeanFactoryPostProcessor介面的bean,注意這裡已將上面實現了BeanDefinitionRegistryPostProcessor介面的bean給剔除了, //將這些bean分為三類:實現了PriorityOrdered介面的放入priorityOrderedPostProcessors, //實現了Ordered介面的放入orderedPostProcessorNames,其他的放入nonOrderedPostProcessorNames //自定義的實現BeanFactoryPostProcessor介面的bean就會在nonOrderedPostProcessorNames被找出來 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. //priorityOrderedPostProcessors先排序再被invokeBeanFactoryPostProcessors執行 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. //orderedPostProcessorNames先被遍歷加入到orderedPostProcessors,再被排序,最後才被invokeBeanFactoryPostProcessors執行 List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. //nonOrderedPostProcessorNames也是先被遍歷到nonOrderedPostProcessors,再被invokeBeanFactoryPostProcessors執行 List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } //這時才是執行自定義BeanFactoryPostProcessor的postProcessBeanFactory invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have // modified the original metadata, e.g. replacing placeholders in values... beanFactory.clearMetadataCache(); }
-
- getBeanNamesForType():根據傳遞的型別獲取容器中的beanName
// type:類的型別名稱 // includeNonSingletons:返回資料包含了非單例beanName // allowEagerInit: 可以提前載入初始化 public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) { if (!isConfigurationFrozen() || type == null || !allowEagerInit) { // 不可用快取、型別無效、不允許提前載入初始化 // 需要獲取當前type的原始型別,繼續獲取資料 return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit); } Map<Class<?>, String[]> cache = (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType); String[] resolvedBeanNames = cache.get(type); // 如果快取已經儲存了該資料,則無需再計算,直接返回即可 if (resolvedBeanNames != null) { return resolvedBeanNames; } resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true); // 這一步就是真正的獲取資料,遍歷beanDefinitionNames的每一個數據,符合要求的就會加入到返回的列表中 if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) { cache.put(type, resolvedBeanNames); // 便於下一次獲取,加入快取中 } return resolvedBeanNames; }
- getBean後面還有一個引數BeanFactoryPostProcessor.class,注意看這個函式,會發現返回的是一個抽象類,結論就是nonOrderedPostProcessors新增的不是bean例項,而是beandefinition,在例項化前。
- getBeanNamesForType():根據傳遞的型別獲取容器中的beanName
/** * Invoke the given BeanDefinitionRegistryPostProcessor beans. */ private static void invokeBeanDefinitionRegistryPostProcessors( Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanDefinitionRegistry(registry); } } /** * Invoke the given BeanFactoryPostProcessor beans. */ private static void invokeBeanFactoryPostProcessors( Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); } }
8.BeanFactoryPostProcessor 執行的整體流程:
1)ApplicationContext的refresh方法
2)ApplicationContext的invokeBeanFactoryPostProcessors方法
3)PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors
9.BeanFactoryPostProcessor執行的優先順序:
1)首先是實現了PriorityOrdered介面的,排序執行
2)下來是實現了Ordered介面的,排序執行
3)最後是其它(未實現排序介面),順序執行
10.BeanFactoryPostProcessor獲取機制:
1)首先獲取手動註冊ApplicationContext的集合
2)再次是通過beanFactory.getBeanNamesForType查詢所有已註冊的BeanFactory
PostProcessor的bean定義並例項化。
四.總結
1. ApplicationContext擴充套件類可以呼叫AbstractApplicationContext.addBeanFactoryPostProcessor方法,將自定義的BeanFactoryPostProcessor實現類儲存到ApplicationContext中;
2. Spring容器初始化時,上一步中被加入到ApplicationContext的bean會被優先呼叫其postProcessBeanFactory方法;
3. 自定義的BeanFactoryPostProcessor介面實現類,也會被找出來,然後呼叫其postProcessBeanFactory方法;
4. postProcessBeanFactory方法被呼叫時,beanFactory會被作為引數傳入,自定義類中可以使用該引數來處理bean的定義,達到業務需求;
5. 此時的Spring容器還沒有開始例項化bean,因此自定義的BeanFactoryPostProcessor實現類不要做與bean例項有關的操作,而是做一些與bean定義有關的操作,例如修改某些欄位的值,這樣後面例項化的bean的就會有相應的改變;
6.Spring主要將BeanFactoryPostProcessor劃分了兩類:
-
- 正常的BeanFactoryPostProcessor
- BeanDefinitionRegistry型別的BeanDefinitionRegistryPostProcessor
7.在執行流程中可以看到Spring先執行了BeanDefinitionRegistryPostProcessor型別的postProcessBeanDefinitionRegistry方法,再執行BeanDefinitionRegistryPostProcessor和正常BeanFactoryPostProcessor的postProcessBeanFactory方法。
8.Spring對BeanDefinitionRegistryPostProcessor的解釋是:允許在正常的BeanFactoryPostProcessor執行檢測開始之前註冊更多的自定義bean。也就是說BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry可以在後置處理器執行前自定義註冊更多的BeanDefinition。
例如:Spring實現的ConfigurationClassPostProcessor用於註冊註解@Configuration標識的類裡面定義的BeanDefinition。