zoukankan      html  css  js  c++  java
  • 动态代理

    http://a.codekk.com/detail/Android/Caij/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20Java%20%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86

    1.1 代理

    在某些情况下,我们不希望或是不能直接访问对象A,而是通过访问一个中介对象 B,由 B 去访问 A 达成目的,这种方式我们就称为代理。

    这里对象 A 所属类我们称为委托类,也称为被代理类,对象 B 所属类称为代理类。

    代理优点有:

        隐藏委托类的实现;

        解耦,不改变委托类代码情况下做一些额外处理,比如添加初始判断及其他公共操作;

    根据程序运行前代理类是否已经存在,可以将代理分为静态代理和动态代理。

    1.2 静态代理

    代理类在程序运行前已经存在的代理方式称为静态代理。

    通过上面解释可以知道,由开发人员编写或是编译器生成代理类的方式都属于静态代理,如下是简单的静态代理实例:

        class ClassA {
            public void operateMethod1() {};
    
            public void operateMethod2() {};
    
            public void operateMethod3() {};
        }
    
        public class ClassB {
            private ClassA a;
    
            public ClassB(ClassA a) {
                this.a = a;
            }
    
            public void operateMethod1() {
                a.operateMethod1();
            };
    
            public void operateMethod2() {
                a.operateMethod2();
            };
    
            // not export operateMethod3()
        }

    上面ClassA是委托类,ClassB是代理类,ClassB中的函数都是直接调用ClassA相应函数,并且隐藏了Class的operateMethod3()函数。

    注:静态代理中 代理类 和 委托类 也常常继承同一父类或实现同一接口。

    1.3 动态代理:

    代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。

    Java 提供了动态代理的实现方式,可以在运行时刻动态生成代理类。

    好处是:可以方便对代理类的函数做统一或特殊处理,如记录所有函数执行时间、所有函数执行前添加验证判断、对某个特殊函数进行特殊操作,而不用像静态代理方式那样需要修改每个函数。

    实现动态代理包括三步:

    (1). 新建委托类;

    (2). 实现InvocationHandler接口,这是负责连接代理类和委托类的中间类必须实现的接口;

    (3). 通过Proxy类新建代理类对象。

    主要涉及到这几个类:

        Proxy类

            public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

                loader - 委托类的classloader

                interfaces - 代表了return的代理对象要实现的接口

                h - 通过代理对象调用的方法,在InvocationHandler.invoke方法里通过反射的方式进行处理

                return - 返回的是代理对象,它指定了InvocationHandler,并且实现了传进来的接口

        InvocationHandler接口

            一般创建此对象时,需要把委托类target传进来

            @Override

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

                proxy 是Proxy.newProxyInstance()生成的动态代理类对象。

                method 表示代理对象被调用的函数。

                args 表示代理对象被调用的函数的参数。Object obj = method.invoke(target, args);

                return 表示代理对象被调用的函数的 返回值/做修改的返回值。

    实例1

    public interface Operate {
        public void operateMethod1();
    
        public void operateMethod2();
    
        public void operateMethod3();
    }
    
    // 委托类
    public class OperateImpl implements Operate {
    
        @Override
        public void operateMethod1() {
            sleep(110);
        }
    
        @Override
        public void operateMethod2() {
            sleep(120);
        }
    
        @Override
        public void operateMethod3() {
            sleep(130);
        }
    
        private static void sleep(long millSeconds) {
            try {
                Thread.sleep(millSeconds);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    // 中间类
    public class TimeInvocationHandler implements InvocationHandler {
    
        private Object target;
    
        public TimeInvocationHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long start = System.currentTimeMillis();
            Object obj = method.invoke(target, args);
            System.out.println(method.getName() + " cost time is:" + (System.currentTimeMillis() - start));
            return obj;
        }
    }
    
    
    class MyClass {
        TimeInvocationHandler timeInvocationHandler = new TimeInvocationHandler(new OperateImpl());
        
        public Operate getOperateInstance() {
            return (Operate) Proxy.newProxyInstance(Operate.class.getClassLoader(), new Class[]{Operate.class}, timeInvocationHandler);
        }
    }
    
    // 获取代理类对象
    Operate operate = MyClass.getOperateInstance();
    operate.operateMethod1();
    operate.operateMethod2();
    operate.operateMethod3();

    实例2:打印时间

        private static LoggingTimeProxy mLoggingTimeProxy;
    
        public static Object getLoggingTimeProxy(Object target) {
            if (mLoggingTimeProxy == null) {
                synchronized (LogUtils.class) {
                    if (mLoggingTimeProxy == null) {
                        mLoggingTimeProxy = new LoggingTimeProxy();
                    }
                }
            }
            return mLoggingTimeProxy.newProxyInstance(target);
        }
    
    
        class LoggingTimeProxy implements InvocationHandler {
    
            private Object target;
    
            Object newProxyInstance(Object target) {
                if (target == null) {
                    throw new IllegalArgumentException("target is null");
                }
                this.target = target;
                return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                                target.getClass().getInterfaces(),
                                                this);
            }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (target == null) {
                throw new IllegalArgumentException("target is null");
            }
            long startTimeMillis = System.currentTimeMillis();
    
            Object result = method.invoke(target, args);
    
            String tag = target.getClass().getSimpleName() + "." + method.getName();
            infoByTag(tag, (System.currentTimeMillis() - startTimeMillis) + " ms");
            return result;
        }
     }
  • 相关阅读:
    2016.7.17
    2016.7.16
    2016.7.15
    2016.7.12
    2016.7.11
    2016.7.10
    coco2d-x中的坐标系问题
    cocos2d-x中的Tiled地图
    cocos2d-x中的Box2D物理引擎
    python文件处理及装饰器
  • 原文地址:https://www.cnblogs.com/muouren/p/11706523.html
Copyright © 2011-2022 走看看