AOP 实现的几种方法 arthas工具分析

9) AOP 实现之 ajc 编译器

代码参考项目 demo6_advanced_aspectj_01

收获

  1. 编译器也能修改 class 实现增强

  2. 编译器增强能突破代理仅能通过方法重写增强的限制:可以对构造方法、静态方法等实现增强

项目地址:demo6_advanced_aspectj_01https://github.com/LJay997/demo6_advanced_aspectj_01

查看IDEA 编译的class文件可看出ajc帮我们修改了源码实现了增强静态方法

AOP 实现的几种方法 arthas工具分析_第1张图片

10) AOP 实现之 agent 类加载

代码参考项目 demo6_advanced_aspectj_02

收获

  1. 类加载时可以通过 agent 修改 class 实现增强

demo6_advanced_aspectj_02https://github.com/LJay997/demo6_advanced_aspectj_02项目地址:[email protected]:LJay997/demo6_advanced_aspectj_02.git

 使用 Alibaba开源的Java诊断工具  Arthashttps://github.com/alibaba/arthas/blob/master/README_CN.md 反编译运行时的文件

        下载arthas-boot.jar,然后用java -jar的方式启动:

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

 运行 A10,选择3

运行成功后 使用命令 jad (Decompile class 使用 help命令可查看帮助)

jad  jad com.itheima.service.MyService

 查看运行时编译文件。可见 aop foo()foo()内部又调用了自己的 bar()也可以被增强的。

Spring Aop失效的情況及解决办法http://t.csdn.cn/aRC6D

11) AOP 实现之 proxy

演示1 - jdk 动态代理

interface Foo {
    void foo();
    int bar();
}
class Target implements Foo {

    @Override
    public int bar() {
        return 0;
    }

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

    public static void main(String[] args) throws IOException {
        // method.invoke 需要传递 target
        Target target = new Target();
        ClassLoader loader = JdkProxy.class.getClassLoader();
        // Proxy.newProxyInstance  ClassLoader [] Class[]
        // java.lang.reflect 生成的代理对象需要是接口实现的方法 代理与目标是同级关系
        Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (tmpProxy, method, args1) -> {
            System.out.println("before");
            // method.invoke 参数1 需要传递
            return method.invoke(target, args1);
        });
        // 执行代理方法
        proxy.foo();
        // 获取当前代理方法的类
        System.out.println(proxy.getClass());
        // 防止程序自己终止
        System.in.read();
    }
}

使用arthas工具查看 JdkProxy运行期间动态生成(ASM)生成的代理类的源码。

# 运行 arthas
java -jar .\arthas-boot.jar

# 查看到程序的代号输入(回车确认)
4

# jad 命令反编译
jad $Proxy0

AOP 实现的几种方法 arthas工具分析_第2张图片

 arthas 获取的源码JdkProxy

package a11;

import a11.Foo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0
extends Proxy
implements Foo {
    // 获取接口所有的方法
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;
    
    // 实现构造方法 Proxy
    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke(this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int bar() {
        try {
            return (Integer)this.h.invoke(this, m3, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void foo() {
        try {
            this.h.invoke(this, m4, null);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("a11.Foo").getMethod("bar", new Class[0]);
            m4 = Class.forName("a11.Foo").getMethod("foo", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }
}

使用IDEA插件ASM加载字节码文件

AOP 实现的几种方法 arthas工具分析_第3张图片

AOP 实现的几种方法 arthas工具分析_第4张图片

 main 方法中补充


        byte[] dump = $Proxy0Dump.dump();

        ClassLoader classLoader = new ClassLoader() {
            @Override
            protected Class findClass(String name) throws ClassNotFoundException {
                // 将字节数组转换为Class 类的实例
                return super.defineClass(name, dump, 0, dump.length);
            }
        };

        Class proxy0 = classLoader.loadClass("$Proxy0");
        Constructor constructor = proxy0.getConstructor(InvocationHandler.class);
        Foo proxy = (Foo)constructor.newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return null;
            }
        });
        
        proxy.foo();
        
        // .....JDK 代理方法
        Target target = new Target();
        // ......

JDK 代理的优化

在反射调用第17次时候 代理类变化了 

16:jdk.internal.reflect.NativeMethodAccessorImpl@cb5822  ->
17:jdk.internal.reflect.GeneratedMethodAccessor2@26653222

public class TestMethodInvoke {
    public static void main(String[] args) throws Exception {
        Method foo = TestMethodInvoke.class.getMethod("foo", int.class);
        for (int i = 1; i <= 17; i++) {
            show(i, foo);
            foo.invoke(null, i);
        }
        System.in.read();
    }

    // 方法反射调用时, 底层 MethodAccessor 的实现类
    private static void show(int i, Method foo) throws Exception {
        Method getMethodAccessor = Method.class.getDeclaredMethod("getMethodAccessor");
        getMethodAccessor.setAccessible(true);
        Object invoke = getMethodAccessor.invoke(foo);
        if (invoke == null) {
            System.out.println(i + ":" + null);
            return;
        }
        Field delegate = Class.forName("jdk.internal.reflect.DelegatingMethodAccessorImpl").getDeclaredField("delegate");
        delegate.setAccessible(true);
        System.out.println(i + ":" + delegate.get(invoke));
    }

    public static void foo(int i) {
        System.out.println(i + ":" + "foo");
    }
}

收获

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

演示2 - cglib 代理

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.io.IOException;
import java.lang.reflect.Method;

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

    public static void main(String[] args) throws IOException {
        Target target = new Target();

        //  public static Object create(Class type, Callback callback) 第二个参数 使用  MethodInterceptor extends Callback
        // cglib 生产的类型为目标类型的 子类型(方法重写) 目标方法&目标类不能是final类型的
        Target proxy = (Target)Enhancer.create(Target.class, new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
//                Object invoke = method.invoke(target, objects); // 用方法反射调用目标
                Object invoke = methodProxy.invoke(target, objects); // 没有用反射 - 推荐
//                Object invoke = methodProxy.invokeSuper(o, objects); // 没有用反射 需要代理
                System.out.println("after");
                return invoke;
            }
        });

        proxy.foo();
        System.out.println(proxy.getClass());
        System.in.read();
    }
}

arthas 获取运行时class

package a11;

import a11.CglibProxy;
import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibProxy$Target$$EnhancerByCGLIB$$f6222c24
extends CglibProxy.Target
implements Factory {
    // Method MethodProxy 重点
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$foo$0$Method;
    private static final MethodProxy CGLIB$foo$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class clazz = Class.forName("a11.CglibProxy$Target$$EnhancerByCGLIB$$f6222c24");
        Class clazz2 = Class.forName("java.lang.Object");
        Method[] methodArray = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());
        CGLIB$equals$1$Method = methodArray[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = methodArray[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = methodArray[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = methodArray[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        clazz2 = Class.forName("a11.CglibProxy$Target");
        CGLIB$foo$0$Method = ReflectUtils.findMethods(new String[]{"foo", "()V"}, clazz2.getDeclaredMethods())[0];
        CGLIB$foo$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "foo", "CGLIB$foo$0");
    }
    // 带原始功能的方法
    final void CGLIB$foo$0() {
        super.foo();
    }
    // 带增强功能的方法
    @Override
    final void foo() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$foo$0$Method, CGLIB$emptyArgs, CGLIB$foo$0$Proxy);
            return;
        }
        super.foo();
    }

    final boolean CGLIB$equals$1(Object object) {
        return super.equals(object);
    }

    public final boolean equals(Object object) {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object2 = methodInterceptor.intercept(this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);
            return object2 == null ? false : (Boolean)object2;
        }
        return super.equals(object);
    }

    final String CGLIB$toString$2() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            return (String)methodInterceptor.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);
        }
        return super.toString();
    }

    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return object == null ? 0 : ((Number)object).intValue();
        }
        return super.hashCode();
    }

    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            return methodInterceptor.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
        }
        return super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
        String string = ((Object)signature).toString();
        switch (string.hashCode()) {
            case -1268936465: {
                if (!string.equals("foo()V")) break;
                return CGLIB$foo$0$Proxy;
            }
            case -508378822: {
                if (!string.equals("clone()Ljava/lang/Object;")) break;
                return CGLIB$clone$4$Proxy;
            }
            case 1826985398: {
                if (!string.equals("equals(Ljava/lang/Object;)Z")) break;
                return CGLIB$equals$1$Proxy;
            }
            case 1913648695: {
                if (!string.equals("toString()Ljava/lang/String;")) break;
                return CGLIB$toString$2$Proxy;
            }
            case 1984935277: {
                if (!string.equals("hashCode()I")) break;
                return CGLIB$hashCode$3$Proxy;
            }
        }
        return null;
    }

    public CglibProxy$Target$$EnhancerByCGLIB$$f6222c24() {
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(cglibProxy$Target$$EnhancerByCGLIB$$f6222c24);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {
        CGLIB$THREAD_CALLBACKS.set(callbackArray);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {
        CGLIB$STATIC_CALLBACKS = callbackArray;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object object) {
        block2: {
            Object object2;
            block3: {
                CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = (CglibProxy$Target$$EnhancerByCGLIB$$f6222c24)object;
                if (cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BOUND) break block2;
                cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BOUND = true;
                object2 = CGLIB$THREAD_CALLBACKS.get();
                if (object2 != null) break block3;
                object2 = CGLIB$STATIC_CALLBACKS;
                if (CGLIB$STATIC_CALLBACKS == null) break block2;
            }
            cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])object2)[0];
        }
    }

    @Override
    public Object newInstance(Callback[] callbackArray) {
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
        return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    }

    @Override
    public Object newInstance(Callback callback) {
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
        return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    }

    @Override
    public Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        Class[] classArray2 = classArray;
        switch (classArray.length) {
            case 0: {
                cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
                break;
            }
            default: {
                throw new IllegalArgumentException("Constructor not found");
            }
        }
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
        return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    }

    @Override
    public Callback getCallback(int n) {
        MethodInterceptor methodInterceptor;
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
        switch (n) {
            case 0: {
                methodInterceptor = this.CGLIB$CALLBACK_0;
                break;
            }
            default: {
                methodInterceptor = null;
            }
        }
        return methodInterceptor;
    }

    @Override
    public void setCallback(int n, Callback callback) {
        switch (n) {
            case 0: {
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
                break;
            }
        }
    }

    @Override
    public Callback[] getCallbacks() {
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    @Override
    public void setCallbacks(Callback[] callbackArray) {
        Callback[] callbackArray2 = callbackArray;
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
    }

    static {
        CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$STATICHOOK1();
    }
}

15) jdk 和 cglib 在 Spring 中的统一

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

  • 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut(在哪些地方增强

  • 通知:典型接口为 MethodInterceptor 代表环绕通知(增强具体要做的事情)

  • 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut(哪个人 在哪个地方Pointcut 做什么事情Advice)

AOP 实现的几种方法 arthas工具分析_第5张图片

代理相关类图(代理工厂需要 目标类(Target) + 哪个人(Advisor)即可完成 代理者的创建(Proxy) 

  • AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现

  • AopProxy 通过 getProxy 创建代理对象

  • 图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)

  • 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor

//        1.未setInterfaces              未 setTargetClass CGLIB
//        2.setInterfaces               未 setTargetClass JDKProxy
//        3.                                    setTargetClass CGLIB

AOP 实现的几种方法 arthas工具分析_第6张图片

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");
        }
    }
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

public class Demo {
    public static void main(String[] args) {
        // 1.添加切入点 pointcut
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");

        // 2.添加通知Advice org.aopalliance.intercept.MethodInterceptor
        MethodInterceptor advice = invocation -> {
            System.out.println("before");
            Object proceed = invocation.proceed();  // 调用目标
            System.out.println("after");
            return proceed;
        };

        // 3.添加切面 Advisor !! 重要 反向查找就是找一下 advisor 下有 pointcut实现类 的类就可以了!!
        // DefaultPointcutAdvisor 与 AspectJExpressionPointcut 同属于 AbstractGenericPointcutAdvisor
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

        // 4. 创建代理
        A15.Target1 target = new A15.Target1();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(target.getClass().getInterfaces()); // 如果实现了接口必须setInterfaces ProxyFactory不会自动检测
//        proxyFactory.setTargetClass(target.getClass());             // proxyFactory.getProxy使用的 CGLIB 实现 返回类型需要改为 I1 的子类
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(advisor);
        A15.I1 proxy = (A15.I1)proxyFactory.getProxy();

        proxy.foo();
        System.out.println(proxy.getClass());
        // spring 代理的实现由两种 JDKProxy 与 CGLIB
//        1.未setInterfaces      未 setTargetClass CGLIB
//        2.setInterfaces       未 setTargetClass JDKProxy
//        3.                    setTargetClass CGLIB

    }
}

AOP 实现的几种方法 arthas工具分析_第7张图片

proxyFactory.setInterfaces(target.getClass().getInterfaces()); proxyFactory.setTargetClass(target.getClass());

AOP 实现的几种方法 arthas工具分析_第8张图片

切点匹配

PointCut 的重要属性 org.springframework.aop.MethodMatcher 检查目标方法是否有资格获得advice

AOP 实现的几种方法 arthas工具分析_第9张图片

        对使用了注解标注(对整个类型层次结构执行完整搜索,包括超类和实现的接口)的方法进行增强

	StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
		// 执行静态检查给定方法是否匹配
		@Override
		public boolean matches(Method method, Class targetClass) {
			// MergedAnnotations可以从任何 Java AnnotatedElement获得。
			// 可以使用不同的搜索策略来定位包含要聚合的注释的相关源元素。
			// 例如, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY将搜索超类和实现的接口。
			
			// 检查方法上是否加了 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));

17) 从 @Aspect 到 Advisor

代理创建器

代码参考

org.springframework.aop.framework.autoproxy

package org.springframework.aop.framework.autoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;

import java.util.List;

public class A17 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("aspect1", Aspect1.class);
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 属于 BeanPostProcessor  初始化回调前(通过标记接口等填充 bean) 初始化回调后(而使用代理包装 bean)
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        // BeanPostProcessor
        // 创建 -> (*) 依赖注入 -> 初始化 (*)

        context.refresh();
//        for (String name : context.getBeanDefinitionNames()) {
//            System.out.println(name);
//        }

        /*
            第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
                a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
                b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
         */
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List 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(new Target2("ss"));
        /*
            学到了什么
                a. 自动代理后处理器 AnnotationAwareAspectJAutoProxyCreator 会帮我们创建代理
                b. 通常代理创建的活在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行
                c. 高级的 @Aspect 切面会转换为低级的 Advisor 切面, 理解原理, 大道至简
         */
    }

    static class Target1 {


        public void foo(Target2 ss) {
            System.out.println("target1 foo");
        }
    }

    static class Target2 {
        public Target2() {
        }
        public Target2(String ss) {
            this.ss = ss;
        }

        @NonNull
        private String ss;

        public String getSs() {
            return ss;
        }

        public void setSs(String ss) {
            this.ss = ss;
        }

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

    @Aspect // 高级切面类
    @Order(2)
    static class Aspect1 {
        @AfterReturning("execution(* foo(*))")
        public void before1(JoinPoint joinPoint) {
            System.out.println("aspect1 before1..." + (MethodInvocation)joinPoint);
        }

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

    @Configuration
    static class Config {
        @Bean // 低级切面
//        @Order(1) p配置在此地方不生效
        public Advisor advisor3(MethodInterceptor advice3) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
            advisor.setOrder(1);
            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. AnnotationAwareAspectJAutoProxyCreator 的作用

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

    • 在合适的时机创建代理

  2. findEligibleAdvisors 找到有【资格】的 Advisors

    • 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 A17 中的 advisor3

    • 有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得

  3. wrapIfNecessary

    • 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理

    • 它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行

演示2 - 代理创建时机

代码参考

org.springframework.aop.framework.autoproxy.A17_1

    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()");
        }
    }

 // 循环依赖演示 注意 “Creating implicit proxy for bean 'bean1'”意思是增强了

AOP 实现的几种方法 arthas工具分析_第10张图片

 // 无循环依赖 Bean2 setBean1依赖注入Bean1 代理($Bean1)增强后($$EnhancerBySpringCGLIB)的对象

 // 工厂方法配置

    @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();
        }
    }

// 主方法调用

    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. 依赖注入与初始化不应该被增强, 仍应被施加于原始对象
         */
    }

收获??

创建 -> (1.2) 依赖注入 -> 初始化 (1.1)

  1. 代理的创建时机

    • 初始化之后 (无循环依赖时)

    • 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存

  2. 依赖注入与初始化不应该被增强, 仍 应被施加于原始对象

@Order 、@Priority 与 org.springframework.core.Ordered

基础的应用场景是 配置类中(标注了@Aspect注解的多个类 声明了多个切面 默认的执行顺序是Bean注册的顺序),但我想自定义 切面拦截的顺序。

1.定义@Aspect类(高级切面类)的顺序 使用 @Order注解

AOP 实现的几种方法 arthas工具分析_第11张图片        @Order 放在类上可以生效。org.aspectj.lang.annotation类下面的注解不是@Bean的子类。所以不能定义拦截的顺序。

 

2.定义@Configuration (低级切面方法)的顺序。

对于实现了org.springframework.core.Ordered接口的来来说。配置此类的order属性即可。

AOP 实现的几种方法 arthas工具分析_第12张图片

 

AOP 实现的几种方法 arthas工具分析_第13张图片

 

你可能感兴趣的:(Spring4.0,AspectJ,java,spring,jvm)