美文网首页
Spring Aop 详解

Spring Aop 详解

作者: Aaron_Swartz | 来源:发表于2019-10-08 00:50 被阅读0次
  • Spring Aop 应用

常用的场景包括记录日志、异常处理、性能监控、安全控制(例如拦截器)等,总结起来就是,凡是想对当前功能做变更,但是又不想修改源代码的情况下,都可以考虑是否可以用 AOP 实现。

  • 总体设计原理
    参考 1

  • java 动态代理机制详解


    java字节码
  • JdkDynamicAopProxy源码分析
    参考2

  • 动态代理

在java的动态代理机制中有两个重要的类或者接口,InvocationHandler(Interface)、另一个则是 Proxy(Class)。

InvocationHandler: 每一个动态代理类都必须要实现该接口,并且每个代理类的实例都关联到了一个handler,当最后通过代理对象调用一个方法的时候,这个方法的调用最终会被转发为InvocationHandler的invoke方法

// proxy: 我们所代理的真实对象  method:我们所要调用的真实对象的方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable

Proxy: 这个类的作用就是用来动态的创建一个代理对象的类,其中用的最多的方法就是newProxyInstance 方法。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

下来会展示一个实例,具体参见 5

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), 
realSubject.getClass().getInterfaces(), handler);

具体对这个代码做一个解释:该方法调用Proxy.newProxyInstance 方法,传入handler的类加载器、真实目标访问对象的接口、handler。返回的是一个com.sun.proxy.$Proxy0, 这个对象是JVM 在运行时生成的代理对象,该对象实现Subject的接口,但是该对象是一个新的类的实例。反编译(如何获取查看参考4)后类内容如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import test.annotation.aspect.Subject;

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void rent() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void hello(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m4 = Class.forName("test.annotation.aspect.Subject").getMethod("rent", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("test.annotation.aspect.Subject").getMethod("hello", new Class[]{Class.forName("java.lang.String")});
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看到,该类是Proxy的子类,并且实现Subject接口,并且实现了Subject中的方法。***在调用$Proxy0类的方法时,实际上调用的还是handler中的方法。

  • 部分Proxy类
public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }

    /**
     * Constructs a new {@code Proxy} instance from a subclass
     * (typically, a dynamic proxy class) with the specified value
     * for its invocation handler.
     *
     * @param  h the invocation handler for this proxy instance
     *
     * @throws NullPointerException if the given invocation handler, {@code h},
     *         is {@code null}.
     */
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }
JDK动态代理流程
  • JDK动态代理小结

比如现在想为RealSubject这个类创建一个动态代理对象,JDK主要会做以下工作:
1 获取 RealSubject上的所有接口列表;
2 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;
3 根据需要实现的接口信息,在代码中动态创建 该Proxy类的字节码;
4 将对应的字节码转换为对应的class 对象;
5 创建InvocationHandler 实例handler,用来处理Proxy所有方法调用;
6 Proxy 的class对象 以创建的handler对象为参数,实例化一个proxy对象

  • cglib 生成动态代理类的机制----通过类继承
    具体参见 6

  • Spring Aop 和动态代理的关系
    参考7

  • 关于Spring Aop拦截器的回调
    参考 8

参考:
1 Spring AOP设计原理
2 JdkDynamicAopProxy 源码分析
3 java如何查看jvm中动态代理class类内容
4 JDK动态代理文件$Proxy0.class的生成和查看
5 深入理解Java反射+动态代理
6 Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
7 Spring AOP 和 动态代理技术
8 Spring AOP原理之拦截器调用的实现

相关文章

网友评论

      本文标题:Spring Aop 详解

      本文链接:https://www.haomeiwen.com/subject/sctvpctx.html