Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • Spring常见面试题
  • Spring常用注解与接口
  • 容器与Bean
  • AOP
    • AOP增强方式
      • jdk代理原理
      • cglib代理原理
    • Spring选择代理
    • 从@Aspect到Advisor
    • 静态通知调用
  • Spring事务
  • Spring中的设计模式
  • 手撸Spring

  • 事务嵌套
  • 事件监听器
  • Spring自定义异常
  • Spring
Nreal
2023-12-05
目录

AOP

# AOP增强方式

  1. aspectj 编译器增强;

    • 通过 ajc 编译器在编译 class 类文件时,就把通知的增强功能,织入到目标类的字节码中;

    • 通过 agent 在加载目标类时,修改目标类的字节码,织入增强功能;

  2. 代理增强 (运行期增强);

    1. jdk动态代理:目标必须实现接口,生成的代理类实现相同接口,因此代理与目标之间是平级兄弟关系;

      public class JdkProxyDemo {
          interface Foo{
              void foo();
          }
          //目标类与代理是兄弟关系
          static class Target implements Foo{
              @Override
              public void foo() {
                  System.out.println("target foo");
              }
          }
      
          public static void main(String[] param) {
              //目标对象
              Target target = new Target();
              //代理对象 (1.目标对象的类加载器,2.接口,3.InvocationHandler)
              Foo proxy = (Foo) Proxy.newProxyInstance(Target.class.getClassLoader(),
                      new Class[]{Foo.class},
                      //1.代理对象自己,2.正在执行的方法,3.方法传过来的实际参数
                      (p,method,args)->{
                          System.out.println("Proxy before...");
                          // 一般调用方法:目标.方法(参数);
                          // 使用反射:方法.invoke(目标,参数);
                          Object res = method.invoke(target,args);
                          System.out.println("Proxy after...");
                          return res;
                      });
              //调用代理
              proxy.foo();
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
    2. cglib动态代理:生成的代理类是目标的子类,因此代理与目标之间是子父关系;

      public class CglibProxyDemo {
          static class Target {
              public void foo() {
                  System.out.println("target foo");
              }
          }
      
          public static void main(String[] param) {
              Target target = new Target();
              // 代理和目标是父子继承关系
              Target proxy = (Target) Enhancer.create(Target.class, new MethodInterceptor() {
                  // 1.代理对象自己,2.代理类中执行的方法,3.方法参数,4.另一个方法对象
                  @Override
                  public Object intercept(Object p, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                      System.out.println("before...");
      //                Object res = method.invoke(target,args);// 用方法反射调用目标
      //                //methodProxy 避免反射调用
      //                Object res = methodProxy.invoke(target,args); // 内部没有用反射,需要目标(Spring使用);
                      Object res = methodProxy.invokeSuper(p,args);// 内部没有用反射,需要代理;
                      System.out.println("after...");
                      return res;
                  }
              });
              proxy.foo();
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26

# jdk代理原理

利用 InvocationHandler回调;

  1. 接口与目标类

    public interface Foo {
        void foo();
        int bar();
    }
    
    1
    2
    3
    4
    public class Target implements Foo{
        @Override
        public void foo() {
            System.out.println("target foo");
        }
    
        @Override
        public int bar() {
            System.out.println("target bar");
            return 100;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  2. 代理类

    public class $Proxy0 implements Foo{
    
        private A2.InvocationHandler h;
    
        public $Proxy0(A2.InvocationHandler h){
            this.h = h;
        }
    
        static Method foo;//避免调用一次就创建一个方法对象
        static Method bar;
        static {
            try {
                foo = Foo.class.getMethod("foo");
                bar = Foo.class.getMethod("bar");
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
        }
    
        @Override
        public void foo() {
            try {
                h.invoke(this,foo,new Object[0]);//代理类为自己this
            } catch (RuntimeException | Error e) {//运行时异常 直接抛
                throw e;
            } catch (Throwable e) {//检查异常 转换未运行异常
                throw new UndeclaredThrowableException(e);
            }
        }
    
        @Override
        public int bar() {
            try {
                Object result = h.invoke(this, bar, new Object[0]);
                return (int) result;
            } catch (RuntimeException | Error e) {
                throw e;
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
  3. 测试

    public class A2 {
    
        interface InvocationHandler {
            Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
        }
    
        public static void main(String[] param) {
            Foo proxy = new $Proxy0(new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
                    // 1.动态增强
                    System.out.println("before...");
                    // 2.反射调用目标方法
                    return method.invoke(new Target(),args);
                }
            });
            proxy.foo();
            proxy.bar();
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

如果直接将代理类继承Proxy类,省去自己定义InvocationHandler过程;

public class $Proxy0 extends Proxy implements Foo{

//    private A2.InvocationHandler h;
//
//    public $Proxy0(A2.InvocationHandler h){
//        this.h = h;
//    }

    protected $Proxy0(InvocationHandler h) {
        super(h);
    }
    
    //......
      
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class A2 {

//    interface InvocationHandler {
//        Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
//    }

    public static void main(String[] param) {
        Foo proxy = new $Proxy0(new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
                // 1.动态增强
                System.out.println("before...");
                // 2.反射调用目标方法
                return method.invoke(new Target(),args);
            }
        });
        proxy.foo();
        proxy.bar();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# cglib代理原理

利用 MethodInterceptor回调;

使用 MethodProxy避免反射;

  1. 目标类

    public class Target {
        public void save() {
            System.out.println("save()");
        }
    
        public void save(int i) {
            System.out.println("save(int)");
        }
    
        public void save(long j) {
            System.out.println("save(long)");
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  2. 代理类

    public class Proxy extends Target{
        private MethodInterceptor methodInterceptor;
    
        public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
            this.methodInterceptor = methodInterceptor;
        }
    
        static Method save0;
        static Method save1;
        static Method save2;
        static MethodProxy save0Proxy;
        static MethodProxy save1Proxy;
        static MethodProxy save2Proxy;
        static {
            try {
                save0 = Target.class.getMethod("save");
                save1 = Target.class.getMethod("save", int.class);
                save2 = Target.class.getMethod("save", long.class);
                save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
                save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
                save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
        }
    
        // 原始功能
        public void saveSuper() {
            super.save();
        }
        public void saveSuper(int i) {
            super.save(i);
        }
        public void saveSuper(long j) {
            super.save(j);
        }
    
        // 增强功能
        @Override
        public void save() {
            try {
                methodInterceptor.intercept(this, save0, new Object[0], save0Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    
        @Override
        public void save(int i) {
            try {
                methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    
        @Override
        public void save(long j) {
            try {
                methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
  3. 测试

    public class A3 {
        public static void main(String[] args) {
            Proxy proxy = new Proxy();
            Target target = new Target();
            proxy.setMethodInterceptor(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    System.out.println("before...");
                    // 反射调用
    //                return method.invoke(target, args);
                    // 内部无反射, 结合目标用
                    return methodProxy.invoke(target, args);
                    // 内部无反射, 结合代理用
    //                return methodProxy.invokeSuper(p, args);
                }
            });
            proxy.save();
            proxy.save(1);
            proxy.save(2L);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

# Spring选择代理

Spring 中对切点、通知、切面的抽象:

  • 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut;
  • 通知:典型接口为 MethodInterceptor 代表环绕通知;
  • 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut;

代理类相关:

  • AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现;
  • AopProxy 通过 getProxy 创建代理对象;
  • 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor;

测试:

public class A4 {
    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();
    }

    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");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# 从@Aspect到Advisor

代理创建器:AnnotationAwareAspectJAutoProxyCreator 的作用

  • 将高级 @Aspect 切面统一为低级 Advisor 切面;

  • 在合适的时机创建代理(Bean的实例化与依赖注入间,或初始化之后);

    代理创建时机:

    • 初始化之后 (无循环依赖时);
    • 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存;
public class A1 {
    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);//Bean后处理器
        context.refresh();

        /*
            第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
                a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
                b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
         */
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List<Advisor> advisors = creator.findEligibleAdvisors(Target2.class, "target2");
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }

        /*
            第二个重要方法 wrapIfNecessary
                a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
         */
        Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
        System.out.println(o1.getClass());
        Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
        System.out.println(o2.getClass());

        ((Target1) o1).foo();
    }

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

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

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

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

    @Configuration
    static class Config {
        @Bean // 低级切面
        public Advisor advisor3(MethodInterceptor advice3) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
            return advisor;
        }
        @Bean
        public MethodInterceptor advice3() {
            return invocation -> {
                System.out.println("advice3 before...");
                Object result = invocation.proceed();
                System.out.println("advice3 after...");
                return result;
            };
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

高级切面@Before如何转化为低级切面?

public class A2 {
 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);//创建切点对象
             // 通知类,根据注解的不同选择不同的底层实现,如@Before
             AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
             // 切面
             Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
             list.add(advisor);
         }
     }
     for (Advisor advisor : list) {
         System.out.println(advisor);
     }
 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  1. @Before 前置通知会被转换为原始的 AspectJMethodBeforeAdvice 形式,该对象包含了如下信息:

    1. 通知代码从哪儿来;
    2. 切点是什么(这里为啥要切点, 后面解释);
    3. 通知对象如何创建, 本例共用同一个 Aspect 对象;
  2. 类似的还有

    1. AspectJAroundAdvice (环绕通知);
    2. AspectJAfterReturningAdvice;
    3. AspectJAfterThrowingAdvice (环绕通知);
    4. AspectJAfterAdvice (环绕通知);

    通知统一转换为环绕通知 MethodInterceptor;

# 静态通知调用

容器与Bean
Spring事务

← 容器与Bean Spring事务→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式