Spring開閉原則的表現-BeanPostProcessor擴展點-2

 

 

上接Spring提供的BeanPostProcessor的擴展點-1繼續分析。java

 


4、BeanPostProcessor接口及回調方法圖


 從圖中咱們能夠看出一共五個接口,共十個回調方法,即十個擴展點,但咱們以前的文章只分析了其中八個,另外兩個稍候也會解析一下是幹什麼的。spring

 

===================================================================緩存

===================================================================異步

5、五個接口十個擴展點解析

1InstantiationAwareBeanPostProcessor:實例化Bean後置處理器(繼承BeanPostProcessorpost

postProcessBeforeInstantiation :在實例化目標對象以前執行,能夠自定義實例化邏輯,如返回一個代理對象等,3.1處執行;若是此處返回的Bean不爲null將中斷後續Spring建立Bean的流程,且只執行postProcessAfterInitialization回調方法,如當AbstractAutoProxyCreator的實現者註冊了TargetSourceCreator(建立自定義的TargetSource)將改變執行流程,不註冊TargetSourceCreator咱們默認使用的是SingletonTargetSource(即AOP代理直接保證目標對象),此處咱們還可使用如ThreadLocalTargetSource(線程綁定的Bean)、CommonsPoolTargetSource(實例池的Bean)等等,你們能夠去spring官方文檔瞭解TargetSource詳情;學習

postProcessAfterInitialization : Bean實例化完畢後執行的後處理操做,全部初始化邏輯、裝配邏輯以前執行,若是返回false將阻止其餘的InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation的執行,(3.2和(9.1處執行;在此處能夠執行一些初始化邏輯或依賴裝配邏輯;ui

postProcessPropertyValues :完成其餘定製的一些依賴注入和依賴檢查等,如AutowiredAnnotationBeanPostProcessor執行@Autowired註解注入,CommonAnnotationBeanPostProcessor執行@Resource 等註解的注入,PersistenceAnnotationBeanPostProcessor執行@ PersistenceContextJPA註解的注入,RequiredAnnotationBeanPostProcessor執行@ Required註解的檢查等等,9.3處執行;this

 

2MergedBeanDefinitionPostProcessor:合併Bean定義後置處理器         (繼承BeanPostProcessorspa

postProcessMergedBeanDefinition:執行Bean定義的合併,在7.1處執行,且在實例化完Bean以後執行;.net

 

3SmartInstantiationAwareBeanPostProcessor:智能實例化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,此時經過(8A做爲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處的AspectJAwareAdvisorAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization將不執行,即這兩個回調方法是二選一的;

 

4BeanPostProcessorBean後置處理器

postProcessBeforeInitialization:實例化、依賴注入完畢,在調用顯示的初始化以前完成一些定製的初始化任務,如BeanValidationPostProcessor完成JSR-303 @Valid註解Bean驗證,InitDestroyAnnotationBeanPostProcessor完成@PostConstruct註解的初始化方法調用,ApplicationContextAwareProcessor完成一些Aware接口的注入(如EnvironmentAwareResourceLoaderAwareApplicationContextAware),其返回值將替代原始的Bean對象;10.2處執行;

postProcessAfterInitialization:實例化、依賴注入、初始化完畢時執行,如AspectJAwareAdvisorAutoProxyCreator(完成xml風格的AOP配置(<aop:config>)的目標對象包裝到AOP代理對象)、AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj註解風格(<aop:aspectj-autoproxy> @Aspect)的AOP配置的目標對象包裝到AOP代理對象),其返回值將替代原始的Bean對象;10.3.3處執行;此處須要參考getEarlyBeanReference

 

5DestructionAwareBeanPostProcessor:銷燬Bean後置處理器(繼承BeanPostProcessor

postProcessBeforeDestruction:銷燬後處理回調方法,該回調只能應用到單例Bean,如InitDestroyAnnotationBeanPostProcessor完成@PreDestroy註解的銷燬方法調用;12.1.1處執行。

 

===================================================================

===================================================================

6、內置的一些BeanPostProcessor


 部份內置的BeanPostProcessor

此圖只有內置的一部分。

 

一、ApplicationContextAwareProcessor

容器啓動時會自動註冊。注入那些實現ApplicationContextAwareMessageSourceAwareResourceLoaderAwareEnvironmentAware

EmbeddedValueResolverAwareApplicationEventPublisherAware標識接口的Bean須要的相應實例,在postProcessBeforeInitialization回調方法中進行實施,即10.2處實施。

 

2CommonAnnotationBeanPostProcessor

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依賴注入 ——跟我學spring3JSR-250註解部分。


3AutowiredAnnotationBeanPostProcessor

當在配置文件有<context:annotation-config><context:component-scan>會自動註冊。

 

提供對JSR-330規範註解的支持和Spring自帶註解的支持。

 

3.1Spring自帶註解的依賴注入支持,@Autowired@Value

    determineCandidateConstructors :決定候選構造器;詳見【12.2中的構造器注入】;6.2.2.1處實施;

postProcessPropertyValues :進行依賴注入;詳見【12.2中的字段注入和方法參數注入】;9.3處實施;

3.2、對JSR-330規範註解的依賴注入支持,@Inject

    2.1相似只是查找使用的註解不同;

 

詳見【第十二章】零配置 之 12.2 註解實現Bean依賴注入 ——跟我學spring3Spring自帶依賴注入註解和 JSR-330註解部分。


4RequiredAnnotationBeanPostProcessor

當在配置文件有<context:annotation-config><context:component-scan>會自動註冊。

 

4.1、提供對@ Required註解的方法進行依賴檢查支持:

    postProcessPropertyValues:若是檢測到沒有進行依賴注入時拋出BeanInitializationException異常;9.3處實施;

 

詳見【第十二章】零配置 之 12.2 註解實現Bean依賴注入 ——跟我學spring3@Required:依賴檢查


5PersistenceAnnotationBeanPostProcessor

當在配置文件有<context:annotation-config><context:component-scan>會自動註冊。

 

5.1、經過對JPA @ javax.persistence.PersistenceUnit@ javax.persistence.PersistenceContext註解進行依賴注入的支持;

    postProcessPropertyValues : 根據@PersistenceUnit/@PersistenceContext進行EntityManagerFactoryEntityManager的支持;


6AbstractAutoProxyCreator

AspectJAwareAdvisorAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator都是繼承AbstractAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator提供對(<aop:config>)聲明式AOP的支持,AnnotationAwareAspectJAutoProxyCreator提供對(<aop:aspectj-autoproxy>)註解式(@AspectJAOP的支持,所以只須要分析AbstractAutoProxyCreator便可。

 

當使用<aop:config>配置時自動註冊AspectJAwareAdvisorAutoProxyCreator,而使用<aop:aspectj-autoproxy>時會自動註冊AnnotationAwareAspectJAutoProxyCreator

 

6.1predictBeanType:預測Bean的類型,若是目標對象被AOP代理對象包裝,此處將返回AOP代理對象的類型;

public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);
		return this.proxyTypes.get(cacheKey); //獲取代理對象類型,可能返回null
}

6.2postProcessBeforeInstantiation

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.3getEarlyBeanReference

//獲取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.4postProcessAfterInitialization

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;
}
  

從如上流程能夠看出 getEarlyBeanReferencepostProcessAfterInitialization是兩者選一的,並且單例Bean目標對象只能被加強一次,而原型Bean目標對象可能被包裝屢次。

 

7BeanValidationPostProcessor

默認不自動註冊,Spring3.0開始支持。

 

提供對JSR-303驗證規範支持。

 

根據afterInitializationfalse/true決定調用postProcessBeforeInitializationpostProcessAfterInitialization來經過JSR-303規範驗證Bean,默認false


8MethodValidationPostProcessor

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()這種前置條件/後置條件的判斷了。


9ScheduledAnnotationBeanPostProcessor

當配置文件中有<task:annotation-driven>自動註冊或@EnableScheduling自動註冊。

 

提供對註解@Scheduled任務調度的支持。

 

postProcessAfterInitialization:經過查找Bean對象類上的@Scheduled註解來建立ScheduledMethodRunnable對象並註冊任務調度方法(僅返回值爲void且方法是無形式參數的才能夠)。

 

可參考Spring官方文檔的任務調度章節學習@Scheduled註解任務調度。


10AsyncAnnotationBeanPostProcessor

當配置文件中有<task:annotation-driven>自動註冊或@EnableAsync自動註冊。

 

提供對@ AsyncEJB3.1@javax.ejb.Asynchronous註解的異步調用支持。

 

postProcessAfterInitialization:經過ProxyFactory建立目標對象的代理對象,默認使用AsyncAnnotationAdvisor(內部使用AsyncExecutionInterceptor 經過AsyncTaskExecutor(繼承TaskExecutor)經過submit提交異步任務)。

 

可參考Spring官方文檔的異步調用章節學習@Async註解異步調用。


11ServletContextAwareProcessor

在使用Web容器時自動註冊。

 

相似於ApplicationContextAwareProcessor,當你的Bean 實現了ServletContextAware/ ServletConfigAware會自動調用回調方法注入ServletContext/ ServletConfig

 

===================================================================

===================================================================

7、BeanPostProcessor如何註冊

1、如ApplicationContextAwareProcessor會在ApplicationContext容器啓動時自動註冊,而CommonAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessor會在當你使用<context:annotation-config><context:component-scan>配置時自動註冊。

2、只要將BeanPostProcessor註冊到容器中,Spring會在啓動時自動獲取並註冊。

 

===================================================================

===================================================================

8、BeanPostProcessor的執行順序

1、若是使用BeanFactory實現,非ApplicationContext實現,BeanPostProcessor執行順序就是添加順序。

 

2、若是使用的是AbstractApplicationContext(實現了ApplicationContext)的實現,則經過以下規則指定順序。

2.1PriorityOrdered(繼承了Ordered),實現了該接口的BeanPostProcessor會在第一個順序註冊,標識高優先級順序,即比實現Ordered的具備更高的優先級;

2.2Ordered,實現了該接口的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              實現了Orderedorder = Ordered.LOWEST_PRECEDENCE

MethodValidationPostProcessor          實現了OrderedLOWEST_PRECEDENCE

ScheduledAnnotationBeanPostProcessor   實現了OrderedLOWEST_PRECEDENCE

AsyncAnnotationBeanPostProcessor      實現了Orderedorder = Ordered.LOWEST_PRECEDENCE

 

//3註冊無實現任何接口的BeanPostProcessor

BeanValidationPostProcessor            無序

ApplicationContextAwareProcessor       無序

ServletContextAwareProcessor          無序

 

//3 註冊實現了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor,且按照實現了Ordered的順序進行註冊,沒有實現Ordered的默認爲Ordered.LOWEST_PRECEDENCE

PersistenceAnnotationBeanPostProcessor  實現了PriorityOrderedOrdered.LOWEST_PRECEDENCE - 4

AutowiredAnnotationBeanPostProcessor   實現了PriorityOrderedorder = Ordered.LOWEST_PRECEDENCE - 2

RequiredAnnotationBeanPostProcessor    實現了PriorityOrderedorder = Ordered.LOWEST_PRECEDENCE - 1

CommonAnnotationBeanPostProcessor    實現了PriorityOrderedOrdered.LOWEST_PRECEDENCE

 

從上到下順序執行,若是order相同則咱們應該認爲同序(誰先執行不肯定,其執行順序根據註冊順序決定)。

 

===================================================================

===================================================================

9、完成Spring事務處理時自我調用的解決方案及一些實現方式的分析分析

場景請先參考請參考Spring事務處理時自我調用的解決方案及一些實現方式的風險中的3.3、經過BeanPostProcessor 在目標對象中注入代理對象。

 

 

分析:


 

 

問題出如今59處:

 

5、使用步驟1處註冊的SingletonFactoryObjectFactory.getObject() 使用AnnotationAwareAspectJAutoProxyCreatorgetEarlyBeanReference獲取循環引用Bean),所以此處將返回A目標對象的代理對象;

 

9、此處調用AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization,但發現以前調用過AnnotationAwareAspectJAutoProxyCreatorgetEarlyBeanReference獲取代理對象,此處再也不建立代理對象,而是直接返回目標對象,所以使用InjectBeanSelfProcessor不能注入代理對象;但此時的Spring容器中的A已是代理對象了,所以我使用了從上下文從新獲取A代理對象的方式注入(context.getBean(beanName))。

 

此處的getEarlyBeanReferencepostProcessAfterInitialization爲何是兩者選一的請參考以前介紹的AbstractAutoProxyCreator

 

到此問題咱們分析完畢,實際項目中的循環依賴應該儘可能避免,這違反了「無環依賴原則」。

 

 

 

下一篇我將介紹一些內置BeanPostProcessor的使用和自定義一些本身的BeanPostProcessor來更好的理解這些擴展點。

相關文章
相關標籤/搜索