java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java动态代理

Java中的动态代理使用

作者:让你三行代码QAQ

这篇文章主要介绍了Java中的动态代理使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

动态代理

动态代理的时候,定义一个接口,需要代理人和被代理类实现这个接口,这样不够灵活,代理类能够代理的类只有实现这个接口的类。

非常不灵活,假如被代理人的类没有实现这个接口,那么就需重新写一个代理类。对于日志、事务这些操作是不区分业务的,即不需要规定都实现某接口。因此,出现了动态代理

java种的动态代理生成的方式大概有三种JDK动态代理、instrument动态代理、cglib动态代理。其中,前两种是JDK自带的,cglib是需要第三方依赖使用的。

JDK动态代理

先看这样一个程序

/** 接口*/
public interface Mobile {
    void move();
}
/** 被代理类*/
public class Car implements Mobile{
    @Override
    public void move() {
        System.out.println("move...");
    }
}
/** 使用动态代理*/
public class Test {
    public static void main(String[] args) {
        Car car = new Car();
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles",true);
        Mobile proxyInstance = (Mobile) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(),  new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long before = System.currentTimeMillis();
                System.out.println(method.getName()+"方法被执行前。。。");
                Object invoke = method.invoke(car, args);
                System.out.println(method.getName()+"方法被执行后。。。");
                long after = System.currentTimeMillis();
                System.out.println("耗时:" + (after - before));
                return null;
            }
        });

        proxyInstance.move();
    }
}

创建代理类需要调用Proxy.newProxyInstance()方法,其中有三个参数

可以把动态代理的创建改成这样:自己写一个类实现InvocationHandler。

public class Test {
    public static void main(String[] args) {
        Car car = new Car();
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        Mobile proxyInstance = (Mobile) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(), new MyInvocationHandler(car));
        proxyInstance.move();
    }

}
class MyInvocationHandler implements InvocationHandler{
    private Car car;

    public MyInvocationHandler(Car car) {
        this.car = car;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long before = System.currentTimeMillis();
        System.out.println(method.getName()+"方法被执行前。。。");
        Object invoke = method.invoke(car, args);
        System.out.println(method.getName()+"方法被执行后。。。");
        long after = System.currentTimeMillis();
        System.out.println("耗时:" + (after - before));
        return null;
    }
}

要想搞懂JDK动态代理必须查看动态生成代理类,通过设置JDK动态代理生成的类是否保存的一个属性将生成的代理类保存下来,通过在程序启动前加上: 

System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles",true);

代理类的调用过程

public final class $Proxy0 extends Proxy implements Mobile {
    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 move() 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.shaoby.basic.proxy.JdkProxy.Mobile").getMethod("move");
            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());
        }
    }
}

Method类

这个类是一个方法的类,说白了就是方法的模板,在这个类中有一个方法invoke,传入两个参数,一个是调用方法的对象,另一个是方法的入参

InvocationHandler中的invoke方法

可以看到在代理类中invoke方法的调用为 super.h.invoke(this, m3, (Object[])null);

MyInvocationHandler中的invoke方法:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long before = System.currentTimeMillis();
        System.out.println(method.getName()+"方法被执行前。。。");
        Object invoke = method.invoke(car, args);
        System.out.println(method.getName()+"方法被执行后。。。");
        long after = System.currentTimeMillis();
        System.out.println("耗时:" + (after - before));
        return null;
    }

参数:

返回值:

这个返回值其实是被代理方法的返回值,如果没有返回值就返回null;

这里最重要的是method.invoke(car, args),就是用car对象调用move方法。

ASM

在上述分析中,动态代理类的构造方法中参数是我们猜测的。其实这里是用ASM实现的。在生成代理类时调用的Proxy.newInstance()传入了InvocationHandler接口的实现类,Proxy.neInstance()会动态的生成代理类,并产生一个代理对象。这里后续再研究。

ASM是Java字节码操控框架,它能够以二进制形式修改已有类,或动态生成类,ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

cglib动态代理

public class Test {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Plane.class);
        enhancer.setCallback(new MyMethodInterceptor());
        Plane o = (Plane)enhancer.create();
        o.move();


    }
}
class MyMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        long before = System.currentTimeMillis();
        System.out.println(method.getName()+"方法被执行前。。。");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println(method.getName()+"方法被执行后。。。");
        long after = System.currentTimeMillis();
        System.out.println("耗时:" + (after - before));
        return result;
    }
}

cglib动态代理的原理是:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文