Java 进阶(三)动态代理
要想学习动态代理,首先我们得了解一下代理模式。
代理模式
定义
代理模式给某一个对象提供代理对象,并由代理对象控制对原对象的引用。
举个例子,tx想用游戏赚钱,但是自己又设计不出好的游戏,于是跟拳头公司协商,拿下LoL中国区的代理。这样tx就不用再去关心新英雄新皮肤的设计、游戏更新等等问题,只需要关心英雄和皮肤怎么卖才赚钱就行了(狗头保命)。
作用
那么为什么要用代理模式呢?
还是回到刚刚的栗子,tx拿到代理权后解决了两个事情:1.tx不用关心游戏设计中等等的问题 2.tx也可以开展自己擅长的业务(卖皮肤)
所以归纳一下,
1.中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
2.开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
静态代理
静态代理和动态代理的区别在于代理的创建时期。
静态代理是由程序员创建或特定工具自动生成源代码,在程序运行之前,代理类就已经被创建了。
而动态代理是在程序运行时通过反射机制动态创建的。关于反射,请关注我专栏的其他博客。
静态代理的创建比较简单:
// 服务接口
public interface LoL {
void developLoL();
}
// 委托类
public class tencent implements LoL {
@Override
public void developLoL() {
System.out.println("卖英雄");
System.out.println("卖皮肤");
}
}
// 代理类
public class Roit implements LoL{
private tencent tx;
public Roit(final tencent tx){
this.tx = tx;
}
@Override
public void developLoL() {
System.out.println("设计新英雄");
System.out.println("平衡性调整");
tx.developLoL();
}
}
// 测试
public class test {
public static void main(String[] args) {
tencent tx = new tencent();
tx.developLoL();
Roit r = new Roit(tx);
r.developLoL();
}
}/* output
卖英雄
卖皮肤
设计新英雄
平衡性调整
卖英雄
卖皮肤
*/
可以看到,使用静态代理时,我们需要为每个服务都创建代理类,工作量较大,而且不能动态修改。
另外,有同学可能要问了,这和装饰器模式有什么区别?确实,上面一段代码同样适用于装饰器模式,但装饰器模式的目的和代理模式是不一样的,装饰器模式更加偏重于拓展的功能。
动态代理
动态代理通过编写动态处理器实现,真正的代理对象由JDK运行时创建:
动态处理器:
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable{
System.out.println("设计游戏");
System.out.println("设计皮肤");
Object result = method.invoke(object, args);
return result;
}
}
可以看到,动态处理器实现了InvocationHandler接口的invoke方法,而该方法实际调用的是method对象的invoke方法,该方法用来执行某个的对象的目标方法。
接下来我们来编写测试类:
public class test {
public static void main(String[] args) {
LoL tx = new tencent();
LoL tx_proxy = (LoL) Proxy.newProxyInstance(LoL.class.getClassLoader(), new Class[]{LoL.class}, new DynamicProxyHandler(tx));
tx_proxy.developLoL();
}
}/*output
设计游戏
设计皮肤
卖英雄
卖皮肤
*/
可以发现,相比于静态代理,动态代理是仅支持接口代理的,具体的代理对象生成由Proxy.newProxyInstance方法实现,该方法接收3个参数:
1.ClassLoader loader: 指定当前对象使用的类加载器
2.Class<?>[] interfaces :指定目标对象实现的接口的类型
3.InvocationHandler: 指定动态处理器