Spring5.2 源码学习 - 读取 XML 的 Bean 配置信息 阶段知道:
AOP 相关配置属于自定义标签解析,对应 AopNamespaceHandler 如下:

  1. public class AopNamespaceHandler extends NamespaceHandlerSupport {
  2. @Override
  3. public void init() {
  4. // In 2.0 XSD as well as in 2.5+ XSDs
  5. registerBeanDefinitionParser("config"
  6. , new ConfigBeanDefinitionParser());
  7. registerBeanDefinitionParser("aspectj-autoproxy"
  8. , new AspectJAutoProxyBeanDefinitionParser());
  9. registerBeanDefinitionDecorator("scoped-proxy"
  10. , new ScopedProxyBeanDefinitionDecorator());
  11. // Only in 2.0 XSD: moved to context namespace in 2.5+
  12. registerBeanDefinitionParser("spring-configured"
  13. , new SpringConfiguredBeanDefinitionParser());
  14. }
  15. }

所以遇到 aspectj-autoproxy 配置就会进入 AspectJAutoProxyBeanDefinitionParser 解析器,其继承 BeanDefinitionParser 那么 parse 方法:

  1. @Override
  2. @Nullable
  3. public BeanDefinition parse(Element element, ParserContext parserContext) {
  4. // 注册 AnnotationAwareAspectJAutoProxyCreator
  5. AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext
  6. , element);
  7. // 对注解的子类的处理
  8. extendBeanDefinition(element, parserContext);
  9. return null;
  10. }

进入方法查看注册

  1. public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext
  2. , Element sourceElement) {
  3. // 注册 AnnotationAwareAspectJAutoProxyCreator
  4. BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
  5. parserContext.getRegistry(), parserContext.extractSource(sourceElement));
  6. // 对 proxy-target-class 以及 expose-proxy 属性的处理
  7. useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
  8. // 注册并通知
  9. registerComponentIfNecessary(beanDefinition, parserContext);
  10. }

注册 AnnotationAwareAspectJAutoProxyCreator

  1. @Nullable
  2. public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
  3. BeanDefinitionRegistry registry, @Nullable Object source) {
  4. return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
  5. }
  1. @Nullable
  2. private static BeanDefinition registerOrEscalateApcAsRequired(
  3. Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
  4. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  5. if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
  6. // 如果 AUTO_PROXY_CREATOR_BEAN_NAME 存在
  7. BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
  8. if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
  9. // 并且和传入的不一样,那么比较下优先级(集合索引)
  10. // 已经存在的
  11. int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
  12. // 传入的
  13. int requiredPriority = findPriorityForClass(cls);
  14. if (currentPriority < requiredPriority) {
  15. // 谁在集合中索引位置大,谁赢
  16. // 改变bean就改变其className
  17. apcDefinition.setBeanClassName(cls.getName());
  18. }
  19. }
  20. return null;
  21. }
  22. RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
  23. beanDefinition.setSource(source);
  24. beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
  25. beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  26. registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
  27. return beanDefinition;
  28. }
  1. 如果判断没有bean AUTO_PROXY_CREATOR_BEAN_NAME 那么就直接创建;
  2. 如果已经存在了,就判断下是否和传入的一致,不一致的话,那么就比较下优先级。优先级大的成为新的。

    proxy-target-class 以及 expose-proxy 属性的处理

    很明显,根据配置信息,向 BeanDefinition 中添加属性。代码如下所示:
    1. private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry
    2. , @Nullable Element sourceElement) {
    3. if (sourceElement != null) {
    4. // 如果配置了 proxy-target-class="true",那么使用添加属性 proxyTargetClass=true
    5. boolean proxyTargetClass
    6. = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
    7. if (proxyTargetClass) {
    8. AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    9. }
    10. // expose-proxy ture,那么添加属性exposeProxy=true
    11. boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
    12. if (exposeProxy) {
    13. AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    14. }
    15. }
    16. }

这里涉及到两个配置:proxy-target-class 、expose-proxy
Spring Aop 使用 JDK 动态代理或者 CGLIB 代理,如果被代理目标至少有一个接口,那么就会使用 JDK 动态代理,代理其所有实现接口的方法。如果被代理对象没有任何接口,那么就会创建 CBLIB 代理,代理其所有的方法。如果想强制使用 CGLIB 代理,则需要配置
<aop:config proxy-target-class="true"> 来强制使用。如果强制使用 CGLIB 需要考虑如下问题:

  • 无法通知(advise) Final 方法,因为它们不能被重写;
  • CGLIB 是独立的包,需要引入项目中;

有些时候对象内部的自我调用无法切中增强,这个时候就可以用到 expose-proxy。

  1. public interface Aservice{
  2. public void a();
  3. public void b();
  4. }
  5. @Service
  6. public class AServiceImpl implements AService{
  7. @Transactional(propagation = Propagation.REQUIRED)
  8. public void a(){
  9. this.b();
  10. }
  11. @Transactional(propagation = Propagation.REQUIRES_NEW)
  12. public void b(){
  13. }
  14. }

此时调用 this.b() ,并不能执行增强,解决这个问题可以增加如下配置:

  1. <aop:aspectj-autoproxy expose-proxy="true"/>

方法调用调整为:修改为 “((AService) AopContext.currentProxy()).b();” 即可.

registerComponentIfNecessary

注册通知。