• 动态代理


    时间:2017-1-4 22:33

    ——动态代理(Proxy)概述

    1、只学一个方法:
        Proxy proxy = newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

    2、方法的作用:
        在运行时动态创建一个实现了一组指定接口的对象。

    3、参数:
        1)ClassLoader:类加载器
            它是用来加载类的,把.class文件加载到内存,生成Class对象。

        2)Class[] interfaces:Class数组
            指定要实现的接口们。

        3)InvocationHandler:
            代理对象的所有方法(个别方法不执行,例如getClass())都会调用InvocationHandler的invoke()方法。

    4、动态代理的作用
        最终学习AOP(面向切面编程),它与装饰设计模式相似,但比装饰设计模式灵活。

    示例代码:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
     
    import org.junit.Test;
     
    public class Demo {
        @Test
        public void fun(){
     
            /*
             * 三大参数
             * 1、ClassLoader
             * 该方法会动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象
             * 需要生成一个类,这个类也需要通过ClassLoader加载到方法区中
             * 
             * 2、Class[] interfaces
             * 它是要实现的接口们
             * 
             * 3、InvocationHandler
             * 它是调用处理器
             * 
             * 代理对象实现的所有接口中的方法内容都是调用InvocationHandler的invoke()方法
             */
            ClassLoader loader = this.getClass().getClassLoader();

     
            InvocationHandler h = new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("Hello Proxy");
                    return null;
                }
            };
     
            //使用三大参数创建代理对象
            Object o = Proxy.newProxyInstance(loader, new Class[]{A.class, B.class}, h);
     
            A a = (A)o;
            B b = (B)o;
     
            a.a();
            b.b();
        }
    }
     
    interface A{
        public Object a(String s, int i);
        public Object aa(String s, int i); 
    }
     
    interface B{
        public void b();
    }

    打印结果:
    Hello Proxy
    Hello Proxy
     




    ——InvocationHandler接口

    1、只有一个方法:
        public Object invoke(Object proxy, Method method, Object[] args);
        在调用代理对象所实现接口中的方法时被调用。

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

    2、invoke()方法与代理对象调用方法的关系
        图片


    ——动态代理应用

    增强的方式:
        1、继承
            *   被增强对象不能变
            *   增强内容不能变
        2、装饰设计模式
            *   被增强对象可变
            *   增强内容不可变
        3、动态代理
            *   被增强对象可变
            *   增强内容可变

    目标对象:被增强的对象。
    代理对象:需要目标对象,然后在目标对象上添加了增强后的对象。
    目标方法:被增强的内容。

    代理对象 = 目标对象 + 增强内容

    =============================================================================
    示例代码:

    package com.wyc.demo2;
     
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
     
    import org.junit.Test;
     
    public class Demo2 {
        @Test
        public void fun1() {
            // 目标对象
            Waiter manWaiter = new ManWaiter();
            /*
             * 给出三个参数,来创建方法,得到代理对象
             */
            ClassLoader loader = this.getClass().getClassLoader();
            Class[] interfaces = { Waiter.class };
     
            // manWaiter表示目标对象
            InvocationHandler h = new WaiterInvocationHandler(manWaiter);
     
            // 得到代理对象,其实代理对象就是在目标对象的基础上进行增强的对象
            Waiter waiterProxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h);
     
            /*
             * 在服务方法前添加“你好”,在服务方法后添加“再见”
             */
            waiterProxy.serve();
        }
    }
     
    class WaiterInvocationHandler implements InvocationHandler {
        // 目标对象
        private Waiter waiter;
        public WaiterInvocationHandler(Waiter waiter){
            this.waiter = waiter;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("您好");
            // 调用目标对象的目标方法
            this.waiter.serve();
            System.out.println("再见");
            return null;
        }
    }

    ----------------------------------------------------------------------------------------------------------------------------

    package com.wyc.demo2;
     
    public interface Waiter {
        // 服务方法
        public void serve();
    }

    ----------------------------------------------------------------------------------------------------------------------------

    package com.wyc.demo2;
     
    public class ManWaiter implements Waiter {
        @Override
        public void serve() {
            System.out.println("服务中...");
        }
    }
    ============================================================================= 
     

    ——代理工厂实现

    ============================================================================= 


    ProxyFactory:

    package com.wyc.demo3;
     
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
     
    /*
     * 代理工厂
     * 它用来(组装)生成代理对象
     * 所需参数:
     *  * 目标对象
     *  * 增强内容
     */
     
    /*
     * 1、创建代理工厂
     * 2、给工厂设置三个属性:
     *  * 目标对象:setTargetObject(xxx);
     *  * 前置增强对象:setBeforeAdvice(该接口的实现类)
     *  * 后置增强对象:setAfterAdvice(该接口的实现类)
     *  
     * 3、调用createProxy()方法得到代理对象
     *  * 执行代理对象方法时,首先执行的是BeforeAdvice的before()方法
     *  * 目标对象的目标方法
     *  * 最后会执行AfterAdvice的after()方法
     */
    public class ProxyFactory {
        // 目标对象
        private Object targetObject;
     
        // 前置增强对象
        private BeforeAdvice beforeAdvice;
     
        // 后置增强对象
        private AfterAdvice afterAdvice;
     
        /*
         * 用来生成代理对象
         */
        public Object createProxy(){
            /*
             * 1、给出三大参数
             */
            ClassLoader loader = this.getClass().getClassLoader();
            // 得到该对象的真实类型,获取该类型实现的所有接口
            Class[] interfaces = targetObject.getClass().getInterfaces();
            InvocationHandler h = new InvocationHandler(){
     
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    /*
                     * 在调用代理对象的方法时,会调用该方法,执行这里的内容
                     */
                    // 执行前置增强
                    if(beforeAdvice != null){
                        beforeAdvice.before();
                    }
     
                    // 通过反射得到的Method类,调用目标对象的目标方法
                    Object result = method.invoke(targetObject, args);
     
                    // 执行后置增强
                    if(afterAdvice != null){
                        afterAdvice.after();
                    }
     
                    // 返回目标对象的返回值
                    return result;
                }
            };
     
            /*
             * 2、得到代理对象
             */
            Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
            return proxyObject;
        }
     
        public Object getTargetObject() {
            return targetObject;
        }
     
        public void setTargetObject(Object targetObject) {
            this.targetObject = targetObject;
        }
     
        public BeforeAdvice getBeforeAdvice() {
            return beforeAdvice;
        }
     
        public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
            this.beforeAdvice = beforeAdvice;
        }
     
        public AfterAdvice getAfterAdvice() {
            return afterAdvice;
        }
     
        public void setAfterAdvice(AfterAdvice afterAdvice) {
            this.afterAdvice = afterAdvice;
        }
    }
    ----------------------------------------------------------------------------------------------------------------------------

    测试:

    package com.wyc.demo3;
     
    import org.junit.Test;
     
    /*
     * 让目标对象和增强内容都可以切换
     * 不决定增强对象和增强内容,只起到了装配作用
     */
    public class Demo3 {
        @Test
        public void fun() {
            // 创建工厂
            ProxyFactory factory = new ProxyFactory();
     
            // 设置目标对象
            factory.setTargetObject(new ManWaiter());
     
            // 设置前置增强对象
            factory.setBeforeAdvice(new BeforeAdvice() {
     
                @Override
                public void before() {
                    System.out.println("您好");
                }
            });
     
            // 设置后置增强对象
            factory.setAfterAdvice(new AfterAdvice() {
     
                @Override
                public void after() {
                    System.out.println("再见");
                }
            });
     
            Waiter waiter = (Waiter) factory.createProxy();
            waiter.serve();
            waiter.money();
        }
    }
    ----------------------------------------------------------------------------------------------------------------------------

    Waiter接口:

    package com.wyc.demo3;
     
    public interface Waiter {
        // 服务方法
        public void serve();
     
        // 增加方法
        public void money();
    }
    ----------------------------------------------------------------------------------------------------------------------------

    ManWaiter接口:

    package com.wyc.demo3;
     
    public class ManWaiter implements Waiter {
     
        @Override
        public void serve() {
            System.out.println("服务中...");
        }
     
        @Override
        public void money() {
            System.out.println("收钱...");
        }
    }

    ----------------------------------------------------------------------------------------------------------------------------

    BeforeAdvice接口:

    package com.wyc.demo3;
     
    /*
     * 前置增强
     */
    public interface BeforeAdvice {
        public void before();
    }

    ----------------------------------------------------------------------------------------------------------------------------
     

    AfterAdvice接口:

    package com.wyc.demo3;
     
    /*
     * 后置增强
     */
    public interface AfterAdvice {
        public void after();
    }
  • 相关阅读:
    洛谷 P1019单词接龙
    洛谷 P1091合唱队列
    洛谷 P1141 01迷宫
    洛谷 P1101单词方阵
    NOIP要炸?
    洛谷 P1219八皇后
    洛谷 P1181数列分段Section I
    刷普及-刷爆了。。。。。。
    洛谷 P3952时间复杂度 (本地AC测评RE的伪题解)
    动态数码管
  • 原文地址:https://www.cnblogs.com/wwwwyc/p/6375386.html
Copyright © 2020-2023  润新知