Spring源码-AOP(五)-AOP核心组件的注册
前言
上一篇已经说过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对象的注册