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; } }