前言
上一篇已經說過AOP的入口是BeanDefinition。在<aop:aspectj-autoproxy>中,解析的是AopNamespaceHandler類,我們對 AopNamespaceHandler 類進行分析。
AspectJAutoProxyBeanDefinitionParser
我們發現有這樣一段代碼
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
也就是說AspectJAutoProxyBeanDefinitionParser
這個類會去解析<aop:aspectj-autoproxy>標簽,進入到該類中發現它也是BeanDefinitionParser的實現類,而所有BeanDefinitionParser的實現類都是從parse()開始入口的。那么我們接下來看看這個類
【AspectJAutoProxyBeanDefinitionParser】
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注冊AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
//對于注釋中的子類進行解析
extendBeanDefinition(element, parserContext);
return null;
}
其中的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法是實現注冊AnnotationAwareAspectJAutoProxyCreator的地方,也是AOP注冊邏輯的主要邏輯。
【AOPNameSpaceUtils】
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
/**
* 1、注冊或者升級AutoProxyCreator
* 2、定義beanName為org.Springframework.aop.config.internalAutoProxyCreator的
* BeanDefinition
*/
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 對于 proxy-target-class 以及 expose-proxy 屬性的處理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注冊組件并通知,便于監聽器作進一步處理
// 其中 beanDefinition 的 className 為 AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
1、注冊AnnotationAwareAspectJAutoProxyCreator
我們進入到registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法內部
/**
* 1、實現了自動注冊AnnotationAwareAspectJAutoProxyCreator類的功能
* 2、處理優先級問題,如果已經存在了自動代理創建器,且已經存在的自動代理創建器與現在的不一致,
* 那么需要根據優先級來判斷到底需要使用哪個
*/
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
@Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
/**
* 如果已經存在了自動代理的創建器且存在的自動代理創建器與
* 現在的不一致那么需要根據優先級來判斷到底需要使用個
*/
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
//AUTO_PROXY_CREATOR_BEAN_NAME = org.springframework.aop.config.internalAutoProxyCreator
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
//改變bean的ckassName屬性(改變bean最重要的就是改變該屬性)
apcDefinition.setBeanClassName(cls.getName());
}
}
//若已存在的自動代理創建器并且與將要創建的一致,那么無需再創建
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
- 1、該方法主要是實現了自動注冊AnnotationAwareAspectJAutoProxyCreator類的功能,該類是AOP的核心類。
- 2、處理優先級問題,如果已經存在了自動代理創建器,且已經存在的自動代理創建器與現在的不一致,那么需要根據優先級來判斷到底需要使用哪個
2、屬性處理
回到registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中繼續接下來的分析useClassProxyingIfNecessary()方法,這里是對proxy-target-class及expose-proxy屬性的處理。
【AopNamespaceUtils】
/**
* 該方法實現了對proxy-target-class屬性以及expose-proxy 屬性的處理
* @param registry
* @param sourceElement
*/
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
//對于proxy-target-class屬性的處理
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//對于expose-proxy屬性的處理
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
//強制使用,也是屬性設置的一種方式
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
AopConfigUtils中的強制設置
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
在此處兩個屬性的作用如下:
-
1、prioxy-target-class: 主要負責上面兩種代理的實現,SpringAOP使用jdkProxy或者CGLIB為目標對象創建代理(盡量使用jdkProxy),如果被代理的目標對象實現了至少一個接口,則會使用jdk動態代理。所有該目標類型實現的接口都將被代理。若該mybatis對象沒有實現任何接口。則創建一個CGLIB代理,如果你希望強制使用CGLIB代理(即增強代理目標所有方法)。但是有如下兩個問題:
- 無法通知(advice)Final方法,因為它們不能被覆蓋。
- 需要將CGLIB二進制包放在classpath下面。
2、expose-proxy 則負責自我調用切面中的增強。
以上就完成了AspectJAutoProxyBeanDefinitionParser對象的注冊