【小家Spring】Sping AOP中使用到的那些工具类盘点:AopUtils、AopConfigUtils、AspectJAopUtils 、AopProxyUtils、AopContext(下)

简介: 【小家Spring】Sping AOP中使用到的那些工具类盘点:AopUtils、AopConfigUtils、AspectJAopUtils 、AopProxyUtils、AopContext(下)

AopProxyUtils

我理解成它是对org.springframework.aop.support.AopUtils的一个补充。


    public static void main(String[] args) {
        HelloService helloService = getProxy(new HelloServiceImpl());
        //===============演示AopUtils==================
        // 注意:此处的入参必须是一个Advised:也就是被代理过的对象,否则返回null
        // 里面的TargetSource必须是SingletonTargetSource才会有所返回
        //@since 4.3.8
        System.out.println(AopProxyUtils.getSingletonTarget(helloService)); //com.fsx.service.HelloServiceImpl@17d677df
        // 获取一个代理对象的最终对象类型
        System.out.println(AopProxyUtils.ultimateTargetClass(helloService)); //class com.fsx.service.HelloServiceImpl
    }


接下俩的方法,才是这个工具类真正厉害的方法:


public abstract class AopProxyUtils {
  ...
  //很牛逼的方法来了,判断一个advised真正需要代理的目标接口列表 
  // 这个方法在getProxy()上都有应用,非常的重要。核心实现事下面的这个私有方法
  public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) {
    return completeProxiedInterfaces(advised, false);
  }
  // 很显然发现,最终代理出来的对象,除了实现了自己的接口外,还实现了额外的接口,如:
  // SpringProxy、Advised、DecoratingProxy等三个接口(备注:CGLIB代理未实现DecoratingProxy接口)
  static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
    Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
    if (specifiedInterfaces.length == 0) {
      // No user-specified interfaces: check whether target class is an interface.
      Class<?> targetClass = advised.getTargetClass();
      if (targetClass != null) {
        if (targetClass.isInterface()) {
          advised.setInterfaces(targetClass);
        }
        else if (Proxy.isProxyClass(targetClass)) {
          advised.setInterfaces(targetClass.getInterfaces());
        }
        specifiedInterfaces = advised.getProxiedInterfaces();
      }
    }
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
    int nonUserIfcCount = 0;
    if (addSpringProxy) {
      nonUserIfcCount++;
    }
    if (addAdvised) {
      nonUserIfcCount++;
    }
    if (addDecoratingProxy) {
      nonUserIfcCount++;
    }
    Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
    System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
    int index = specifiedInterfaces.length;
    if (addSpringProxy) {
      proxiedInterfaces[index] = SpringProxy.class;
      index++;
    }
    if (addAdvised) {
      proxiedInterfaces[index] = Advised.class;
      index++;
    }
    if (addDecoratingProxy) {
      proxiedInterfaces[index] = DecoratingProxy.class;
    }
    return proxiedInterfaces;
  }
  //该方法用于获取一个代理对象中的用户定义的接口,即非(Advised接口体系)之外的其他接口
  public static Class<?>[] proxiedUserInterfaces(Object proxy) {
    Class<?>[] proxyInterfaces = proxy.getClass().getInterfaces();
    int nonUserIfcCount = 0;
    if (proxy instanceof SpringProxy) {
      nonUserIfcCount++;
    }
    if (proxy instanceof Advised) {
      nonUserIfcCount++;
    }
    if (proxy instanceof DecoratingProxy) {
      nonUserIfcCount++;
    }
    Class<?>[] userInterfaces = new Class<?>[proxyInterfaces.length - nonUserIfcCount];
    System.arraycopy(proxyInterfaces, 0, userInterfaces, 0, userInterfaces.length);
    Assert.notEmpty(userInterfaces, "JDK proxy must implement one or more interfaces");
    return userInterfaces;
  }
  //判断两个(即将)代理出来的对象是否相同
  public static boolean equalsInProxy(AdvisedSupport a, AdvisedSupport b) {
    return (a == b ||
        (equalsProxiedInterfaces(a, b) && equalsAdvisors(a, b) && a.getTargetSource().equals(b.getTargetSource())));
  }
  // 判断它哥俩的接口是否相同
  public static boolean equalsProxiedInterfaces(AdvisedSupport a, AdvisedSupport b) {
    return Arrays.equals(a.getProxiedInterfaces(), b.getProxiedInterfaces());
  }
  // 判断它哥俩的增强器(Advisor)是否相同
  public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
    return Arrays.equals(a.getAdvisors(), b.getAdvisors());
  }
}


JDK代理和CGLIB代理的获取代理对象方法都用使用此方法:


  // JDK代理的获取代理对象~~~
  @Override
  public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }
    // 这里就是获取到所有需要被代理的接口
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  }


AopProxyUtils中的方法不多,但是其中的ultimateTargetClass和completeProxiedInterfaces方法确是Spring AOP中比较重要的方法,也给了我们一个入手观察Spring AOP真正实现过程的一个突破口;我认为这个,才是AopProxyUtils给我们的价值;


AopContext


这个工具类就更简单,它代表AOP的上下文。主要是提供我们访问上下文中当前AOP对象的快速方法。


public abstract class AopContext {
  // 一个ThreadLocal,和当前上下文绑定的AOP对象
  private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");
  // public方法,调用者可以在任何地方获取到当前上下文中的AOP代理对象。
  // 请注意:这个和exposeProxy参数有关,只有为true了才生效,默认都是false的
  public static Object currentProxy() throws IllegalStateException {
    Object proxy = currentProxy.get();
    if (proxy == null) {
      throw new IllegalStateException(
          "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
    }
    return proxy;
  }
  @Nullable
  static Object setCurrentProxy(@Nullable Object proxy) {
    Object old = currentProxy.get();
    if (proxy != null) {
      currentProxy.set(proxy);
    }
    else {
      currentProxy.remove();
    }
    return old;
  }
}


备注:这个工具类主要是和属性exposeProxy相关,让我们能够快捷的获取到AOP代理对象,而不是this对象。这个在事务不生效原因大解读的博文了得到了应用


AutoProxyUtils


为自动代理组件准备的工具类。主要用于框架内部使用(AbstractAutoProxyCreator)

public abstract class AutoProxyUtils {
  // org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass
  // preserve:保护的  保留的
  // determine:查明  测定
  public static final String PRESERVE_TARGET_CLASS_ATTRIBUTE =
      Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "preserveTargetClass");
  // org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass
  public static final String ORIGINAL_TARGET_CLASS_ATTRIBUTE =
      Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass");
  // 判断该beanName是否应该被代理
  // `AbstractAutoProxyCreator`里就有判断是否能够被代理。  如果能够被代理,那就采用CGLIB的代理方式了
  // 往里setAttr,目前只有`ConfigurationClassPostProcessor`对config配置类进行增强的时候
  // 
  public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) {
    // 容器内存在这个Bean,并且这个Bean的定义信息里面属性值`PRESERVE_TARGET_CLASS_ATTRIBUTE`必须是true才行  说明才能被代理
    if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
      BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
      return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
    }
    return false;
  }
  // 看看这个Bean定义的TargetClass
  // 如果Bean定义信息里面有ORIGINAL_TARGET_CLASS_ATTRIBUTE这个字段,那就不用getType()了
  // 以及ScopedProxyUtils创建和Scope有关的代理类的时候,其余地方都不会设置此属性
  @Nullable
  public static Class<?> determineTargetClass(ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) {
    if (beanName == null) {
      return null;
    }
    if (beanFactory.containsBeanDefinition(beanName)) {
      BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
      Class<?> targetClass = (Class<?>) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);
      if (targetClass != null) {
        return targetClass;
      }
    }
    return beanFactory.getType(beanName);
  }
  //Expose the given target class for the specified bean, if possible
  // 就是在它的Bean定义信息里面,设置一个ORIGINAL_TARGET_CLASS_ATTRIBUTE属性,然后吧targetClass类型放进去
  // 也是子啊`AbstractAutoProxyCreator`创建代理的时候会这只进去的
  static void exposeTargetClass(ConfigurableListableBeanFactory beanFactory, @Nullable String beanName,
      Class<?> targetClass) {
    if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
      beanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass);
    }
  }
}


AspectJAopUtils

相比于AopUtilsAspectJAopUtils是专门针对于AspectJ advisors的工具类。(当然AspectJ也是当下的主流方式)


public abstract class AspectJAopUtils {
  //拿到AspectJ的优先信息:AspectJPrecedenceInformation 这个就接口保存着
  @Nullable
  public static AspectJPrecedenceInformation getAspectJPrecedenceInformationFor(Advisor anAdvisor) {
    if (anAdvisor instanceof AspectJPrecedenceInformation) {
      return (AspectJPrecedenceInformation) anAdvisor;
    }
    Advice advice = anAdvisor.getAdvice();
    if (advice instanceof AspectJPrecedenceInformation) {
      return (AspectJPrecedenceInformation) advice;
    }
    return null;
  }
  // Advisor 是否是前置通知类型~~~~(Advisor都持有一个advice嘛)
  public static boolean isBeforeAdvice(Advisor anAdvisor) {
    AspectJPrecedenceInformation precedenceInfo = getAspectJPrecedenceInformationFor(anAdvisor);
    if (precedenceInfo != null) {
      return precedenceInfo.isBeforeAdvice();
    }
    return (anAdvisor.getAdvice() instanceof BeforeAdvice);
  }
  // Advisor 是否是后置通知类型~~~~(Advisor都持有一个advice嘛)
  public static boolean isAfterAdvice(Advisor anAdvisor) {
    AspectJPrecedenceInformation precedenceInfo = getAspectJPrecedenceInformationFor(anAdvisor);
    if (precedenceInfo != null) {
      return precedenceInfo.isAfterAdvice();
    }
    return (anAdvisor.getAdvice() instanceof AfterAdvice);
  }
}


AspectJProxyUtils

同样的,它相对于AopProxyUtils,它只是专门处理AspectJ代理对象的工具类。


public abstract class AspectJProxyUtils {
  // 判断,该Advisor是否是AspectJ的的增强器
  private static boolean isAspectJAdvice(Advisor advisor) {
    return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
        advisor.getAdvice() instanceof AbstractAspectJAdvice ||
        (advisor instanceof PointcutAdvisor &&
             ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
  }
  // 只提供这么一个公共方法,但是这个方法都还是非常重要的。 Capable:有能力的
  // 它在自动代理创建器`AspectJAwareAdvisorAutoProxyCreator#extendAdvisors`方法中有调用(重要~~~)
  // 在AspectJProxyFactory#addAdvisorsFromAspectInstanceFactory方法中也有调用
  // 它的作用:只要发现有AspectJ的Advisor存在,并且advisors还不包含有ExposeInvocationInterceptor.ADVISOR  那就在第一个位置上调添加一个ExposeInvocationInterceptor.ADVISOR
  // 这个`ExposeInvocationInterceptor.ADVISOR`的作用:就是获取到当前的currentInvocation,也是使用的ThreadLocal
  public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // Don't add advisors to an empty list; may indicate that proxying is just not required
    if (!advisors.isEmpty()) {
      boolean foundAspectJAdvice = false;
      for (Advisor advisor : advisors) {
        // Be careful not to get the Advice without a guard, as
        // this might eagerly instantiate a non-singleton AspectJ aspect
        if (isAspectJAdvice(advisor)) {
          foundAspectJAdvice = true;
        }
      }
      if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
        advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
        return true;
      }
    }
    return false;
  }
}
相关文章
|
2天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
23 8
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
76 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
80 8
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
50 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
51 4
|
3月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
57 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
47 1
|
4月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
下一篇
开通oss服务