AOP基础——JDK动态代理

1.JDK动态代理原理

代理模式则是通过创建代理类(proxy)的方式来访问服务,代理类通常会持有一个委托类对象,代理类不会自己实现真正服务,而是通过调用委托类对象的相关方法,来提供服务,所以其实我们调用的还是委托类的服务,但是中间隔了一个代理类。这么做是有好处的,我们可以在访问服务之前或者之后加一下我们需要的操作。例如Spring的面向切面编程,我们可以在切入点之前执行一些操作,切入点之后执行一些操作。这个切入点就是一个个方法。

静态代理就是程序员在编写代码的时候就已经把代理类的源码写好了,编译后就会生成.class文件。
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。

代理类在程序运行时创建的代理方式被成为动态代理。在静态代理中,代理类是自己已经定义好了的,在程序运行之前就已经编译完成。而动态代理是在运行时根据我们在Java代码中的“指示”动态生成的。动态代理相较于静态代理的优势在于可以很方便的对代理类的所有函数进行统一管理,如果我们想在每个代理方法前都加一个方法,如果代理方法很多,我们需要在每个代理方法都要写一遍,很麻烦。而动态代理则不需要。

public interface Animal {
    void eat();
}

public class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("猫猫 吃 猫粮!");
    }
}



public class Main {
    public static void main(String[] args) {
        //1. 创建目标对象
        Cat cat = new Cat();
        cat.eat();
        System.out.println("-----------------------------------------");

        //2. 创建JdkDynamicProxy 对象
        JdkDynamicProxy dynamicProxy = new JdkDynamicProxy(cat);

        //3. 获取代理之后的对象
        Animal proxy = (Animal) dynamicProxy.getProxy();
        proxy.eat();
    }
}

核心是InvocationHandler :

public class JdkDynamicProxy implements InvocationHandler {

    /**
     * 被代理对象
     */
    private Object target;

    public JdkDynamicProxy(Object target) {
        this.target = target;
    }


    /**
     * @param proxy 代理对象,代理了target,代理对象内部持有target对象!
     * @param method 被代理对象的方法
     * @param args 被代理对象方法的入参
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //需求:打印出来Animal 吃饭开始时间 和 结束时间
        System.out.println("开始时间:" + System.currentTimeMillis());
        Object ret = method.invoke(target, args);
        System.out.println("结束时间:" + System.currentTimeMillis());
        return ret;
    }

    /**
     * 返回代理之后的对象
     */
    public Object getProxy() {
        //参数一:类加载器
        //参数二:代理类 需要 实现的接口集合
        //参数三:代理类虽然全部实现了 接口方法,但是接口方法 要依靠 InvocationHandler 去处理。
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}

运行结果:

猫猫 吃 猫粮!
-----------------------------------------
开始时间:1670663462575
猫猫 吃 猫粮!
结束时间:1670663462576

1.1 Proxy#newProxyInstance源码

    //参数一:类加载器
    //参数二:代理类 需要 实现的接口集合
    //参数三:代理类虽然全部实现了 接口方法,但是接口方法 要依靠 InvocationHandler 去处理。
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
        final Class[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */

        //生成代理Class类型,参数2  代理需要实现的接口
        Class cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //获取 代理类 的构造方法,选择 参数为 InvocationHandler 类型的构造方法。
            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //cons 就是 代理类的构造方法,这一步完事之后,就创建出来了代理对象,并且代理对象内部持有 InvocationHandler
            //代理对象 必须得有 target 目标对象!
            //貌似没有传递Target? 其实已经传递了,InvocationHandler 它里面有target !
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
    private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }
    private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

1.2 ProxyClassFactory

    private static final class ProxyClassFactory
        implements BiFunction[], Class>
    {
        // prefix for all proxy class names
        // 代理类型名称前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        // 生成唯一数字使用,结合上面 代理类型名称前缀 一起生成 代理类名称 使用的。
        private static final AtomicLong nextUniqueNumber = new AtomicLong();


        /**
         * @param loader Proxy.newInstance时传递的
         * @param interfaces Proxy.newInstance时传递的 接口集合。
         */
        @Override
        public Class apply(ClassLoader loader, Class[] interfaces) {

            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);


            for (Class intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class interfaceClass = null;
                try {
                    //加载接口到jvm
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                //保证 interfaces 接口集合内 全部都是接口
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                //保证 interfaces 接口集合内 没有重复接口
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            // 生成的代理类 它的包名!
            String proxyPkg = null;     // package to define proxy class in
            // 生成的代理类 访问修饰符:public final ....
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            //检查接口集合内的接口,看看有没有 某个接口 它的访问修饰符 不是 public 的!
            //如果有哪个 不是public 的接口,那么咱们生成 代理类 class 就必须 和它在一个包下,否则会出现访问问题。
            for (Class intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    //获取 当前接口的 全限定名!  包名.类名
                    String name = intf.getName();

                    int n = name.lastIndexOf('.');
                    //获取当前接口包名
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }


            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            //获取唯一编号
            long num = nextUniqueNumber.getAndIncrement();
            //包名 + $proxy + 数字
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            //生成二进制字节码,这个字节码写入到文件内 ,它就是一个编译好的 class文件。
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

            try {
                // 使用加载器 加载这个 二进制 字节码 到 jvm,并且返回 代理类 Class
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

1.3 生成的代理类

可以看到代理类的所有方法最终都是调用InvocationHandler的invoke()方法。

如下就是代理类:

public final class $proxy0 extends Proxy implements Animal {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    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});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void eat() throws  {
        try {
            super.h.invoke(this, m3, (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 int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.wz.utils.aop.demo01.Animal").getMethod("eat");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

2.层层嵌套式的动态代理

public class Main {
    public static void main(String[] args) {
        //1. 第一步 创建目标对象,被代理对象
        Cat cat = new Cat();

        cat.eat();
        System.out.println("---------------------");

        //2. 第一次代理,需要 JdkDynamicProxy
        JdkDynamicProxy dynamicProxy01 = new JdkDynamicProxy(cat);
        // 只被代理了 一层 的 代理对象。
        Animal proxy01 = (Animal) dynamicProxy01.getProxy();

        proxy01.eat();

        System.out.println("---------------------");

        //3. 第二次代理,需要 JdkDynamicProxy02 + proxy01
        JdkDynamicProxy2 dynamicProxy02 = new JdkDynamicProxy2(proxy01);

        Animal proxy02 = (Animal) dynamicProxy02.getProxy();

        proxy02.eat();

    }
}

3.使用责任链模式,dummy头节点

执行链条:
$Proxy#eat
-> InvocationHandler#invoke 也即 JdkDynamicProxy#invoke
-> headHandler#proceed
-> OneHandler#invoke
-> OneHandler#proceed
-> TwoHandler#invoke
-> TwoHandler#proceed
-> Cat#eat

public class Main {
    public static void main(String[] args) {
        //1. 创建被代理对象
        Cat cat = new Cat();

        //2. 创建一个责任链
        AbstractHandler headHandler = new AbstractHandler.HeadHandler();
        OneHandler one = new OneHandler();
        one.setNextHandler(new TwoHandler());
        headHandler.setNextHandler(one);

        //3. 先创建 jdkdynamicproxy 对象
        JdkDynamicProxy dynamicProxy = new JdkDynamicProxy(cat, headHandler);

        //4. 获取代理对象
        Animal proxy = (Animal) dynamicProxy.getProxy();

        proxy.eat();
    }

    public static class OneHandler extends AbstractHandler {
        Object invoke(TargetMethod targetMethod) throws Throwable {
            System.out.println("one handler begin");
            Object ret = proceed(targetMethod);
            System.out.println("one handler end");
            return ret;
        }
    }

    public static class TwoHandler extends AbstractHandler {
        Object invoke(TargetMethod targetMethod) throws Throwable {
            System.out.println("two handler begin");
            Object ret = proceed(targetMethod);
            System.out.println("two handler end");
            return ret;
        }
    }
}
public class JdkDynamicProxy implements InvocationHandler {

    /**
     * 被代理对象
     */
    private Object target;

    /**
     * 责任链 头结点
     */
    private AbstractHandler headHandler;

    public JdkDynamicProxy(Object target, AbstractHandler headHandler) {
        this.target = target;
        this.headHandler = headHandler;
    }


    /**
     * @param proxy 代理对象,代理了target,代理对象内部持有target对象!
     * @param method 被代理对象的方法
     * @param args 被代理对象方法的入参
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        TargetMethod targetMethod = new TargetMethod();
        targetMethod.setTarget(target);
        targetMethod.setMethod(method);
        targetMethod.setArgs(args);
        return headHandler.proceed(targetMethod);
    }

    /**
     * 返回代理之后的对象
     */
    public Object getProxy() {
        //参数一:类加载器
        //参数二:代理类 需要 实现的接口集合
        //参数三:代理类虽然全部实现了 接口方法,但是接口方法 要依靠 InvocationHandler 去处理。
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}

public abstract class AbstractHandler {
    /**
     * 责任链 下一个 处理单元
     */
    private AbstractHandler nextHandler;

    public void setNextHandler(AbstractHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    abstract Object invoke(TargetMethod targetMethod) throws Throwable;


    public Object proceed(TargetMethod targetMethod) throws Throwable {
        if(!hasNext()) {
            return targetMethod.getMethod().invoke(targetMethod.getTarget(), targetMethod.getArgs());
        }

        return nextHandler.invoke(targetMethod);
    }


    public boolean hasNext() {
        if(nextHandler != null) {
            return true;
        }
        return false;
    }


    public static class HeadHandler extends AbstractHandler {

        Object invoke(TargetMethod targetMethod) {
            return null;
        }
    }


}

4.使用责任链模式,Interceptor链表

执行链条:
$Proxy#eat
-> InvocationHandler#invoke 也即 JdkDynamicProxy#invoke
-> MyMethodInvocationImpl#proceed
-> interceptorList[0].invoke(this也即MyMethodInvocationImpl) 也即OneMethodInterceptor#invoke
-> MyMethodInvocationImpl#proceed
-> interceptorList[1].invoke(this也即MyMethodInvocationImpl) 也即TwoMethodInterceptor#invoke
-> MyMethodInvocationImpl#proceed
-> Cat#eat

这里核心是将interceptor.invoke(this)时,将this也即MyMethodInvocationImpl传给Interceptor了。

public class Main {
    public static void main(String[] args) {
        //1. 创建目标对象,被代理对象
        Cat cat = new Cat();
        //2. 创建JdkDynamicProxy ,用来创建代理对象
        JdkDynamicProxy dynamicProxy = new JdkDynamicProxy(cat);
        //3. 咱们的目的是 使用 方法拦截器,去增强方法!
        dynamicProxy.addInterceptor(new OneMethodInterceptor());
        dynamicProxy.addInterceptor(new TwoMethodInterceptor());

        //4. 获取代理对象!
        Animal proxy = (Animal) dynamicProxy.getProxy();


        proxy.eat();
    }
}
public class JdkDynamicProxy implements InvocationHandler {

    /**
     * 被代理对象
     */
    private Object target;

    /**
     * 方法拦截器列表
     */
    private List interceptorList = new ArrayList<>();

    public JdkDynamicProxy(Object target) {
        this.target = target;
    }

    public void addInterceptor(MyMethodInterceptor interceptor) {
        interceptorList.add(interceptor);
    }


    /**
     * @param proxy 代理对象,代理了target,代理对象内部持有target对象!
     * @param method 被代理对象的方法
     * @param args 被代理对象方法的入参
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        TargetMethod targetMethod = new TargetMethod();
        targetMethod.setTarget(target);
        targetMethod.setMethod(method);
        targetMethod.setArgs(args);

        MyMethodInvocation methodInvocation = new MyMethodInvocationImpl(targetMethod, interceptorList);
        return methodInvocation.proceed();
    }

    /**
     * 返回代理之后的对象
     */
    public Object getProxy() {
        //参数一:类加载器
        //参数二:代理类 需要 实现的接口集合
        //参数三:代理类虽然全部实现了 接口方法,但是接口方法 要依靠 InvocationHandler 去处理。
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}


public interface MyMethodInterceptor {
    /**
     * 方法拦截器接口,增强逻辑,全部写在里面
     */
    Object invoke(MyMethodInvocation methodInvocation) throws Throwable;
}

public interface MyMethodInvocation {

    /**
     * 驱动拦截器链,执行增强逻辑 + 被代理方法调用
     */
    Object proceed() throws Throwable;
}


public class MyMethodInvocationImpl implements MyMethodInvocation {

    private TargetMethod targetMethod;

    private List interceptorList;

    private int index = 0;


    public Object proceed() throws Throwable {
        //拦截器全部执行完毕,接下来需要执行被代理接口方法!
        if(index == interceptorList.size()) {
            return targetMethod.getMethod().invoke(targetMethod.getTarget(), targetMethod.getArgs());
        }

        //到这里,说明还有拦截器 未执行呢
        MyMethodInterceptor interceptor = interceptorList.get(index ++);

        return interceptor.invoke(this);
    }

    public void setInterceptorList(List interceptorList) {
        this.interceptorList = interceptorList;
    }

    public MyMethodInvocationImpl(TargetMethod targetMethod, List interceptorList) {
        this.targetMethod = targetMethod;
        this.interceptorList = interceptorList;
    }
}

public class OneMethodInterceptor implements MyMethodInterceptor {
    public Object invoke(MyMethodInvocation methodInvocation) throws Throwable {
        System.out.println("one interceptor begin");
        Object ret = methodInvocation.proceed();
        System.out.println("one interceptor end");
        return ret;
    }
}

public class TwoMethodInterceptor implements MyMethodInterceptor {

    public Object invoke(MyMethodInvocation methodInvocation) throws Throwable {
        System.out.println("two interceptor begin");
        Object ret = methodInvocation.proceed();
        System.out.println("two interceptor end");
        return ret;
    }
}

你可能感兴趣的:(AOP基础——JDK动态代理)