上接Spring提供的BeanPostProcessor的擴展點-1繼續分析。java
4、BeanPostProcessor接口及回調方法圖
從圖中咱們能夠看出一共五個接口,共十個回調方法,即十個擴展點,但咱們以前的文章只分析了其中八個,另外兩個稍候也會解析一下是幹什麼的。spring
===================================================================緩存
===================================================================異步
5、五個接口十個擴展點解析
1、InstantiationAwareBeanPostProcessor:實例化Bean後置處理器(繼承BeanPostProcessor)post
postProcessBeforeInstantiation :在實例化目標對象以前執行,能夠自定義實例化邏輯,如返回一個代理對象等,(3.1處執行;若是此處返回的Bean不爲null將中斷後續Spring建立Bean的流程,且只執行postProcessAfterInitialization回調方法,如當AbstractAutoProxyCreator的實現者註冊了TargetSourceCreator(建立自定義的TargetSource)將改變執行流程,不註冊TargetSourceCreator咱們默認使用的是SingletonTargetSource(即AOP代理直接保證目標對象),此處咱們還可使用如ThreadLocalTargetSource(線程綁定的Bean)、CommonsPoolTargetSource(實例池的Bean)等等,你們能夠去spring官方文檔瞭解TargetSource詳情;學習
postProcessAfterInitialization : Bean實例化完畢後執行的後處理操做,全部初始化邏輯、裝配邏輯以前執行,若是返回false將阻止其餘的InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation的執行,(3.2和(9.1處執行;在此處能夠執行一些初始化邏輯或依賴裝配邏輯;ui
postProcessPropertyValues :完成其餘定製的一些依賴注入和依賴檢查等,如AutowiredAnnotationBeanPostProcessor執行@Autowired註解注入,CommonAnnotationBeanPostProcessor執行@Resource 等註解的注入,PersistenceAnnotationBeanPostProcessor執行@ PersistenceContext等JPA註解的注入,RequiredAnnotationBeanPostProcessor執行@ Required註解的檢查等等,(9.3處執行;this
2、MergedBeanDefinitionPostProcessor:合併Bean定義後置處理器 (繼承BeanPostProcessor)spa
postProcessMergedBeanDefinition:執行Bean定義的合併,在(7.1處執行,且在實例化完Bean以後執行;.net
3、SmartInstantiationAwareBeanPostProcessor:智能實例化Bean後置處理器(繼承InstantiationAwareBeanPostProcessor)
predictBeanType:預測Bean的類型,返回第一個預測成功的Class類型,若是不能預測返回null;當你調用BeanFactory.getType(name)時當經過Bean定義沒法獲得Bean類型信息時就調用該回調方法來決定類型信息;BeanFactory.isTypeMatch(name, targetType)用於檢測給定名字的Bean是否匹配目標類型(如在依賴注入時須要使用);
determineCandidateConstructors:檢測Bean的構造器,能夠檢測出多個候選構造器,再有相應的策略決定使用哪個,如AutowiredAnnotationBeanPostProcessor實現將自動掃描經過@Autowired/@Value 註解的構造器從而能夠完成構造器注入,請參考【第十二章】零配置 之12.2 註解實現Bean依賴注入 ——跟我學spring3 ,(6.2.2.1處執行;
getEarlyBeanReference:當正在建立A時,A依賴B,此時經過(8將A做爲ObjectFactory放入單例工廠中進行early expose,此處B須要引用A,但A正在建立,從單例工廠拿到ObjectFactory(其經過getEarlyBeanReference獲取及早暴露Bean),從而容許循環依賴,此時AspectJAwareAdvisorAutoProxyCreator(完成xml風格的AOP配置(<aop:config>)將目標對象(A)包裝到AOP代理對象)或AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj註解風格(<aop:aspectj-autoproxy> @Aspect)將目標對象(A)包裝到AOP代理對象),其返回值將替代原始的Bean對象,即此時經過early reference能獲得正確的代理對象,(8.1處實施;若是此處執行了,(10.3.3處的AspectJAwareAdvisorAutoProxyCreator或AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization將不執行,即這兩個回調方法是二選一的;
4、BeanPostProcessor:Bean後置處理器
postProcessBeforeInitialization:實例化、依賴注入完畢,在調用顯示的初始化以前完成一些定製的初始化任務,如BeanValidationPostProcessor完成JSR-303 @Valid註解Bean驗證,InitDestroyAnnotationBeanPostProcessor完成@PostConstruct註解的初始化方法調用,ApplicationContextAwareProcessor完成一些Aware接口的注入(如EnvironmentAware、ResourceLoaderAware、ApplicationContextAware),其返回值將替代原始的Bean對象;(10.2處執行;
postProcessAfterInitialization:實例化、依賴注入、初始化完畢時執行,如AspectJAwareAdvisorAutoProxyCreator(完成xml風格的AOP配置(<aop:config>)的目標對象包裝到AOP代理對象)、AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj註解風格(<aop:aspectj-autoproxy> @Aspect)的AOP配置的目標對象包裝到AOP代理對象),其返回值將替代原始的Bean對象;(10.3.3處執行;此處須要參考getEarlyBeanReference;
5、DestructionAwareBeanPostProcessor:銷燬Bean後置處理器(繼承BeanPostProcessor)
postProcessBeforeDestruction:銷燬後處理回調方法,該回調只能應用到單例Bean,如InitDestroyAnnotationBeanPostProcessor完成@PreDestroy註解的銷燬方法調用;(12.1.1處執行。
===================================================================
===================================================================
6、內置的一些BeanPostProcessor
部份內置的BeanPostProcessor
此圖只有內置的一部分。
一、ApplicationContextAwareProcessor
容器啓動時會自動註冊。注入那些實現ApplicationContextAware、MessageSourceAware、ResourceLoaderAware、EnvironmentAware、
EmbeddedValueResolverAware、ApplicationEventPublisherAware標識接口的Bean須要的相應實例,在postProcessBeforeInitialization回調方法中進行實施,即(10.2處實施。
2、CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor繼承InitDestroyAnnotationBeanPostProcessor,當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊。
提供對JSR-250規範註解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
2.1、經過@Resource註解進行依賴注入:
postProcessPropertyValues:經過此回調進行@Resource註解的依賴注入;(9.3處實施;
2.2、用於執行@PostConstruct 和@PreDestroy 註解的初始化和銷燬方法的擴展點:
postProcessBeforeInitialization()將會調用bean的@PostConstruct方法;(10.2處實施;
postProcessBeforeDestruction()將會調用單例 Bean的@PreDestroy方法(此回調方法會在容器銷燬時調用),(12.1.1處實施。
詳見【第十二章】零配置 之 12.2 註解實現Bean依賴注入 ——跟我學spring3,JSR-250註解部分。
3、AutowiredAnnotationBeanPostProcessor
當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊。
提供對JSR-330規範註解的支持和Spring自帶註解的支持。
3.1、Spring自帶註解的依賴注入支持,@Autowired和@Value:
determineCandidateConstructors :決定候選構造器;詳見【12.2中的構造器注入】;(6.2.2.1處實施;
postProcessPropertyValues :進行依賴注入;詳見【12.2中的字段注入和方法參數注入】;(9.3處實施;
3.2、對JSR-330規範註解的依賴注入支持,@Inject:
同2.1相似只是查找使用的註解不同;
詳見【第十二章】零配置 之 12.2 註解實現Bean依賴注入 ——跟我學spring3,Spring自帶依賴注入註解和 JSR-330註解部分。
4、RequiredAnnotationBeanPostProcessor
當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊。
4.1、提供對@ Required註解的方法進行依賴檢查支持:
postProcessPropertyValues:若是檢測到沒有進行依賴注入時拋出BeanInitializationException異常;(9.3處實施;
詳見【第十二章】零配置 之 12.2 註解實現Bean依賴注入 ——跟我學spring3,@Required:依賴檢查。
5、PersistenceAnnotationBeanPostProcessor
當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊。
5.1、經過對JPA @ javax.persistence.PersistenceUnit和@ javax.persistence.PersistenceContext註解進行依賴注入的支持;
postProcessPropertyValues : 根據@PersistenceUnit/@PersistenceContext進行EntityManagerFactory和EntityManager的支持;
6、AbstractAutoProxyCreator
AspectJAwareAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator都是繼承AbstractAutoProxyCreator,AspectJAwareAdvisorAutoProxyCreator提供對(<aop:config>)聲明式AOP的支持,AnnotationAwareAspectJAutoProxyCreator提供對(<aop:aspectj-autoproxy>)註解式(@AspectJ)AOP的支持,所以只須要分析AbstractAutoProxyCreator便可。
當使用<aop:config>配置時自動註冊AspectJAwareAdvisorAutoProxyCreator,而使用<aop:aspectj-autoproxy>時會自動註冊AnnotationAwareAspectJAutoProxyCreator。
6.1、predictBeanType:預測Bean的類型,若是目標對象被AOP代理對象包裝,此處將返回AOP代理對象的類型;
public Class<?> predictBeanType(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); return this.proxyTypes.get(cacheKey); //獲取代理對象類型,可能返回null }
6.2、postProcessBeforeInstantiation:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { //一、獲得一個緩存的惟一key(根據beanClass和beanName生成惟一key) Object cacheKey = getCacheKey(beanClass, beanName); //二、若是當前targetSourcedBeans(經過自定義TargetSourceCreator建立的TargetSource)不包含cacheKey if (!this.targetSourcedBeans.contains(cacheKey)) { //2.一、advisedBeans(已經被加強的Bean,即AOP代理對象)中包含當前cacheKey或nonAdvisedBeans(不該該被加強的Bean)中包含當前cacheKey 返回null,即走Spring默認流程 if (this.advisedBeans.contains(cacheKey) || this.nonAdvisedBeans.contains(cacheKey)) { return null; } //2.二、若是是基礎設施類(如Advisor、Advice、AopInfrastructureBean的實現)不進行處理 //2.二、shouldSkip 默認false,能夠生成子類覆蓋,如AspectJAwareAdvisorAutoProxyCreator覆蓋 (if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) return true; 即若是是本身就跳過) if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.nonAdvisedBeans.add(cacheKey);//在不能加強的Bean列表緩存當前cacheKey return null; } } //三、開始建立AOP代理對象 //3.一、配置自定義的TargetSourceCreator進行TargetSource建立 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { //3.二、若是targetSource不爲null 添加到targetSourcedBeans緩存,並建立AOP代理對象 this.targetSourcedBeans.add(beanName); // specificInterceptors即加強(包括前置加強、後置加強等等) Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); //3.三、建立代理對象 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); //3.四、將代理類型放入proxyTypes從而容許後續的predictBeanType()調用獲取 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }
從如上代碼能夠看出,當咱們配置TargetSourceCreator進行自定義TargetSource建立時,會建立代理對象並中斷默認Spring建立流程。
6.3、getEarlyBeanReference
//獲取early Bean引用(只有單例Bean才能回調該方法) public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { Object cacheKey = getCacheKey(bean.getClass(), beanName); //一、將cacheKey添加到earlyProxyReferences緩存,從而避免屢次重複建立 this.earlyProxyReferences.add(cacheKey); //二、包裝目標對象到AOP代理對象(若是須要) return wrapIfNecessary(bean, beanName, cacheKey); }
6.4、postProcessAfterInitialization
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); //一、若是以前調用過getEarlyBeanReference獲取包裝目標對象到AOP代理對象(若是須要),則再也不執行 if (!this.earlyProxyReferences.contains(cacheKey)) { //二、包裝目標對象到AOP代理對象(若是須要) return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (this.targetSourcedBeans.contains(beanName)) {//經過TargetSourceCreator進行自定義TargetSource不須要包裝 return bean; } if (this.nonAdvisedBeans.contains(cacheKey)) {//不該該被加強對象不須要包裝 return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {//基礎設施/應該skip的不須要保證 this.nonAdvisedBeans.add(cacheKey); return bean; } // 若是有加強就執行包裝目標對象到代理對象 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.add(cacheKey);//將cacheKey添加到已經被加強列表,防止屢次加強 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//建立代理對象 this.proxyTypes.put(cacheKey, proxy.getClass());//緩存代理類型 return proxy; } this.nonAdvisedBeans.add(cacheKey); return bean; }
從如上流程能夠看出 getEarlyBeanReference和postProcessAfterInitialization是兩者選一的,並且單例Bean目標對象只能被加強一次,而原型Bean目標對象可能被包裝屢次。
7、BeanValidationPostProcessor
默認不自動註冊,Spring3.0開始支持。
提供對JSR-303驗證規範支持。
根據afterInitialization是false/true決定調用postProcessBeforeInitialization或postProcessAfterInitialization來經過JSR-303規範驗證Bean,默認false。
8、MethodValidationPostProcessor
Spring3.1開始支持,且只支持Hibernate Validator 4.2及更高版本,從Spring 3.2起可能將採起自動檢測Bean Validation 1.1兼容的提供商且自動註冊(Bean Validation 1.1 (JSR-349)正處於草案階段,它將提供方法級別的驗證,提供對方法級別的驗證),目前默認不自動註冊。
Bean Validation 1.1草案請參考http://jcp.org/en/jsr/detail?id=349 http://beanvalidation.org/。
提供對方法參數/方法返回值的進行驗證(即前置條件/後置條件的支持),經過JSR-303註解驗證,使用方式如:
public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)
默認只對@org.springframework.validation.annotation.Validated註解的Bean進行驗證,咱們能夠修改validatedAnnotationType爲其餘註解類型來支持其餘註解驗證。並且目前只支持Hibernate Validator實現,在將來版本可能支持其餘實現。
有了這東西以後咱們就不須要在進行如Assert.assertNotNull()這種前置條件/後置條件的判斷了。
9、ScheduledAnnotationBeanPostProcessor
當配置文件中有<task:annotation-driven>自動註冊或@EnableScheduling自動註冊。
提供對註解@Scheduled任務調度的支持。
postProcessAfterInitialization:經過查找Bean對象類上的@Scheduled註解來建立ScheduledMethodRunnable對象並註冊任務調度方法(僅返回值爲void且方法是無形式參數的才能夠)。
可參考Spring官方文檔的任務調度章節學習@Scheduled註解任務調度。
10、AsyncAnnotationBeanPostProcessor
當配置文件中有<task:annotation-driven>自動註冊或@EnableAsync自動註冊。
提供對@ Async和EJB3.1的@javax.ejb.Asynchronous註解的異步調用支持。
postProcessAfterInitialization:經過ProxyFactory建立目標對象的代理對象,默認使用AsyncAnnotationAdvisor(內部使用AsyncExecutionInterceptor 經過AsyncTaskExecutor(繼承TaskExecutor)經過submit提交異步任務)。
可參考Spring官方文檔的異步調用章節學習@Async註解異步調用。
11、ServletContextAwareProcessor
在使用Web容器時自動註冊。
相似於ApplicationContextAwareProcessor,當你的Bean 實現了ServletContextAware/ ServletConfigAware會自動調用回調方法注入ServletContext/ ServletConfig。
===================================================================
===================================================================
7、BeanPostProcessor如何註冊
1、如ApplicationContextAwareProcessor會在ApplicationContext容器啓動時自動註冊,而CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor會在當你使用<context:annotation-config>或<context:component-scan>配置時自動註冊。
2、只要將BeanPostProcessor註冊到容器中,Spring會在啓動時自動獲取並註冊。
===================================================================
===================================================================
8、BeanPostProcessor的執行順序
1、若是使用BeanFactory實現,非ApplicationContext實現,BeanPostProcessor執行順序就是添加順序。
2、若是使用的是AbstractApplicationContext(實現了ApplicationContext)的實現,則經過以下規則指定順序。
2.1、PriorityOrdered(繼承了Ordered),實現了該接口的BeanPostProcessor會在第一個順序註冊,標識高優先級順序,即比實現Ordered的具備更高的優先級;
2.2、Ordered,實現了該接口的BeanPostProcessor會第二個順序註冊;
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;//最高優先級
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;//最低優先級
即數字越小優先級越高,數字越大優先級越低,如0(高優先級)——1000(低優先級)
2.3、無序的,沒有實現Ordered/ PriorityOrdered的會在第三個順序註冊;
2.4、內部Bean後處理器,實現了MergedBeanDefinitionPostProcessor接口的是內部Bean PostProcessor,將在最後且無序註冊。
3、接下來咱們看看內置的BeanPostProcessor執行順序
//1註冊實現了PriorityOrdered接口的BeanPostProcessor
//2註冊實現了Ordered接口的BeanPostProcessor
AbstractAutoProxyCreator 實現了Ordered,order = Ordered.LOWEST_PRECEDENCE
MethodValidationPostProcessor 實現了Ordered,LOWEST_PRECEDENCE
ScheduledAnnotationBeanPostProcessor 實現了Ordered,LOWEST_PRECEDENCE
AsyncAnnotationBeanPostProcessor 實現了Ordered,order = Ordered.LOWEST_PRECEDENCE
//3註冊無實現任何接口的BeanPostProcessor
BeanValidationPostProcessor 無序
ApplicationContextAwareProcessor 無序
ServletContextAwareProcessor 無序
//3 註冊實現了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor,且按照實現了Ordered的順序進行註冊,沒有實現Ordered的默認爲Ordered.LOWEST_PRECEDENCE。
PersistenceAnnotationBeanPostProcessor 實現了PriorityOrdered,Ordered.LOWEST_PRECEDENCE - 4
AutowiredAnnotationBeanPostProcessor 實現了PriorityOrdered,order = Ordered.LOWEST_PRECEDENCE - 2
RequiredAnnotationBeanPostProcessor 實現了PriorityOrdered,order = Ordered.LOWEST_PRECEDENCE - 1
CommonAnnotationBeanPostProcessor 實現了PriorityOrdered,Ordered.LOWEST_PRECEDENCE
從上到下順序執行,若是order相同則咱們應該認爲同序(誰先執行不肯定,其執行順序根據註冊順序決定)。
===================================================================
===================================================================
9、完成Spring事務處理時自我調用的解決方案及一些實現方式的分析分析
場景請先參考請參考Spring事務處理時自我調用的解決方案及一些實現方式的風險中的3.3、經過BeanPostProcessor 在目標對象中注入代理對象。
分析:
問題出如今5和9處:
5、使用步驟1處註冊的SingletonFactory(ObjectFactory.getObject() 使用AnnotationAwareAspectJAutoProxyCreator的getEarlyBeanReference獲取循環引用Bean),所以此處將返回A目標對象的代理對象;
9、此處調用AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization,但發現以前調用過AnnotationAwareAspectJAutoProxyCreator的getEarlyBeanReference獲取代理對象,此處再也不建立代理對象,而是直接返回目標對象,所以使用InjectBeanSelfProcessor不能注入代理對象;但此時的Spring容器中的A已是代理對象了,所以我使用了從上下文從新獲取A代理對象的方式注入(context.getBean(beanName))。
此處的getEarlyBeanReference和postProcessAfterInitialization爲何是兩者選一的請參考以前介紹的AbstractAutoProxyCreator。
到此問題咱們分析完畢,實際項目中的循環依賴應該儘可能避免,這違反了「無環依賴原則」。
下一篇我將介紹一些內置BeanPostProcessor的使用和自定義一些本身的BeanPostProcessor來更好的理解這些擴展點。