Java

动态代理实战

2021-06-27  本文已影响0人  奔跑吧李博

动态代理它可以直接给某一个目标(被代理 对象)对象(实现了某个或者某些接口)生成一个代理对象,而不需要代理类存在。
动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。

jdk中的动态代理

1、Java.lang.reflect.Proxy类可以直接生成一个代理对象

Proxy.newProxyInstance方法参数介绍

ClassLoader:类加载器
它是用来加载器的,把.class文件加载到内存,形成Class对象!
Class[] interfaces:指定要实现的接口们
InvocationHandler:代理对象的所有方法(个别不执行,getClass())都会调用InvocationHandler的invoke()方法。

2、InvocationHandler方法参数介绍

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

这个invoke()方法在什么时候被调用!在调用代理对象所实现接口中的方法时

Object proxy:当前对象,即代理对象!在调用谁的方法!
Method method:当前被调用的方法(目标方法)
Object[] args:实参!

示例一:

Customer类为需要打官司的顾客,Lawyer为律师类,Lawyer类需要代理Customer打官司。

定义代理类与目标类共同的接口:

interface Law {
    //定义一个打官司的接口,需要实现打官司
    void law();
}

被代理类:某个客户需要打官司

class Customer implements Law {

    @Override
    public void law() {
        System.out.println("上法庭陈述事实");
    }
}

创建实现动态代理的MyHandler类,实现InvocationHandler接口和invoke方法。

/**
 * 实现动态代理的核心接口,动态代理本质采用的java反射机制实现
 */
class MyHandler implements InvocationHandler {
    private Customer  customer;

    public MyHandler(Customer customer) {
        this.customer = customer;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("搜集证据");
        Object obj = method.invoke(customer, args);  //使用反射调用customer中的method方法
        System.out.println("打赢官司");
        return obj;
    }
}

执行测试:

    public static void main(String[] args) {

        //代理目标对象
        Customer customer = new Customer();
        //代理回调类
        MyHandler myHandler = new MyHandler(customer);
        //生成代理对象Proxy通过调用newProxyInstance方法生成代理对象,传入该类的classLoader,实现接口,InvocationHandler
        Law proxy = (Law) Proxy.newProxyInstance(Customer.class.getClassLoader(), customer.getClass().getInterfaces(), myHandler);
        proxy.law();
    }

调用结果:

示例二:

定义代理类与目标类共同的接口:

public interface HelloInterface {
    void sayHello();
}

被代理类:

class Hello implements HelloInterface {
    @Override
    public void sayHello() {
        System.out.println("这里是被代理类Hello");
    }
}

创建实现动态代理的ProxyHandler类,实现InvocationHandler接口和invoke方法。

class ProxyHandler implements InvocationHandler {
    private Object object;

    //需要传入Object类型,任意类型
    public ProxyHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //invoke中使用反射调用传入的被代理对象的方法
        System.out.println("before invoke" + method.getName());
        method.invoke(object, args);
        System.out.println("after invoke" + method.getName());
        return null;
    }
}

执行测试:

    public static void main(String[] args) {
        HelloInterface hello = new Hello();  //创建需要被代理的Hello类对象

        //此时,不再创建具体的代理对象,而是用Proxy.newProxyInstance利用反射生成代理对象
        InvocationHandler invocationHandler = new ProxyHandler(hello);

        //通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例(注,这里需要强转)。针对不同的代理类,传入相应的代理程序控制器InvocationHandler。
        //newProxyInstance需传入三个参数:分别传入被代理对象的classloader、interface,和创建的invocationHandler,
        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), invocationHandler);
        proxyHello.sayHello(); //通过调用代理接口的方法,调用到了invocationHandler的invoke方法,从而调用到了被代理对象的方法
    }

调用结果:


动态代理比静态代理优秀的方法在于,可以动态地代理各个被代理类,那么此时新的代理类就来了。

创建新的代理类Bye:

public interface ByeInterface {
    void sayBye();
}
class Bye implements ByeInterface {
    @Override
    public void sayBye() {
        System.out.println("这里是被代理类Bye");
    }
}

重新执行:

    public static void main(String[] args) {
        HelloInterface hello = new Hello();  //创建需要被代理的Hello类对象
        ByeInterface bye = new Bye();

        //此时,不再创建具体的代理对象,而是用Proxy.newProxyInstance利用反射生成代理对象
        InvocationHandler invocationHandler = new ProxyHandler(hello);
        InvocationHandler byeHandler = new ProxyHandler(bye);

        //通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例(注,这里需要强转)。针对不同的代理类,传入相应的代理程序控制器InvocationHandler。
        //newProxyInstance需传入三个参数:分别传入被代理对象的classloader、interface,和创建的invocationHandler,
        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), invocationHandler);
        proxyHello.sayHello(); //通过调用代理接口的方法,调用到了invocationHandler的invoke方法,从而调用到了被代理对象的方法

        ByeInterface proxyBye = (ByeInterface) Proxy.newProxyInstance(bye.getClass().getClassLoader(), bye.getClass().getInterfaces(), byeHandler);
        proxyBye.sayBye();
    }

执行结果:


动态代理具体步骤:

通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

上一篇下一篇

猜你喜欢

热点阅读