在 Spring5.2 源码学习 - 读取 XML 的 Bean 配置信息 阶段知道:
AOP 相关配置属于自定义标签解析,对应 AopNamespaceHandler 如下:
public class AopNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {// In 2.0 XSD as well as in 2.5+ XSDsregisterBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace in 2.5+registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}}
所以遇到 aspectj-autoproxy 配置就会进入 AspectJAutoProxyBeanDefinitionParser 解析器,其继承 BeanDefinitionParser 那么 parse 方法:
@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 注册 AnnotationAwareAspectJAutoProxyCreatorAopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);// 对注解的子类的处理extendBeanDefinition(element, parserContext);return null;}
进入方法查看注册
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {// 注册 AnnotationAwareAspectJAutoProxyCreatorBeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));// 对 proxy-target-class 以及 expose-proxy 属性的处理useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);// 注册并通知registerComponentIfNecessary(beanDefinition, parserContext);}
注册 AnnotationAwareAspectJAutoProxyCreator
@Nullablepublic static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}
@Nullableprivate 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 存在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就改变其classNameapcDefinition.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;}
- 如果判断没有bean AUTO_PROXY_CREATOR_BEAN_NAME 那么就直接创建;
 - 如果已经存在了,就判断下是否和传入的一致,不一致的话,那么就比较下优先级。优先级大的成为新的。
proxy-target-class 以及 expose-proxy 属性的处理
很明显,根据配置信息,向 BeanDefinition 中添加属性。代码如下所示:private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {if (sourceElement != null) {// 如果配置了 proxy-target-class="true",那么使用添加属性 proxyTargetClass=trueboolean proxyTargetClass= Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));if (proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}// expose-proxy ture,那么添加属性exposeProxy=trueboolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));if (exposeProxy) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}
 
这里涉及到两个配置:proxy-target-class 、expose-proxy
Spring Aop 使用 JDK 动态代理或者 CGLIB  代理,如果被代理目标至少有一个接口,那么就会使用 JDK 动态代理,代理其所有实现接口的方法。如果被代理对象没有任何接口,那么就会创建 CBLIB 代理,代理其所有的方法。如果想强制使用 CGLIB 代理,则需要配置<aop:config proxy-target-class="true"> 来强制使用。如果强制使用 CGLIB 需要考虑如下问题:
- 无法通知(advise) Final 方法,因为它们不能被重写;
 - CGLIB 是独立的包,需要引入项目中;
 
有些时候对象内部的自我调用无法切中增强,这个时候就可以用到 expose-proxy。
public interface Aservice{public void a();public void b();}@Servicepublic class AServiceImpl implements AService{@Transactional(propagation = Propagation.REQUIRED)public void a(){this.b();}@Transactional(propagation = Propagation.REQUIRES_NEW)public void b(){}}
此时调用 this.b() ,并不能执行增强,解决这个问题可以增加如下配置:
<aop:aspectj-autoproxy expose-proxy="true"/>
方法调用调整为:修改为 “((AService) AopContext.currentProxy()).b();” 即可.
registerComponentIfNecessary
注册通知。
