什么是代理
假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子

代理模式的分类
远程代理模式:为不同地理的对象提供局域网代表对象(例子:通过远程代理可以监控各个店铺,使之可以直观的了解店里的情况)
虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建 (类似于新闻网站加载时,图片加载不出来先用一张空的图片代替)
保护代理:控制用户的访问权限
智能引用代理:提供对目标对象提供额外的服务或者减少特定的服务(火车票代售处)
两种实现方式
静态代理
代理和被代理对象在代理之前是确定的。他们都是实现相同的接口或者继承相同的抽象类。就比如已知一个汽车类并且也只到要有一个汽车的代理类,且它们实现相同接口或者继承相同抽象类。

继承的方式实现静态代理
代理者继承被代理者,对所代理的方法进行改造
需求:一个汽车有一个move方法,方法中打印了移动中三个字并有一个行驶时间(通过Thread.sleep方法),现在我们需要使用代理类算出移动时间并打印消息。
1 | //提供一个代理类和被代理类需要实现的接口 |
聚合的方式实现静态代理
继承同一个接口,且代理对象持有被代理的对象
1 | //使用聚合方式构造代理对象 |
聚合方式和继承方式哪个好呢?
这时我们又新增了一个需求,我们需要给汽车再添加一个日志代理类,并在移动前后打印日志信息。
首先我们使用继承方式,那么我们只需要再创建一个日志代理类并继承于时间代理类就好了,代码如下:
1 | //日志代理类 |
但是这时候我们需求又变动了,我们需要先打印时间信息再打印日志信息,这时候继承方式的静态代理就显得很无力了。
所以我们推荐使用聚合式的静态代理,如下:
1 | //创建日志代理类并实现Movable接口 |
动态代理
来自静态代理的思考:静态代理是对特定类产生代理对象,但是就日志打印这个代理功能而言,成千上百的类都会用到日志打印,那么这时候如果我们使用静态代理的话,我们就要创建成千上百的代理类,这样会非常麻烦。
所以出现了动态代理:动态产生代理,实现对不同类和不同方法的代理。
JDK动态代理

创建事务处理器,实现InvocationHandler接口,覆写invoke方法
参数说明:
proxy 代理对象
Method 被代理对象的方法
args 方法的参数
1
invoke(Object proxy,Method method,Object[] args)
创建被代理的类以及接口
调用Proxy的静态方法,创建代理类(这个类是实现了被代理类的接口的)
参数说明:
loader:被代理类的类加载器
interfaces:被代理类实现的接口
1 | newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) |
事务处理器
通过代理调用被代理的方法
代码如下:
1 | //创建一个Handler实现InvocationHandler |
cglib动态代理
JDK只能代理实现了接口的类,cglib针对类来实现代理,对指定目标类产生一个子类,通过方法拦截技术拦截所有调用父类方法地调用。也因为cglib使用了继承的方式,所以它不能对final修饰的类进行代理。
需求:实现对火车类的日志代理
代码如下:
1 | public class CglibProxy implements MethodInterceptor { |
参考
本博文参考于Java的三种代理模式和慕课网的模式的秘密——代理模式课程