Java 动态代理

概述

 

什么是动态代理

  • 使用 JDK 的反射机制,创建对象的能力, 创建的是代理类的对象,不用自己创建类文件,不用写 Java 文件。
  • 动态:在程序执行时,调用 JDK 提供的方法才能创建代理类的对象。
  • JDK 动态代理,必须有接口,目标类必须实现接口,没有接口时,需要使用 cglib 动态代理。

动态代理能做什么

  • 可以在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码。

动态代理性能怎么样

  • 每 100 次动态代理调用,相比原生调用,慢 1 毫秒,性能损耗基本可以忽略不计(JDK8)。

原理

  实质上是通过传入的 Class<?>[] interfaces 参数,JDK 会实现一个代理类对象,该对象包装了所有接口函数,函数内不都是将方法调用,转调到了 InvocationHandler 类的 invoke。JDK 会生成代理类的字节码 byte[],并自动通过给定的 Classloader 加载进虚拟机,从而避免手动写代理类的麻烦,函数增强部分,开发人员可以写在 InvocationHandler.invoke 里。

 

简单示例

public interface Shape {
    String getName();
}
public class Square implements Shape { @Override public String getName() { return "方形"; } } public class Cycle implements Shape { @Override public String getName() { return "圆形"; } }
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DemoInvocationHandler implements InvocationHandler {

    private Object target;

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

    /**
     * 获取动态代理对象
     *
     * @param target
     * @return
     */
    public static Object dynamicProxy(final Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new DemoInvocationHandler(target)
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("==> 方法执行前");
        Object result = method.invoke(this.target);
        System.out.println("  执行结果: " + result);
        System.out.println("<== 方法执行后");
        return result;
    }

}
/**
 * JDK 动态代理,调用100次,比原生方法调用慢了不到1毫秒
 * System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
 */
public class JDKDynamicProxyTest {
    public static void main(String[] args) {
        Shape shape = (Shape) DemoInvocationHandler.dynamicProxy(new Cycle());
        shape.getName();
    }
}

 执行结果:

==> 方法执行前
  执行结果: 圆形
<== 方法执行后

 源码:

 

 

 

 

生成出来的字节码文件:我们发现代理类其实就是一层很薄的封装,所有方法调用都委托给了 InvocationHandler 实现类的 invoke 方法。

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 Shape {
    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 String getName() throws  {
        try {
            return (String)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.asiainfo.crm.xxx.service.Shape").getMethod("getName");
            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());
        }
    }
}

 我们完全可以直接调用 ProxyGenerator.generateProxyClass() 讲动态代理类生成出来:

public class JDKDynamicProxyTest {
    public static void main(String[] args) throws IOException {
        byte[] data = ProxyGenerator.generateProxyClass("$Proxy9", new Cycle().getClass().getInterfaces(), Modifier.PUBLIC | Modifier.FINAL);
        FileCopyUtils.copy(data, new File("C:\\Users\\21550\\Desktop\\$Proxy9.class"));
    }
}

 

posted @ 2022-12-07 15:40  Steven.Chow  阅读(142)  评论(0编辑  收藏  举报