spring之aop底层实现

1.aop之ajc增强

  • 什么是ajc增强?

    • ajc是aop的另外一种实现, 通过aspectj编码器来改动class源文件实现aop

      image-20221230223934157

image-20221230223945914

image-20221230224031682

image-20221230224108681

2.aop之agent增强

  • 什么是agent增强?

    • agent是aop的另外一种实现,是通过类加载时改动class类

      image-20221230224306281

image-20221230224423572

3.aop之proxy增强-jdk代理

  • aop最重要的实现基于代理的实现
public class JdkProxyDemo {
    
    
    interface Foo{
    
    
        void foo();
    }
    static class Target implements Foo{
    
    

        @Override
        public void foo() {
    
    
            System.out.println("target foo");
        }
    }
    // jdk 只能针对接口代理
    public static void main(String[] args) {
    
    
        Target target = new Target();
        ClassLoader loader = JdkProxyDemo.class.getClassLoader(); // 用来加载运行时动态生成的字节码
        Foo foo = (Foo)Proxy.newProxyInstance(loader, new Class[]{
    
    Foo.class}, (p, method, args1) -> {
    
    
            System.out.println("before...");
            // 反射调用 方法.invoke(目标、参数)
            Object invoke = method.invoke(target, args1);
            System.out.println("after...");
            return invoke;
        });
        foo.foo();
    }
}

4.aop之proxy增强-cglib代理

public class CglibProxyDemo {
    
    

    static class Target{
    
    
        public void foo(){
    
    
            System.out.println("target foo");
        }
    }
    // cglib的目标对象和方法不能被final修饰,因为代理类和目标类的父子关系,jdk代理类和目标类的同级关系
    public static void main(String[] params) {
    
    
        Target target = new Target();
        Target target1 = (Target) Enhancer.create(Target.class, (MethodInterceptor) (p, method, args, methodProxy) -> {
    
    
            System.out.println("before...");
            //   method.invoke(target,args);    // 用方法反射目标
            //   methodProxy.invokeSuper(p,args); // methodProxy内部没有调用反射,需要代理
            Object invoke = methodProxy.invoke(target, args); // methodProxy内部没有调用反射,需要目标
            System.out.println("after..");
            return invoke;
        });
        target1.foo();
    }
}

5.jdk代理原理实现

public class ProxySourceDemo {
    
    

    interface Foo {
    
    
        void foo();
        int  bar();
    }

    static class Target implements Foo {
    
    

        @Override
        public void foo() {
    
    
            System.out.println("target foo");
        }

        @Override
        public int  bar() {
    
    
            System.out.println("target bar");
            return 100;
        }
    }

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

    public static void main(String[] args) {
    
    
        Foo foo = new $Proxy0(new InvocationHandler() {
    
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                System.out.println("代理增强");
                Object result = method.invoke(new Target(), args);
                return result;
            }
        });
        foo.foo();
        foo.bar();
    }
}

public class $Proxy0 implements ProxySourceDemo.Foo {
    
    
    private ProxySourceDemo.InvocationHandler invocationHandler;

    public $Proxy0(ProxySourceDemo.InvocationHandler invocationHandler) {
    
    
        this.invocationHandler = invocationHandler;
    }

    @Override
    public void foo() {
    
    
        try {
    
    
            invocationHandler.invoke(this,foo,new Object[0]);
        } catch (RuntimeException | Error e) {
    
    
            throw e;
        }catch (Throwable e){
    
    
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public int bar() {
    
    
        try {
    
    
           return (int) invocationHandler.invoke(this,bar,new Object[0]);
        } catch (RuntimeException | Error e) {
    
    
            throw e;
        }catch (Throwable e){
    
    
            throw new UndeclaredThrowableException(e);
        }
    }

    static Method foo;
    static Method bar;
    static {
    
    
        try {
    
    
            foo = ProxySourceDemo.Foo.class.getMethod("foo");
            bar = ProxySourceDemo.Foo.class.getMethod("bar");
        } catch (NoSuchMethodException e) {
    
    
            throw new NoSuchMethodError(e.getMessage());
        }
    }
}
  • jdk反射优化 前16次都是通过反射调用 性能比较低,17次的时候已经把反射调用变成正常调用,代价是为了一个方法的反射调用生成了一个代理类

    扫描二维码关注公众号,回复: 14697602 查看本文章

    image-20221231105646197

6.cglib代理原理实现

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

    public void save1(int i){
    
    
        System.out.println("save1(int)");
    }

    public void save2(long i){
    
    
        System.out.println("save2(long)");
    }
}

public class Proxy extends Target{
    
    

    private MethodInterceptor methodInterceptor;

    public Proxy(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("save0");
            save1 = Target.class.getMethod("save1",int.class);
            save2 = Target.class.getMethod("save2",long.class);
            // c1=目标类 c2=代理类
            save0Proxy = MethodProxy.create(Target.class,Proxy.class,"()V","save0","save0Super");
            save1Proxy = MethodProxy.create(Target.class,Proxy.class,"(I)V","save1","save1Super");
            save2Proxy = MethodProxy.create(Target.class,Proxy.class,"(J)V","save2","save2Super");
        } catch (NoSuchMethodException e) {
    
    
            throw  new UndeclaredThrowableException(e);
        }
    }
    // 原始功能的方法
    public void save0Super(){
    
    
        super.save0();
    }

    public void   save1Super(int i){
    
    
        super.save1(i);
    }

    public void save2Super(long l){
    
    
         super.save2(l);
    }

    // 增强功能的方法
    @Override
    public void save0() {
    
    
        try {
    
    
            methodInterceptor.intercept(this,save0,new Object[0],save0Proxy);
        } catch (Throwable e) {
    
    
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save1(int i) {
    
    
        try {
    
    
            methodInterceptor.intercept(this,save1,new Object[]{
    
    i},save1Proxy);
        } catch (Throwable e) {
    
    
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save2(long l) {
    
    
        try {
    
    
            methodInterceptor.intercept(this,save2,new Object[]{
    
    l},save2Proxy);
        } catch (Throwable e) {
    
    
            throw new UndeclaredThrowableException(e);
        }
    }
}


public class CglibSourceDemo {
    
    
    public static void main(String[] args) {
    
    
        Proxy proxy = new Proxy(new MethodInterceptor() {
    
    
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
    
                System.out.println("cglib代理增强");
                Object invoke = method.invoke(new Target(),args);
                return invoke;
            }
        });
        proxy.save0();
        proxy.save1(1);
        proxy.save2(1l);
    }
}

image-20221231111827394

  • 无反射调用原理

    • 首次使用MethodProxy方法时就会创建代理Class和目标Class类,因为MethodProxy记录了方法签名(方法名,入参,返回参数)所以getIndex就能获取到方法的编号,之后MethodProxy调用invoke就会间接调用TargetFastClass中的invoke方法,传入方法编号以及目标对象和参数完成无需反射调用

    image-20221231143457020

image-20221231144504846

image-20221231144357656

  • 对比jdk代理的优势?
    • jdk调16次,调17次的时候会针对一个方法产生一个代理类,使之后的反射变成无调用反射,cglib是methodProxy一调用就会产生代理不需要16次调用,一上来就无需反射,cglib一个代理类会对应2个FastClass(一个代理class,一个目标class)一个代理类可以匹配多个方法

7.spring的代理选择

public class SpringProxyDemo {
    
    
    public static void main(String[] args) {
    
    
        /*
               两个切面概念:
             aspect=
                 通知1(advice) + 切点1 (pointcut)
                 通知2(advice) + 切点2 (pointcut)
                 通知3(advice) + 切点3 (pointcut)

             advisor = 更细粒度点切面,包含一个通知和切点
         */

        // 准备好切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        // 准备好通知
        MethodInterceptor advice = new MethodInterceptor() {
    
    
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
                System.out.println("before..");
                Object proceed = invocation.proceed();
                System.out.println("after...");
                return proceed;
            }
        };
        // 准备好切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,advice);
        // 创建代理
        /*
              ProxyConfig
              proxyTargetClass:false 目标实现接口 使用jdk实现
              proxyTargetClass:false 目标没有实现接口 使用cglib实现
              proxyTargetClass:true  总是使用cglib实现
         */
        Target1 target1 = new Target1();
        ProxyFactory factory = new ProxyFactory();
        factory.addAdvisor(advisor);
        factory.setTarget(target1);
//        factory.setInterfaces(target1.getClass().getInterfaces());
        factory.setProxyTargetClass(true);
        T1 t1 = (T1) factory.getProxy();
        System.out.println(t1.getClass());
        t1.foo();
        t1.bar();
    }

    interface T1 {
    
    
        void foo();

        void bar();
    }

    static class Target1 implements T1 {
    
    

        @Override
        public void foo() {
    
    
            System.out.println("foo....");
        }

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

8.切点匹配

  • 使用 AspectJExpressionPointcut.setExpression(“execution(* foo())”)或者@annatation只能匹配方法无法匹配类上或者继承链路上是否使用注解.

image-20221231162548579

9.AnnotationAwareAspectJAutoProxyCreator

package com.liubo.spring.a09;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
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.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author lb
 * @date 2022/12/31 4:36 下午
 */
public class AnnotationAwareAspectJAutoProxyCreatorDemo {
    
    
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    
    
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean("aspect", Aspect1.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        /*
        AnnotationAwareAspectJAutoProxyCreator作用:
                1.找到容器中所有的切面,如果是高级切面会转换成低级切面
                2.根据切面创建代理对象
         */
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
				/*
					 创建--->(*)依赖注入--->初始化(*)
					 a.代理的创建时机
					 			1.初始化之后(无循环依赖)
					 			2.实例创建后,依赖注入前(有循环依赖时)并暂存于二级缓存
					 b.依赖注入与初始化不应该被增强,任应被施加于原始对象
				*/
        context.refresh();
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        /*
         creator.findEligibleAdvisors(Target1.class, "target1"):找到有资格的Advisors
         creator.wrapIfNecessary(new Target1(),"target1","target1"):内部调用findEligibleAdvisors,只要返回集合不为空,则表示需要创建代理
         */
        Method method = AbstractAdvisorAutoProxyCreator.class.getDeclaredMethod("findEligibleAdvisors", Class.class, String.class);
        method.setAccessible(true);
        List<Advisor> advisors = (List<Advisor>) method.invoke(creator, Target1.class, "target1");
        for (Advisor advisor : advisors) {
    
    
            System.out.println(advisor);
        }

        Method method2 = AbstractAutoProxyCreator.class.getDeclaredMethod("wrapIfNecessary", Object.class, String.class, Object.class);
        method2.setAccessible(true);
        Object o1 = method2.invoke(creator, new Target1(), "target1", "target1");
        System.out.println(o1.getClass());
        Object o2 = method2.invoke(creator, new Target2(), "target2", "target2");
        System.out.println(o2.getClass());

    }

    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 before() {
    
    
            System.out.println("before1 ....");
        }

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

    @Configuration
    static class Config {
    
    
        @Bean  // 低级切面 切点+通知
        public Advisor advisor(MethodInterceptor advice) {
    
    
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, advice);
        }

        @Bean
        public MethodInterceptor advice() {
    
    
            return new MethodInterceptor() {
    
    
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
                    System.out.println("before2..");
                    Object proceed = invocation.proceed();
                    System.out.println("after2...");
                    return proceed;
                }
            };
        }
    }
}
  • 高级切面转低级切面过程

    image-20221231205015826

10.统一转为环绕通知

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[0], Target.class, methodInterceptorList
        );
        methodInvocation.proceed();



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

    }
}

猜你喜欢

转载自blog.csdn.net/weixin_53060535/article/details/128585606