动态代理

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;
    }
 }
原文地址:https://www.cnblogs.com/muouren/p/11706523.html