美文网首页Java
动态代理实战

动态代理实战

作者: 奔跑吧李博 | 来源:发表于2021-06-27 10:54 被阅读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 来创建动态代理类;
    通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
    通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

    相关文章

      网友评论

        本文标题:动态代理实战

        本文链接:https://www.haomeiwen.com/subject/pejtultx.html