BeanFactoryPostProcessorjava
在前面幾個章節,筆者有介紹過BeanFactoryPostProcessor接口,在spring在解析BeanDefinition以後,根據BeanDefinition初始化bean以前,會回調咱們編寫的BeanFactoryPostProcessor實現類並調用postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,spring會經過這個方法傳入一個ConfigurableListableBeanFactory對象,咱們能夠對這個bean工廠對象新增或修改BeanDefinition。spring初始化bean一個典型的流程,就是根據咱們標記在類上的@Component生成一個BeanDefinition,BeanDefinition中包含這個類的class對象,而後根據class對象生成實例。若是咱們編寫兩個Service:UserService和OrderService,並在類上標註@Component,再編寫一個BeanFactoryPostProcessor接口,在接口中咱們拿到UserService的BeanDefinition,並修改class爲OrderService,那麼咱們從spring容器中獲取userService這個bean,它的類型是UserService呢仍是OrderService呢?來看下面的示例:spring
package org.example.service; import org.springframework.stereotype.Component; @Component public class OrderService { } package org.example.service; import org.springframework.stereotype.Component; @Component public class UserService { }
在Test1BeanFactoryPostProcessor類中,咱們獲取userService的BeanDefinition,並打印它的class對象,這裏應該是UserService,而後咱們再設置BeanDefinition的class爲OrderService安全
Test1BeanFactoryPostProcessor.javabash
package org.example.service; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.ScannedGenericBeanDefinition; import org.springframework.stereotype.Component; @Component public class Test1BeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("userService"); System.out.println("UserService beanDefinition class:" + beanDefinition.getBeanClass()); beanDefinition.setBeanClass(OrderService.class); } }
MyConfig.java多線程
package org.example.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("org.example.service") public class MyConfig { }
測試用例:併發
@Test public void test01() { ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class); System.out.println("userService class:" + ac.getBean("userService").getClass()); }
運行結果:框架
UserService beanDefinition class:class org.example.service.UserService userService class:class org.example.service.OrderService
能夠看到,spring容器會回調咱們編寫的bean工廠後置處理器BeanFactoryPostProcessor實現類Test1BeanFactoryPostProcessor ,在回調方法中,咱們能夠從bean工廠獲取spring容器已經解析的UserService對應的BeanDefinition對象,打印這個BeanDefinition對象的class對象也確實是UserService的class對象,以後咱們修改UserService對應的BeanDefinition的class對象爲OrderService的class對象,以後咱們從spring容器獲取beanName爲userService的bean能夠看到bean的實現類已經被替換成OrderService對象。這也驗證筆者以前所說的一個事實,BeanFactoryPostProcessor的回調時機,是在spring容器將類解析爲BeanDefinition以後,及根據BeanDefinition生成bean以前。固然,這段代碼在實際開發中意義並不大,這裏只是爲了揭露spring的實現。ide
那麼筆者這裏有個疑問,spring是在什麼時候解析BeanDefinition?什麼時候回調BeanFactoryPostProcessor?什麼時候初始化bean?回顧測試用例test01的兩行代碼,咱們能夠肯定,前面的解析、回調、初始化必定是在test01裏兩句代碼的某一句完成的,那麼到底是那一句呢?是建立應用上下文,仍是打印userService對應的class對象呢?函數
爲了定位上面的問題,咱們對UserService和OrderService稍做修改,咱們在兩個類的構造函數中增長打印:post
public class UserService { public UserService() { System.out.println("UserService init..."); } } public class OrderService { public OrderService() { System.out.println("OrderService init..."); } }
測試用例:
@Test public void test02() { ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class); }
運行結果:
UserService beanDefinition class:class org.example.service.UserService OrderService init... OrderService init...
結果打印了兩次OrderService構造函數的內容,一次spring根據OrderService對應的BeanDefinition進行初始化,一次是咱們修改userService對應的BeanDefinition的class爲OrderService,spring根據class進行初始化。而test02只有一行初始化應用上下文的代碼,至此咱們能夠肯定,spring的解析BeanDefinition、回調BeanFactoryPostProcessor、初始化bean都在初始化應用上下文完成。固然,spring的應用上下文實現,有:AnnotationConfigApplication、ContextClassPathXmlApplicationContext……等等,但大部分的應用上下文實現都是在初始化的時候完成解析BeanDefinition、回調BeanFactoryPostProcessor、初始化bean這三步。
咱們在調用應用上下文的構造函數AnnotationConfigApplicationContext(Class<?>... componentClasses)時,這個函數內部會先調用默認的無參構造方法,初始化reader和scanner兩個對象。調用完默認構造方法後,接着調用register(Class<?>... componentClasses)將咱們的配置類註冊進reader,這一步就會根據配置類生成BeanDefinition並註冊進spring容器,以後調用繼承自父類AbstractApplicationContext的refresh()方法。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner; public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); this.reader.register(componentClasses); } public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); register(componentClasses); refresh(); } …… }
因而咱們進入到AbstractApplicationContext的refresh()方法,這個方法首先在<1>處調用obtainFreshBeanFactory()獲取一個beanFactory對象,在<2>、<3>會把beanFactory做爲參數傳入其餘方法,<2>處咱們單看方法名invokeBeanFactoryPostProcessors能夠知道這裏是調用BeanFactoryPostProcessor接口,咱們以前編寫的BeanFactoryPostProcessor實現類,就是在<2>處進行回調。<3>處單看方法名不太好理解,但若是看註釋就能夠知道,初始化「剩餘且非懶加載」的單例對象,換言之:咱們的dao、service、controller都是在這一層完成bean的初始化以及屬性注入。這裏的「剩餘」頗有意思,當咱們基於spring框架進行開發,大部分的bean都是單例對象,包括咱們以前的配置類(MyConfig)、BeanFactoryPostProcessor在spring容器中都會有對應的BeanDefinition和bean,咱們知道要調用一個類的方法,首先要有那個類的對象,在<2>處的invokeBeanFactoryPostProcessors能夠回調咱們編寫的BeanFactoryPostProcessor實現類,說明在<2>處就已經進行一部分bean的初始化了,這部分bean就包含了BeanFactoryPostProcessor的實現類。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { …… public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { …… // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//<1> …… try { …… // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);//<2> …… // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);//<3> …… } catch (BeansException ex) { …… } finally { …… } } } …… }
咱們總結一下,當咱們調用AnnotationConfigApplicationContext(Class<?>... componentClasses)構造函數時,會先初始化reader和scanner兩個對象,而後將配置類註冊到reader後,再調用refresh()進行BeanDefinition的解析、單例bean的實例化。
如今,咱們來逐行分析AnnotationConfigApplicationContext(Class<?>... componentClasses)這個構造函數,首先這個構造函數會調用默認構造函數,進行reader和scanner的初始化,AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner接受一個BeanDefinitionRegistry接口類型的參數,而AnnotationConfigApplicationContext自己則實現了BeanDefinitionRegistry接口。
public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
從接口名BeanDefinitionRegistry自己咱們能夠知道,這個接口是用來註冊BeanDefinition,而接口所要求的實現,從上至下容許咱們建議beanName和BeanDefinition的映射關係、根據beanName移除BeanDefinition,根據beanName獲取BeanDefinition、獲取全部BeanDefinition對應的beanName,獲取BeanDefinition的數量,判斷beanName是否已被使用。BeanDefinition之於beanName就如bean之於beanName同樣,一個BeanDefinition至少有一個beanName,同理一個bean至少有一個beanName,由於BeanDefinition和bean均可以有別名。
public interface BeanDefinitionRegistry extends AliasRegistry { void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; boolean containsBeanDefinition(String beanName); String[] getBeanDefinitionNames(); int getBeanDefinitionCount(); boolean isBeanNameInUse(String beanName); }
AnnotatedBeanDefinitionReader之因此要傳入一個BeanDefinitionRegistry進行初始化,是由於在初始化AnnotatedBeanDefinitionReader對象時會把一些基礎BeanDefinition註冊到BeanDefinitionRegistry,由於AnnotationConfigApplicationContext這個類自己就實現了BeanDefinitionRegistry接口,因此AnnotatedBeanDefinitionReader會把BeanDefinition註冊到AnnotationConfigApplicationContext,spring容器能夠根據這些基礎的BeanDefinition初始化一些基礎組件,這些組件在spring容器一樣做爲bean對象而存在,這些基礎組件有的能夠根據咱們給定的類路徑將咱們的類解析爲BeanDefinition,有的能夠根據@Autowired、@Inject、@Resource註解注入一個bean所依賴的bean。
當把一個BeanDefinitionRegistry對象傳給AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry)構造函數建立reader對象時,在下面代碼<1>處對象會用字段registry指向傳入的BeanDefinitionRegistry對象,方便後續向BeanDefinitionRegistry對象註冊BeanDefinition。
public class AnnotatedBeanDefinitionReader { …… public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { this(registry, getOrCreateEnvironment(registry)); } public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry;//<1> this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } …… }
以後會執行AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source)方法,這個方法就是先前說的會註冊多個基礎BeanDefinition到BeanDefinitionRegistry,能夠看到這裏會調用registerPostProcessor方法在BeanDefinitionRegistry創建beanName和BeanDefinition的映射。
public abstract class AnnotationConfigUtils { …… public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); …… Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);//<1> def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));//<2> } if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);//<3> def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));//<4> } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);//<5> def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));//<6> } // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. 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)); } 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)); } 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; } private static BeanDefinitionHolder registerPostProcessor( BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) { definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(beanName, definition);//<7> return new BeanDefinitionHolder(definition, beanName); } …… }
上面的registry是咱們以前建立的AnnotationConfigApplicationContext對象,若是咱們查看AnnotationConfigApplicationContext的registerBeanDefinition方法,會發現這個方法是繼承父類GenericApplicationContext,而GenericApplicationContext又是使用代理模式,將registerBeanDefinition方法的工做交由一樣實現了BeanDefinitionRegistry接口的DefaultListableBeanFactory類來完成。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; …… public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } …… @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { this.beanFactory.registerBeanDefinition(beanName, beanDefinition); } …… }
下面,咱們再來看看DefaultListableBeanFactory的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { /** Whether to allow re-registration of a different definition with the same name. */ private boolean allowBeanDefinitionOverriding = true; /** Map of bean definition objects, keyed by bean name. */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); /** List of bean definition names, in registration order. */ private volatile List<String> beanDefinitionNames = new ArrayList<>(256); /** Map from bean name to merged RootBeanDefinition. */ private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); /** Names of beans that have already been created at least once. */ private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); …… public boolean isAllowBeanDefinitionOverriding() { return this.allowBeanDefinitionOverriding; } @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");//<1> …… BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) {//<2> if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } …… this.beanDefinitionMap.put(beanName, beanDefinition);//<3> } else {//<4> if (hasBeanCreationStarted()) {//<5> // 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 {//<6> // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } …… } protected boolean hasBeanCreationStarted() { return !this.alreadyCreated.isEmpty(); } protected void markBeanAsCreated(String beanName) {//<7> if (!this.alreadyCreated.contains(beanName)) { synchronized (this.mergedBeanDefinitions) { if (!this.alreadyCreated.contains(beanName)) { // Let the bean definition get re-merged now that we're actually creating // the bean... just in case some of its metadata changed in the meantime. clearMergedBeanDefinition(beanName); this.alreadyCreated.add(beanName); } } } } …… }
如今,咱們來總結下,在咱們用AnnotationConfigApplicationContext(Class<?>... componentClasses)建立ApplicationContext對象時,AnnotationConfigApplicationContext會先調用默認無參構造方法,在無參構造方法中進行AnnotatedBeanDefinitionReader的初始化,AnnotatedBeanDefinitionReader的構造參數須要傳入一個BeanDefinitionRegistry的實現,BeanDefinitionRegistry是用來註冊一些基礎的beanDefinition,而AnnotationConfigApplicationContext類實現了BeanDefinitionRegistry接口,將自身對象做爲參數傳入到AnnotatedBeanDefinitionReader的構造函數初始化reader對象。在建立AnnotatedBeanDefinitionReader對象的時候,會把ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor這些類構形成RootBeanDefinition並註冊到BeanDefinitionRegistry。
然而,AnnotationConfigApplicationContext也並非在自身完成beanName和BeanDefinition的映射關係,而是其父類GenericApplicationContext使用了代理模式在內部生成一個DefaultListableBeanFactory類型的引用,藉助DefaultListableBeanFactory來完成beanName和BeanDefinition的映射創建。DefaultListableBeanFactory在註冊beanName和BeanDefinition的時候,會先判斷beanName和BeanDefinition是否爲空,爲空就要報錯,若是都不爲空,再判斷beanName在DefaultListableBeanFactory中是否已存在對應的BeanDefinition,若是存在再判斷是否容許重載?默認是容許重載。若是已存在,且容許重載,則從新在DefaultListableBeanFactory的beanDefinitionMap創建映射,若是已存在卻不容許重載,則拋出異常。
若是beanName在註冊時不存在已對應的BeanDefinition,那就要分兩步判斷了,一種是spring容器已存在bean,另外一種是還不存在bean,首先在AnnotatedBeanDefinitionReader內部註冊RootBeanDefinition的時候,走的是不存在bean的分支,也就是簡單的把beanName和BeanDefinition存到beanDefinitionMap,beanName加入到beanDefinitionNames集合。
若是是spring中已存在bean的狀況,爲了防止多線程進行BeanDefinition的註冊,spring對beanDefinitionMap加上同步鎖,在同步代碼塊中保存beanName和BeanDefinition在beanDefinitionMap上的映射,將beanName加入到beanDefinitionNames。
GenericApplicationContext實現了BeanDefinitionRegistry接口,GenericApplicationContext類中存在一個名爲beanFactory的字段,類型是DefaultListableBeanFactory,在調用GenericApplicationContext實現自BeanDefinitionRegistry的方法,會轉而調用DefaultListableBeanFactory對應的方法。
public interface BeanDefinitionRegistry extends AliasRegistry { …… void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; …… BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; …… } public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { …… } public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; …… @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { this.beanFactory.registerBeanDefinition(beanName, beanDefinition); } …… @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { return this.beanFactory.getBeanDefinition(beanName); } …… }
而DefaultListableBeanFactory類自己也實現了BeanDefinitionRegistry,這就是典型的代理模式。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { …… } @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = this.beanDefinitionMap.get(beanName); …… return bd; } }