• Spring-aop技术


    前言

            spring-aop技术是对oop(面向对象)的一个补充,其底层其实就是使用aspect+动态代理进行实现的,本篇文章将大概讨论下aop的核心实现流程

    相关的核心概念

            刚开始,先介绍下aop中比较核心的一些对象和概念,只要理解了这些,后面就可以很容易理解aop是怎么工作的了

    Advisor接口

            Advisor接口包含了Advice和Pointcut的定义,而这两个对象是我们进行代理的核心对象,举个例子你就明白了,如下

    1. public class UserService{
    2. public void a(){
    3. }
    4. public void b(){
    5. }
    6. }
    7. 假设有上面的类对象,现在有一段切入逻辑如下
    8. public void method(){
    9. "插入方法逻辑";
    10. }
    11. 这是一段要插入到UserService类的a和b方法的逻辑,那么在这个场景下
    12. Advice: 指的就是method这段逻辑
    13. PonitCut: 假设只想要在a方法切入,不想在b方法切入,那么这个校验过程就是PonitCut的代表

    ProxyFactory对象

            因为spring对于aop实现底层就是用代理实现的,所以底层会有这个对象进行管理代理对象,代理方法目前有两种,JdkDynamicAopProxy和ObjenesisCglibAopProxy(cglib)

            这个对象主要就是用来获取代理对象的,其他的似乎没啥说的,因为核心逻辑还是在代理对象中进行实现的,下面以两个的其中一个来进行说明

    JdkDynamicAopProxy

            基于jdk的动态代理,Java基础扎实的人肯定都会知道他会实现一个InvocationHandler接口,该接口是代理对象最终会执行的入口,我们就来看看他的invoke接口具体干了啥,如下

    1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    2. Object oldProxy = null;
    3. boolean setProxyContext = false;
    4. //这里简单理解就是获取被代理的类,比如这里就是UserService
    5. TargetSource targetSource = this.advised.targetSource;
    6. Object target = null;
    7. try {
    8. //判断如果是以下这些方法时不需要进行代理
    9. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    10. return equals(args[0]);
    11. }
    12. else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    13. return hashCode();
    14. }
    15. else if (method.getDeclaringClass() == DecoratingProxy.class) {
    16. return AopProxyUtils.ultimateTargetClass(this.advised);
    17. }
    18. else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    19. method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    20. return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    21. }
    22. //下面真正进行代理逻辑的处理
    23. Object retVal;
    24. //是否把当前的代理对象绑定到当前线程,就是放到ThreadLocal中
    25. if (this.advised.exposeProxy) {
    26. oldProxy = AopContext.setCurrentProxy(proxy);
    27. setProxyContext = true;
    28. }
    29. target = targetSource.getTarget();
    30. Class targetClass = (target != null ? target.getClass() : null);
    31. // 获取所有关联的advisor对象,也就是上面刚说的很核心的对象
    32. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    33. if (chain.isEmpty()) {
    34. //如果为空表示没有任何的代理逻辑,直接返回即可
    35. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    36. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    37. }
    38. else {
    39. //如果不为空把数据封装为ReflectiveMethodInvocation对象,然后调用proceed方法,开始处理代理逻辑
    40. MethodInvocation invocation =
    41. new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    42. // Proceed to the joinpoint through the interceptor chain.
    43. retVal = invocation.proceed();
    44. }
    45. // 处理返回值,不是核心方法,,
    46. Class returnType = method.getReturnType();
    47. if (retVal != null && retVal == target &&
    48. returnType != Object.class && returnType.isInstance(proxy) &&
    49. !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    50. retVal = proxy;
    51. }
    52. else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
    53. throw new AopInvocationException(
    54. "Null return value from advice does not match primitive return type for: " + method);
    55. }
    56. return retVal;
    57. }
    58. finally {
    59. if (target != null && !targetSource.isStatic()) {
    60. // Must have come from TargetSource.
    61. targetSource.releaseTarget(target);
    62. }
    63. if (setProxyContext) {
    64. // 移除绑定关系
    65. AopContext.setCurrentProxy(oldProxy);
    66. }
    67. }
    68. }
    69. 以上可以看到核心的处理流程,那么问题就来到了两个细节方法了,接下来分析下下面的问题

      首先,来看下 this.advised.getInterceptorsAndDynamicInterceptionAdvice这个方法,这个方法是来获取所有的Advisor对象的,也可以理解为获取Advice对象,因为最终的代理逻辑就是在Advice里面的

      1. public List getInterceptorsAndDynamicInterceptionAdvice(
      2. Advised config, Method method, @Nullable Class targetClass) {
      3. AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
      4. //获取所有的Advisor,config其实就是ProxyFactory对象,在生成的时候已经绑定进来了
      5. Advisor[] advisors = config.getAdvisors();
      6. List interceptorList = new ArrayList<>(advisors.length);
      7. Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
      8. Boolean hasIntroductions = null;
      9. //循环处理
      10. for (Advisor advisor : advisors) {
      11. if (advisor instanceof PointcutAdvisor) {
      12. // Add it conditionally.
      13. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
      14. //粗筛,可以理解为对UserService类的筛选
      15. if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
      16. //方法匹配器,进一步对UserService类下面的方法进行筛选
      17. MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
      18. boolean match;
      19. if (mm instanceof IntroductionAwareMethodMatcher) {
      20. if (hasIntroductions == null) {
      21. hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
      22. }
      23. match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
      24. }
      25. else {
      26. //是否匹配
      27. match = mm.matches(method, actualClass);
      28. }
      29. if (match) {
      30. //如果是的话会加入到这个逻辑里
      31. //把数据包装为MethodInterceptor对象返回
      32. MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
      33. if (mm.isRuntime()) {
      34. // MethodMatcher是否配置了运行时还要校验,如果是的话到时具体执行的时候还会根据实时参数进一步筛选
      35. for (MethodInterceptor interceptor : interceptors) {
      36. interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
      37. }
      38. }
      39. else {
      40. interceptorList.addAll(Arrays.asList(interceptors));
      41. }
      42. }
      43. }
      44. }
      45. else if (advisor instanceof IntroductionAdvisor) {
      46. IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
      47. if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
      48. Interceptor[] interceptors = registry.getInterceptors(advisor);
      49. interceptorList.addAll(Arrays.asList(interceptors));
      50. }
      51. }
      52. else {
      53. Interceptor[] interceptors = registry.getInterceptors(advisor);
      54. interceptorList.addAll(Arrays.asList(interceptors));
      55. }
      56. }
      57. return interceptorList;
      58. }
      59. 以上就是筛选匹配的Advisor对象,最终会统一封装为MethodInterceptor列表返回,可以进一步来看看这个,这里用了一个适配器模式,还是比较值得看看的

        DefaultAdvisorAdapterRegistry#getInterceptors方法中进行处理的

        1. @Override
        2. public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        3. List interceptors = new ArrayList<>(3);
        4. //获取对应的Advice
        5. Advice advice = advisor.getAdvice();
        6. //如果是MethodInterceptor直接加入即可
        7. if (advice instanceof MethodInterceptor) {
        8. interceptors.add((MethodInterceptor) advice);
        9. }
        10. //如果不是会使用AdvisorAdapter对象进行对比并且加入
        11. for (AdvisorAdapter adapter : this.adapters) {
        12. if (adapter.supportsAdvice(advice)) {
        13. interceptors.add(adapter.getInterceptor(advisor));
        14. }
        15. }
        16. if (interceptors.isEmpty()) {
        17. throw new UnknownAdviceTypeException(advisor.getAdvice());
        18. }
        19. return interceptors.toArray(new MethodInterceptor[0]);
        20. }

        AdvisorAdapter是一种适配器,用于对原来不是MethodInterceptor的对象进行适配为MethodInterceptor对象,可以看看它的接口定义

        1. /**
        2. * Interface allowing extension to the Spring AOP framework to allow
        3. * handling of new Advisors and Advice types.
        4. *
        5. *

          Implementing objects can create AOP Alliance Interceptors from

        6. * custom advice types, enabling these advice types to be used
        7. * in the Spring AOP framework, which uses interception under the covers.
        8. *
        9. *

          There is no need for most Spring users to implement this interface;

        10. * do so only if you need to introduce more Advisor or Advice types to Spring.
        11. *
        12. * @author Rod Johnson
        13. */
        14. public interface AdvisorAdapter {
        15. /**
        16. * Does this adapter understand this advice object? Is it valid to
        17. * invoke the {@code getInterceptors} method with an Advisor that
        18. * contains this advice as an argument?
        19. * @param advice an Advice such as a BeforeAdvice
        20. * @return whether this adapter understands the given advice object
        21. * @see #getInterceptor(org.springframework.aop.Advisor)
        22. * @see org.springframework.aop.BeforeAdvice
        23. */
        24. boolean supportsAdvice(Advice advice);
        25. /**
        26. * Return an AOP Alliance MethodInterceptor exposing the behavior of
        27. * the given advice to an interception-based AOP framework.
        28. *

          Don't worry about any Pointcut contained in the Advisor;

        29. * the AOP framework will take care of checking the pointcut.
        30. * @param advisor the Advisor. The supportsAdvice() method must have
        31. * returned true on this object
        32. * @return an AOP Alliance interceptor for this Advisor. There's
        33. * no need to cache instances for efficiency, as the AOP framework
        34. * caches advice chains.
        35. */
        36. MethodInterceptor getInterceptor(Advisor advisor);
        37. }

        只有两个方法,一个是否支持,一个获取到MethodInterceptor对象,接下来可以看看其中一个实现类,如下

        1. class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
        2. @Override
        3. public boolean supportsAdvice(Advice advice) {
        4. //是否为MethodBeforeAdvice类型的
        5. return (advice instanceof MethodBeforeAdvice);
        6. }
        7. @Override
        8. public MethodInterceptor getInterceptor(Advisor advisor) {
        9. MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        10. //把advice适配为 MethodInterceptor 对象
        11. return new MethodBeforeAdviceInterceptor(advice);
        12. }
        13. }

        这种设计模式很巧妙,很多地方都会用到这个技术,比如gateway也会有相应的使用

        AnnotationAwareAspectJAutoProxyCreator

                自动处理aop逻辑的处理器,它实现了BeanPostProcessor接口,也就是说,所有bean的创建都会经过这个类,它的大概逻辑如下

        1 .bean创建的时候经常这个处理器

        2. 查找当前bean匹配的Advisor对象,分为两种方式,一种是直接从ioc容器中获取Advisor对象,一种是通过对@Aspect进行解析里面的方法

        3. 如果没有配置的就直接返回

        4. 如果有一个及以上匹配的Advisor就使用ProxyFactory进行创建代理对象

        5. 最终整个流程就被串起来了

        到此,aop的核心流程就已经说完了,最后的问题,AnnotationAwareAspectJAutoProxyCreator这个类是如何加载到ioc容器的,其实很简单,我们在使用aop的时候,会标记以下的注解以启用aop功能 @EnableAspectJAutoProxy,这个注解会往容器中导入AspectJAutoProxyRegistrar对象,而AspectJAutoProxyRegistrar对象又会注册AnnotationAwareAspectJAutoProxyCreator对象,最终,整个流程就串起来了

        结语

                整个流程其实并不复杂,只要理解了核心的几个对象,加上些许的Ioc容器工作过程,就可以理解了,源码的入口其实就是在AnnotationAwareAspectJAutoProxyCreator这个对象的后置处理方法中进行的,主要是这个方法AbstractAutoProxyCreator#wrapIfNecessary进行了包装,当然了这个还会涉及到循环依赖问题,这里就不说了

                最后再放一张我自己画的简单流程图,如下。。。

         

      60. 相关阅读:
        一种通过udp进行无确认ip的双向的通信
        SpringMVC拦截器
        spring kafka使用(三)
        Python3 基础语法
        Ansible之Ansible Tower使用User和Team管理访问权限的笔记
        Python基于HRHet的跌倒检测系统(源码&教程)
        linux安装CUDA、cuDNN以及ytorch-gpu
        Zookeeper 节点权限控制ACL详解
        第 7 章 图形用户界面参考答案
        Docker 搭建 LNMP + Wordpress(详细步骤)
      61. 原文地址:https://blog.csdn.net/zxc_user/article/details/128064118