兜兜零元 发表于 2024-11-19 23:31:34

SpringAOP模仿实现

1_底层切点、通知、切面


注意点:

[*]底层的切点实现
[*]底层的通知实现
[*]底层的切面实现
[*]ProxyFactory 用来创建代理

[*]如果指定了接口,且 proxyTargetClass = false,使用 JdkDynamicAopProxy
[*]如果没有指定接口,大概 proxyTargetClass = true,使用 ObjenesisCglibAopProxy
[*]破例:如果目的是接口范例或已经是 jdk 代理,使用 JdkDynamicAopProxy

public class A15 {
    public static void main(String[] args) {
      /*
            两个切面概念
            aspect =
                通知1(advice) +切点1(pointcut)
                通知2(advice) +切点2(pointcut)
                通知3(advice) +切点3(pointcut)
                ...
            advisor = 更细粒度的切面,包含一个通知和切点
         */

      // 1. 备好切点
      AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
      pointcut.setExpression("execution(* foo())");
      // 2. 备好通知
      MethodInterceptor advice = invocation -> {
            System.out.println("before...");
            Object result = invocation.proceed(); // 调用目标
            System.out.println("after...");
            return result;
      };
      // 3. 备好切面
      DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

      /*
         4. 创建代理
                a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现
                b. proxyTargetClass = false,目标没有实现接口, 用 cglib 实现
                c. proxyTargetClass = true, 总是使用 cglib 实现
         */
      Target2 target = new Target2();
      ProxyFactory factory = new ProxyFactory();
      factory.setTarget(target);
      factory.addAdvisor(advisor);
      factory.setInterfaces(target.getClass().getInterfaces());
      factory.setProxyTargetClass(false);
      Target2 proxy = (Target2) factory.getProxy();
      System.out.println(proxy.getClass());
      proxy.foo();
      proxy.bar();
      /*
            学到了什么
                a. Spring 的代理选择规则
                b. 底层的切点实现
                c. 底层的通知实现
                d. ProxyFactory 是用来创建代理的核心实现, 用 AopProxyFactory 选择具体代理实现
                  - JdkDynamicAopProxy
                  - ObjenesisCglibAopProxy
         */
    }

    interface I1 {
      void foo();

      void bar();
    }

    static class Target1 implements I1 {
      public void foo() {
            System.out.println("target1 foo");
      }

      public void bar() {
            System.out.println("target1 bar");
      }
    }

    static class Target2 {
      public void foo() {
            System.out.println("target2 foo");
      }

      public void bar() {
            System.out.println("target2 bar");
      }
    }
}
2_切点匹配


切点匹配:

[*]常见 aspectj 切点用法
[*]aspectj 切点的范围性,现实的 @Transactional 切点实现
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

public class A16 {
    public static void main(String[] args) throws NoSuchMethodException {
//      AspectJExpressionPointcut pt1 = new AspectJExpressionPointcut();
//      pt1.setExpression("execution(* bar())");
//      System.out.println(pt1.matches(T1.class.getMethod("foo"), T1.class));
//      System.out.println(pt1.matches(T1.class.getMethod("bar"), T1.class));
//
//      AspectJExpressionPointcut pt2 = new AspectJExpressionPointcut();
//      pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
//      System.out.println(pt2.matches(T1.class.getMethod("foo"), T1.class));
//      System.out.println(pt2.matches(T1.class.getMethod("bar"), T1.class));

      StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                // 检查方法上是否加了 Transactional 注解
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                  return true;
                }
                // 查看类上是否加了 Transactional 注解
                annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if (annotations.isPresent(Transactional.class)) {
                  return true;
                }
                return false;
            }
      };

      System.out.println(pt3.matches(T1.class.getMethod("foo"), T1.class));
      System.out.println(pt3.matches(T1.class.getMethod("bar"), T1.class));
      System.out.println(pt3.matches(T2.class.getMethod("foo"), T2.class));
      System.out.println(pt3.matches(T3.class.getMethod("foo"), T3.class));

      /*
            学到了什么
                a. 底层切点实现是如何匹配的: 调用了 aspectj 的匹配方法
                b. 比较关键的是它实现了 MethodMatcher 接口, 用来执行方法的匹配
         */
    }


    static class T1 {
      @Transactional
      public void foo() {
      }
      public void bar() {
      }
    }

    @Transactional
    static class T2 {
      public void foo() {
      }
    }

    @Transactional
    interface I3 {
      void foo();
    }
    static class T3 implements I3 {
      public void foo() {
      }
    }
}
3_从 @Aspect 到 Advisor

1_代理创建器


注意点:

[*]AnnotationAwareAspectJAutoProxyCreator 的作用

[*]将高级 @Aspect 切面统一为低级 Advisor 切面。
[*]在合适的时机创建代理。

[*]findEligibleAdvisors 找到有【资格】的 Advisors

[*]有【资格】的 Advisor 一部门是低级的, 可以由自己编写, 如本例 A17 中的 advisor3。
[*]有【资格】的 Advisor 另一部门是高级的, 由解析 @Aspect 后得到。

[*]wrapIfNecessary

[*]它内部调用 findEligibleAdvisors, 只要返回集合不空, 则体现必要创建代理。
[*]它的调用时机通常在原始对象初始化后实行, 但遇到循环依赖会提前至依赖注入之前实行。

package org.springframework.aop.framework.autoproxy;


import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
* @author shenyang
* @version 1.0
* @info TestAop
* @since 2024/8/17 20:26
*/
public class A17 {

    @Aspect//高级切面
    static class Aspect1{
      @Before("execution(* foo())")
      public void before(){
            System.out.println("aspect1 before.....");
      }
      @After("execution(* foo())")
      public void after(){
            System.out.println("aspect1 after.....");
      }
    }

    @Configuration
    static class Config {
      @Bean//低级切面
      public Advisor advisor3(MethodInterceptor advice3) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, advice3);
      }
      @Bean
      public MethodInterceptor advice3(){
            return new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                  System.out.println("advice3 before.....");
                  Object proceed = methodInvocation.proceed();
                  System.out.println("advice3 after.....");
                  return proceed;
                }
            };
      }
    }

    static class T1 {
      public void foo() {
            System.out.println("target1 foo");
      }
    }

    static class T2 {
      public void bar() {
            System.out.println("target2 bar");
      }
    }

    public static void main(String[] args) {
      GenericApplicationContext context = new GenericApplicationContext();
      context.registerBean("aspect1",Aspect1.class);
      context.registerBean("config",Config.class);
      context.registerBean(ConfigurationClassPostProcessor.class);
      context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
      context.refresh();
      AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
      List<Advisor> advisors = creator.findEligibleAdvisors(T2.class, "target2");
      System.out.println("====================");
//      advisors.forEach(System.out::println);
      T1 o1 = (T1) creator.wrapIfNecessary(new T1(), "target1", "target1");
      T2 o2 = (T2) creator.wrapIfNecessary(new T2(), "target2", "target2");
      System.out.println(o1.getClass()+" "+o2.getClass());
      o1.foo();
      o2.bar();
    }

}
2_代理创建时机


注意点:

[*]代理的创建时机

[*]初始化之后 (无循环依赖时)
[*]实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存。

[*]依赖注入与初始化不应该被加强, 仍应被施加于原始对象
package org.springframework.aop.framework.autoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;

public class A17_1 {

    public static void main(String[] args) {
      GenericApplicationContext context = new GenericApplicationContext();
      context.registerBean(ConfigurationClassPostProcessor.class);
      context.registerBean(Config.class);
      context.refresh();
      context.close();
      // 创建 -> (*) 依赖注入 -> 初始化 (*)
      /*
            学到了什么
                a. 代理的创建时机
                  1. 初始化之后 (无循环依赖时)
                  2. 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
                b. 依赖注入与初始化不应该被增强, 仍应被施加于原始对象
         */
    }

    @Configuration
    static class Config {
      @Bean // 解析 @Aspect、产生代理
      public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
      }

      @Bean // 解析 @Autowired
      public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            return new AutowiredAnnotationBeanPostProcessor();
      }

      @Bean // 解析 @PostConstruct
      public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            return new CommonAnnotationBeanPostProcessor();
      }

      @Bean
      public Advisor advisor(MethodInterceptor advice) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, advice);
      }

      @Bean
      public MethodInterceptor advice() {
            return (MethodInvocation invocation) -> {
                System.out.println("before...");
                return invocation.proceed();
            };
      }

      @Bean
      public Bean1 bean1() {
            return new Bean1();
      }

      @Bean
      public Bean2 bean2() {
            return new Bean2();
      }
    }

    static class Bean1 {
      public void foo() {

      }
      public Bean1() {
            System.out.println("Bean1()");
      }
      @Autowired public void setBean2(Bean2 bean2) {
            System.out.println("Bean1 setBean2(bean2) class is: " + bean2.getClass());
      }
      @PostConstruct public void init() {
            System.out.println("Bean1 init()");
      }
    }

    static class Bean2 {
      public Bean2() {
            System.out.println("Bean2()");
      }
      @Autowired public void setBean1(Bean1 bean1) {
            System.out.println("Bean2 setBean1(bean1) class is: " + bean1.getClass());
      }
      @PostConstruct public void init() {
            System.out.println("Bean2 init()");
      }
    }
}
3_@Before 对应的低级通知


注意点:

[*]@Before 前置通知会被转换为原始的 AspectJMethodBeforeAdvice 形式, 该对象包罗了如下信息

[*]通知代码从哪儿来
[*]切点是什么(这里为啥要切点, 后面表明)
[*]通知对象如何创建, 本例共用同一个 Aspect 对象

[*]雷同的还有

[*]AspectJAroundAdvice (围绕通知)
[*]AspectJAfterReturningAdvice
[*]AspectJAfterThrowingAdvice (围绕通知)
[*]AspectJAfterAdvice (围绕通知)

package org.springframework.aop.framework.autoproxy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectInstanceFactory;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class A17_2 {

    static class Aspect {
      @Before("execution(* foo())")
      public void before1() {
            System.out.println("before1");
      }

      @Before("execution(* foo())")
      public void before2() {
            System.out.println("before2");
      }

      public void after() {
            System.out.println("after");
      }

      public void afterReturning() {
            System.out.println("afterReturning");
      }

      public void afterThrowing() {
            System.out.println("afterThrowing");
      }

      public Object around(ProceedingJoinPoint pjp) throws Throwable {
            try {
                System.out.println("around...before");
                return pjp.proceed();
            } finally {
                System.out.println("around...after");
            }
      }
    }

    static class Target {
      public void foo() {
            System.out.println("target foo");
      }
    }

    @SuppressWarnings("all")
    public static void main(String[] args) throws Throwable {

      AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
      // 高级切面转低级切面类
      List<Advisor> list = new ArrayList<>();
      for (Method method : Aspect.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Before.class)) {
                // 解析切点
                String expression = method.getAnnotation(Before.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                list.add(advisor);
            }
      }
      for (Advisor advisor : list) {
            System.out.println(advisor);
      }
      /*
            @Before 前置通知会被转换为下面原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
                a. 通知代码从哪儿来
                b. 切点是什么(这里为啥要切点, 后面解释)
                c. 通知对象如何创建, 本例共用同一个 Aspect 对象
            类似的通知还有
                1. AspectJAroundAdvice (环绕通知)
                2. AspectJAfterReturningAdvice
                3. AspectJAfterThrowingAdvice
                4. AspectJAfterAdvice (环绕通知)
         */

    }
}
4_静态通知调用


代理对象调用流程如下(以 JDK 动态代理实现为例)


[*]从 ProxyFactory 得到 Target 和围绕通知链,根据他俩创建 MethodInvocation,简称 mi
[*]初次实行 mi.proceed() 发现有下一个围绕通知,调用它的 invoke(mi)
[*]进入围绕通知1,实行前加强,再次调用 mi.proceed() 发现有下一个围绕通知,调用它的 invoke(mi)
[*]进入围绕通知2,实行前加强,调用 mi.proceed() 发现没有围绕通知,调用 mi.invokeJoinPoint() 实行目的方法
[*]目的方法实行结束,将结果返回给围绕通知2,实行围绕通知2 的后加强
[*]围绕通知2继续将结果返回给围绕通知1,实行围绕通知1 的后加强
[*]围绕通知1返回最终的结果
图中不同颜色对应一次围绕通知或目的的调用起始至终结
   1_通知调用过程


代理方法实行时会做如下工作:

[*]通过 proxyFactory 的 getInterceptorsAndDynamicInterceptionAdvice() 将其他通知统一转换为 MethodInterceptor 围绕通知

[*]MethodBeforeAdviceAdapter 将 @Before AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
[*]AfterReturningAdviceAdapter 将 @AfterReturning AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor
[*]这体现的是适配器设计模式

[*]所谓静态通知,体现在上面方法的 Interceptors 部门,这些通知调用时无需再次查抄切点,直接调用即可
[*]结合目的与围绕通知链,创建 MethodInvocation 对象,通过它完成整个调用
package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.*;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class A18 {

    static class Aspect {
      @Before("execution(* foo())")
      public void before1() {
            System.out.println("before1");
      }

      @Before("execution(* foo())")
      public void before2() {
            System.out.println("before2");
      }

      public void after() {
            System.out.println("after");
      }

      @AfterReturning("execution(* foo())")
      public void afterReturning() {
            System.out.println("afterReturning");
      }

      @AfterThrowing("execution(* foo())")
      public void afterThrowing(Exception e) {
            System.out.println("afterThrowing " + e.getMessage());
      }

      @Around("execution(* foo())")
      public Object around(ProceedingJoinPoint pjp) throws Throwable {
            try {
                System.out.println("around...before");
                return pjp.proceed();
            } finally {
                System.out.println("around...after");
            }
      }
    }

    static class Target {
      public void foo() {
            System.out.println("target foo");
      }
    }

    @SuppressWarnings("all")
    public static void main(String[] args) throws Throwable {

      AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
      // 1. 高级切面转低级切面类
      List<Advisor> list = new ArrayList<>();
      for (Method method : Aspect.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Before.class)) {
                // 解析切点
                String expression = method.getAnnotation(Before.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                list.add(advisor);
            } else if (method.isAnnotationPresent(AfterReturning.class)) {
                // 解析切点
                String expression = method.getAnnotation(AfterReturning.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                list.add(advisor);
            } else if (method.isAnnotationPresent(Around.class)) {
                // 解析切点
                String expression = method.getAnnotation(Around.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory);
                // 切面
                Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                list.add(advisor);
            }
      }
      for (Advisor advisor : list) {
            System.out.println(advisor);
      }

      /*
            @Before 前置通知会被转换为下面原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
                a. 通知代码从哪儿来
                b. 切点是什么
                c. 通知对象如何创建, 本例共用同一个 Aspect 对象
            类似的通知还有
                1. AspectJAroundAdvice (环绕通知)
                2. AspectJAfterReturningAdvice
                3. AspectJAfterThrowingAdvice (环绕通知)
                4. AspectJAfterAdvice (环绕通知)
         */

      // 2. 通知统一转换为环绕通知 MethodInterceptor
      /*

            其实无论 ProxyFactory 基于哪种方式创建代理, 最后干活(调用 advice)的是一个 MethodInvocation 对象
                a. 因为 advisor 有多个, 且一个套一个调用, 因此需要一个调用链对象, 即 MethodInvocation
                b. MethodInvocation 要知道 advice 有哪些, 还要知道目标, 调用次序如下

                将 MethodInvocation 放入当前线程
                  |-> before1 ----------------------------------- 从当前线程获取 MethodInvocation
                  |                                             |
                  |   |-> before2 --------------------          | 从当前线程获取 MethodInvocation
                  |   |                              |          |
                  |   |   |-> target ------ 目标   advice2    advice1
                  |   |                              |          |
                  |   |-> after2 ---------------------          |
                  |                                             |
                  |-> after1 ------------------------------------
                c. 从上图看出, 环绕通知才适合作为 advice, 因此其他 before、afterReturning 都会被转换成环绕通知
                d. 统一转换为环绕通知, 体现的是设计模式中的适配器模式
                  - 对外是为了方便使用要区分 before、afterReturning
                  - 对内统一都是环绕通知, 统一用 MethodInterceptor 表示

            此步获取所有执行时需要的 advice (静态)
                a. 即统一转换为 MethodInterceptor 环绕通知, 这体现在方法名中的 Interceptors 上
                b. 适配如下
                  - MethodBeforeAdviceAdapter 将 @Before AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
                  - AfterReturningAdviceAdapter 将 @AfterReturning AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor
         */
      Target target = new Target();
      ProxyFactory proxyFactory = new ProxyFactory();
      proxyFactory.setTarget(target);
      proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); // 准备把 MethodInvocation 放入当前线程
      proxyFactory.addAdvisors(list);

      System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
      List<Object> methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class);
      for (Object o : methodInterceptorList) {
            System.out.println(o);
      }

      System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
      // 3. 创建并执行调用链 (环绕通知s + 目标)
      MethodInvocation methodInvocation = new ReflectiveMethodInvocation(
                null, target, Target.class.getMethod("foo"), new Object, Target.class, methodInterceptorList
      );
      methodInvocation.proceed();



      /*
            学到了什么
                a. 无参数绑定的通知如何被调用
                b. MethodInvocation 编程技巧: 拦截器、过滤器等等实现都与此类似
                c. 适配器模式在 Spring 中的体现
         */

    }
}
2_模仿 MethodInvocation


注意点:

[*]proceed() 方法调用链中下一个围绕通知
[*]每个围绕通知内部继续调用 proceed()
[*]调用到没有更多通知了, 就调用目的方法
MethodInvocation 的编程技巧在实现拦截器、过滤器时能用上
package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/*
    模拟调用链过程, 是一个简单的递归过程
      1. proceed() 方法调用链中下一个环绕通知
      2. 每个环绕通知内部继续调用 proceed()
      3. 调用到没有更多通知了, 就调用目标方法
*/
public class A18_1 {

    static class Target {
      public void foo() {
            System.out.println("Target.foo()");
      }
    }

    static class Advice1 implements MethodInterceptor {
      public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Advice1.before()");
            Object result = invocation.proceed();// 调用下一个通知或目标
            System.out.println("Advice1.after()");
            return result;
      }
    }

    static class Advice2 implements MethodInterceptor {
      public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Advice2.before()");
            Object result = invocation.proceed();// 调用下一个通知或目标
            System.out.println("Advice2.after()");
            return result;
      }
    }


    static class MyInvocation implements MethodInvocation {
      private Object target;// 1
      private Method method;
      private Object[] args;
      List<MethodInterceptor> methodInterceptorList; // 2
      private int count = 1; // 调用次数

      public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) {
            this.target = target;
            this.method = method;
            this.args = args;
            this.methodInterceptorList = methodInterceptorList;
      }

      @Override
      public Method getMethod() {
            return method;
      }

      @Override
      public Object[] getArguments() {
            return args;
      }

      @Override
      public Object proceed() throws Throwable { // 调用每一个环绕通知, 调用目标
            if (count > methodInterceptorList.size()) {
                // 调用目标, 返回并结束递归
                return method.invoke(target, args);
            }
            // 逐一调用通知, count + 1
            MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1);
            return methodInterceptor.invoke(this);
      }

      @Override
      public Object getThis() {
            return target;
      }

      @Override
      public AccessibleObject getStaticPart() {
            return method;
      }
    }

    public static void main(String[] args) throws Throwable {
      Target target = new Target();
      List<MethodInterceptor> list = new ArrayList<>();

      list.add(new Advice1());
      list.add(new Advice2());
      MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object, list);
      invocation.proceed();
    }
}

5_动态通知调用


注意点:

[*]通过 proxyFactory 的 getInterceptorsAndDynamicInterceptionAdvice() 将其他通知统一转换为 MethodInterceptor 围绕通知
[*]所谓动态通知,体现在上面方法的 DynamicInterceptionAdvice 部门,这些通知调用时因为要为通知方法绑定参数,还需再次利用切点表达式
[*]动态通知调用复杂水平高,性能较低
package org.springframework.aop.framework.autoproxy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.Field;
import java.util.List;

public class A19 {

    @Aspect
    static class MyAspect {
      @Before("execution(* foo(..))") // 静态通知调用,不带参数绑定,执行时不需要切点
      public void before1() {
            System.out.println("before1");
      }

      @Before("execution(* foo(..)) && args(x)") // 动态通知调用,需要参数绑定,执行时还需要切点对象
      public void before2(int x) {
            System.out.printf("before2(%d)%n", x);
      }
    }

    static class Target {
      public void foo(int x) {
            System.out.printf("target foo(%d)%n", x);
      }
    }

    @Configuration
    static class MyConfig {
      @Bean
      AnnotationAwareAspectJAutoProxyCreator proxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
      }

      @Bean
      public MyAspect myAspect() {
            return new MyAspect();
      }
    }

    public static void main(String[] args) throws Throwable {
      GenericApplicationContext context = new GenericApplicationContext();
      context.registerBean(ConfigurationClassPostProcessor.class);
      context.registerBean(MyConfig.class);
      context.refresh();

      AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
      List<Advisor> list = creator.findEligibleAdvisors(Target.class, "target");

      Target target = new Target();
      ProxyFactory factory = new ProxyFactory();
      factory.setTarget(target);
      factory.addAdvisors(list);
      Object proxy = factory.getProxy(); // 获取代理

      List<Object> interceptorList = factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo", int.class), Target.class);
      for (Object o : interceptorList) {
            showDetail(o);
      }

      System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>");
      ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(
                proxy, target, Target.class.getMethod("foo", int.class), new Object[]{100}, Target.class, interceptorList
      ) {};

      invocation.proceed();

      /*
            学到了什么
                a. 有参数绑定的通知调用时还需要切点,对参数进行匹配及绑定
                b. 复杂程度高, 性能比无参数绑定的通知调用低
         */
    }

    public static void showDetail(Object o) {
      try {
            Class<?> clazz = Class.forName("org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher");
            if (clazz.isInstance(o)) {
                Field methodMatcher = clazz.getDeclaredField("methodMatcher");
                methodMatcher.setAccessible(true);
                Field methodInterceptor = clazz.getDeclaredField("interceptor");
                methodInterceptor.setAccessible(true);
                System.out.println("环绕通知和切点:" + o);
                System.out.println("\t切点为:" + methodMatcher.get(o));
                System.out.println("\t通知为:" + methodInterceptor.get(o));
            } else {
                System.out.println("普通环绕通知:" + o);
            }
      } catch (Exception e) {
            e.printStackTrace();
      }
    }
}
补充—— Advice 常见子接口:
加强范例常见 Advice 子接口/子类描述前置通知MethodBeforeAdvice方法调用前实行后置通知AfterReturningAdvice方法调用后且正常返回时实行围绕通知MethodInterceptor方法调用前后都可加强,控制流程异常通知ThrowsAdvice方法抛出异常时加强引介通知DelegatingIntroductionInterceptor为目的对象动态添加接口实现 https://i-blog.csdnimg.cn/direct/554f4197e05241ce90c7eb92d12a1383.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SpringAOP模仿实现