java动态代理

代理

首先,代理是一种设计模式,是行为型设计模式中的一个,其思想是修改原来的行为,但是对外暴露的方式不变,比如网络代理。 UML图如下:
java动态代理_第1张图片

代理中的角色有:抽象接口、委托类、代理类。
根据代理类产生的方式和时期不同,分为静态代理和动态代理。
静态代理直接在代码编写阶段完成,所以叫做静态代理。动态代理是在运行时生成,所以叫动态代理。

静态代理

这里静态的意思是代理类代码是手工编写的,在java文件时已经确定了,流程如下:
java动态代理_第2张图片

动态代理

静态代理问题是他是静态的,必须实现写好代码。但是如果现在有个订单系统,对订单操作需要防并发,我就要在每个订单操作的方法中添加防并发代码。这时,动态代理就可以派上用场了,我不修改代码,只要写好防并发的代码,在运行时动态生成最终的代码。
动态代理的流程如下:
java动态代理_第3张图片

动态代理有两种,分别是JDK动态代理和Cglib代理。
他们的区别知道是两点:

类型 原理 适用范围
JDK动态代理 反射 接口
Cglib 字节码改写

JDK动态代理

JDK动态代理,是JDK自带的,主要有两个类:Proxy类(用于生成代理类),InvocationHandler类(用于实现改写的逻辑)。
代码如下:

public class DynamicProxyJdk {
    public static void main(String[] args) throws IOException {
        ICalculator calculatorImpl = new ICalculator() {
            @Override
            public int add(int n1, int n2) {
                System.out.println("开始计算加法");

                return n1 + n2;
            }
        };

        ICalculator calculatorProxy =  (ICalculator) getProxy(calculatorImpl);
        System.out.println(calculatorProxy.getClass());
        int sumNum = calculatorProxy.add(1, 2);
        System.out.println("计算结果:" + sumNum);

        System.in.read();
    }

    public static Object getProxy(Object target){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理开始");
                        Object result = method.invoke(target, args);
                        System.out.println("代理结束");

                        return result;
                    }
                });
    }

    public interface ICalculator{
        int add(int n1, int n2);
    }
}

通过arthas,反编译出代理类,如下:

package com.sun.proxy;

import com.zx.java.reflect.proxy.DynamicProxyJdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
extends Proxy
implements DynamicProxyJdk.ICalculator {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    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("com.zx.java.reflect.proxy.DynamicProxyJdk$ICalculator").getMethod("add", Integer.TYPE, Integer.TYPE);
            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());
        }
    }

    public final int add(int n, int n2) {
        try {
            return (Integer)this.h.invoke(this, m3, new Object[]{n, n2});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    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 hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

可以看到,反射出来的代理类,继承Proxy(提供了修改的方法以及而额外的方法)以及委托类接口(提供了类信息)。

Cglib

Cglib(Code Generation Library)是一个功能强大、高性能的代码生成包。

贴代码。

public class CglibMethodInterceptor implements MethodInterceptor {
    public static void main(String[] args) throws IOException {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Calculator.class);
        enhancer.setCallback(new CglibMethodInterceptor());
        Calculator calculatorProxy = (Calculator) enhancer.create();
        System.out.println("计算结果:" +  calculatorProxy.add(1, 2));
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("intercept start");

        Object result = methodProxy.invokeSuper(o, objects);

        System.out.println("intercept end");

        return result;
    }

    public class Calculator {
      public int add(int n1, int n2){
          System.out.println("开始计算");

          return n1 + n2;
      }
    }
}

结果:

intercept start
开始计算
intercept end
计算结果:3

代理类的源代码如下:

public class Calculator$$EnhancerByCGLIB$$c5a6599b
extends Calculator
implements Factory {
    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$add$0$Method;
    private static final MethodProxy CGLIB$add$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;

    public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
        String string = ((Object)signature).toString();
        switch (string.hashCode()) {
            case -1287932281: {
                if (!string.equals("add(II)I")) break;
                return CGLIB$add$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 void setCallback(int n, Callback callback) {
        switch (n) {
            case 0: {
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
                break;
            }
        }
    }

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

    final int CGLIB$add$0(int n, int n2) {
        return super.add(n, n2);
    }

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class clazz = Class.forName("com.zx.java.reflect.proxy.base.Calculator$$EnhancerByCGLIB$$c5a6599b");
        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("com.zx.java.reflect.proxy.base.Calculator");
        CGLIB$add$0$Method = ReflectUtils.findMethods(new String[]{"add", "(II)I"}, clazz2.getDeclaredMethods())[0];
        CGLIB$add$0$Proxy = MethodProxy.create(clazz2, clazz, "(II)I", "add", "CGLIB$add$0");
    }

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

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

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

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

    public void setCallbacks(Callback[] callbackArray) {
        Callback[] callbackArray2 = callbackArray;
        Calculator$$EnhancerByCGLIB$$c5a6599b calculator$$EnhancerByCGLIB$$c5a6599b = this;
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
    }

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

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

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

    public Callback[] getCallbacks() {
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$BIND_CALLBACKS(this);
        Calculator$$EnhancerByCGLIB$$c5a6599b calculator$$EnhancerByCGLIB$$c5a6599b = this;
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public Calculator$$EnhancerByCGLIB$$c5a6599b() {
        Calculator$$EnhancerByCGLIB$$c5a6599b calculator$$EnhancerByCGLIB$$c5a6599b = this;
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$BIND_CALLBACKS(calculator$$EnhancerByCGLIB$$c5a6599b);
    }

    static {
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$STATICHOOK1();
    }

    public final int add(int n, int n2) {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$BIND_CALLBACKS(this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        if (methodInterceptor != null) {
            Object object = methodInterceptor.intercept(this, CGLIB$add$0$Method, new Object[]{new Integer(n), new Integer(n2)}, CGLIB$add$0$Proxy);
            return object == null ? 0 : ((Number)object).intValue();
        }
        return super.add(n, n2);
    }

    public final boolean equals(Object object) {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Calculator$$EnhancerByCGLIB$$c5a6599b.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);
    }

    public final String toString() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Calculator$$EnhancerByCGLIB$$c5a6599b.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();
    }

    public final int hashCode() {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Calculator$$EnhancerByCGLIB$$c5a6599b.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();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            Calculator$$EnhancerByCGLIB$$c5a6599b.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 Object newInstance(Callback[] callbackArray) {
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        Calculator$$EnhancerByCGLIB$$c5a6599b calculator$$EnhancerByCGLIB$$c5a6599b = new Calculator$$EnhancerByCGLIB$$c5a6599b();
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$SET_THREAD_CALLBACKS(null);
        return calculator$$EnhancerByCGLIB$$c5a6599b;
    }

    public Object newInstance(Callback callback) {
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
        Calculator$$EnhancerByCGLIB$$c5a6599b calculator$$EnhancerByCGLIB$$c5a6599b = new Calculator$$EnhancerByCGLIB$$c5a6599b();
        Calculator$$EnhancerByCGLIB$$c5a6599b.CGLIB$SET_THREAD_CALLBACKS(null);
        return calculator$$EnhancerByCGLIB$$c5a6599b;
    }

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

可以看到也是继承委托类。

Spring aop

spring aop,如果是接口使用JDK动态代理,如果是类则使用Cglib。
相对应的概念:

切点:委托类
切面:代理类

你可能感兴趣的:(java)