摘要:
Spring
的代理在上層中主要分為ProxyCreatorSupport
和ProxyProcessorSupport
,前者是基於代理工廠,后者是基於后置處理器,也可以認為后置就是自動代理器。當spring
容器中需要進行aop
進行織入的bean
較多時,簡單采用ProxyFacotryBean
無疑會增加很多工作量(因為每個Bean
!都得手動寫一個)。所以自動代理就發揮它的作用了。
Spring中自動創建代理器分類
在內部,Spring使用BeanPostProcessor
讓自動生成代理。基於BeanPostProcessor的自動代理創建器的實現類,將根據一些規則在容器實例化Bean
時為匹配的Bean生成代理實例。代理創建器可以分為三類:
- 基於Bean配置名規則的自動代理生成器:允許為一組特定配置名的Bean自動創建代理實例的代理創建器,實現類為
BeanNameAutoProxyCreator
- 基於
Advisor
匹配機制的自動代理創建器它會對容器中的所有Advisor進行掃描,自動將這些切面應用到匹配的Bean中,實現類是DefaultAdvisorAutoProxyCreator
(它也支持前綴匹配) - 基於Bean中
AspectJ
注解的自動代理生成器:為包含AspectJ注解的切入的Bean自動創建代理實例,實現類是AnnotationAwareAspectJAutoProxyCreator
,它是我們的@EnableAspectJAutoProxy
導入的,這也是我們當下使用最為廣泛的方式~
BeanNameAutoProxyCreator
package com.github.dqqzj.springboot.aop;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author qinzhongjian
* @date created in 2019-08-25 09:43
* @description: TODO
* @since JDK 1.8.0_212-b10
*/
@Component
public class MyBeanNameAutoProxyCreator extends BeanNameAutoProxyCreator {
@PostConstruct
public void init() {
super.setBeanNames("aopService", "abstractAutoProxyCreatorService");
super.setInterceptorNames("myMethodBeforeAdvice");
}
}
如果你想用自己注冊的@Bean
代替@EnableAspectJAutoProxy
默認給你注冊的自動創建器AnnotationAwareAspectJAutoProxyCreator
,那么你可以注冊一個Bean名稱如下的Bean即可:
// 手動注冊一個自動代理創建器,且名字務必叫AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME
@Bean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME)
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
...
}
AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
...
}
AbstractAutoProxyCreator
是對自動代理創建器的一個抽象實現。最重要的是,它實現了SmartInstantiationAwareBeanPostProcessor
接口,因此會介入到Spring IoC
容器Bean實例化的過程,在AbstractAutowireCapableBeanFactory
中有這樣一段代碼
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
但是一般都不會生效的,因為這個resolveBeforeInstantiation
只是針對有自定義的targetsource
,因為自定義的targetsource
不是spring的bean那么肯定不需要進行后續的一系列的實例化 初始化。所以可以在resolveBeforeInstantiation直接進行proxy
。簡單的說吧 ,這個代碼可以忽略不計,開發者一般用不到。
如何讓resolveBeforeInstantiation直接返回bean?
package com.github.dqqzj.springboot.aop;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
/**
* @author qinzhongjian
* @date created in 2019-08-25 11:35
* @description: TODO
* @since JDK 1.8.0_212-b10
*/
public class AopServiceInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass.isInstance(AopService.class)) {
return new AopService();
}
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
這個是spring
第一次后置處理器的使用,如果這樣直接就返回了,就相當於脫離了IOC
的生命周期了一樣,依賴注入,屬性填充等這些都沒有進行處理,所以使用的時候一定要注意,最好別使用這個功能。
在初始化bean的過程中后續還有2個特別重要的后置處理過程,對於循環依賴甚至異步注解事物注解等都有或多或少的影響,后續會繼續分析它們。
小結:
SpringAOP
應盡量避免自己創建AutoProxyCreator
,內部機制及其復雜難免會由於沒有想到的問題而出現其他不常見的問題,上面分享的內容很少,原因是我覺得熟悉這個架構設計師最關鍵的,各種子類的雖然實現大不相同,但是你想全部都記在腦海或者很熟悉那是不太現實的,只有熟悉他的設計才能遇見問題輕易的就能翻源碼解決。