在说到动态代理模式,我们首先说一说什么是代理模式。
什么是代理模式:
Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一
代理模式的定义:这里先举一个例子,假设某人要找对象,但是由于某些原因不能直接去找,于是委托一个中介机构去完成这一过程,如婚姻介绍所,在这里婚姻介绍所其实就是一个代理。再举一个专业相关的例子,如果你想调用一个功能非常强大的加密算法,而现在正在开发的系统又需要使用到该算法,由于该算法位于远程服务器端,封装该算法的对象位于远程服务器内存中,本地内存中的对象无法直接访问,因此需要通过一个远程代理的机制来实现远程对象的操作。也其实也就是webservice、httpclient等实现原理。再看代理的定义:给某一个对象提供一个代理,并有代理对象控制对原对象的引用。
优点:
- 职责清晰 :真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
- 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。
- 增强代码的拓展性
结构
一个是真正的你要访问的对象(目标类),另一个是代理对象,真正对象与代理对象实现同一个接口。先访问代理类并通过代理对象来访问真正要访问的对象中的方法。
简单案例
在一个论坛中已注册用户和游客的权限不同个,已注册的用户拥有发帖、修改自己的注册信息、修改自己的帖子等功能;而游客只能看到别人发的帖子,没有其他权限。在这里我们使用代理模式来设计权限管理模块。
抽象主题类
public interface AbstractDemo {
public void function();
}
AbstractDemo作为抽象权限类,充当了抽象主体角色,在其中声明了真实主题角色所提供的业务方法,它是真是主题角色和代理主题角色的公共接口。这里所说的主题角色就是需要被代理的对象。
真实主题类(需要被代理的类)
public class RealDemo implements AbstractDemo {
@Override
public void function() {
System.out.println("一种算法");
}
RealDemo是真实主题角色,它实现了在抽象主题角色中定义的方法,假设由于种种原因,客户端无法直接访问其中的方法。
代理主题角色
public class DemoProxy implements AbstractDemo {
private RealDemo demo = new RealDemo();
@Override
public void function() {
demo.function();
}
}
这样我们就用DemoProxy代理了RealDemo,并使用了RealDemo的function方法。
客户端调用
public static void main(String[] args) {
AbstractDemo demo = new DemoProxy();
demo.function();
}
动态代理模式
接下来我们重复代理模式的过程,看看动态代理是怎样解决的
抽象主题类
package demo;
public interface AbstractDemo {
public void function(int i);
}
真实主题类一(需要被代理的类)
public class RealDemo1 implements AbstractDemo {
@Override
public void function(int i) {
System.out.println("一种加密算法"+i);
}
}
真实主题类二(需要被代理的类)
public class RealDemo2 implements AbstractDemo {
@Override
public void function(int i) {
System.out.println("一种解密算法"+i);
}
}
动态代理的实现过程
class TestDemo {
public static void main(String[] args) {
final AbstractDemo demo1 = new RealDemo1();
// Proxy.newProxyInstance():产生代理类的实例。仅能代理实现至少一个接口的类
// ClassLoader:类加载器。也可以写成demo.getClass().getClassLoader()。
// Class[] interface:代理类要实现的接口。固定写法,和被代理类使用相同的接口即可。
// InvocationHandler:策略(方案)设计模式的应用。如何代理?
AbstractDemo proxy = (AbstractDemo)Proxy.newProxyInstance(AbstractDemo.class.getClassLoader(),
new Class[]{AbstractDemo.class}, new InvocationHandler() {
// InvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行
// Object proxy:代理对象本身的引用。一般用不着。
// Method method:当前调用的方法。
// Object[] args:当前方法用到的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("执行方法前");
Object obj = method.invoke(demo1,new Object[]{(int)args[0]});
System.out.println("执行方法后");
return obj;
}
});
proxy.function(2);
}
}
结果如下:
执行方法前
一种算法2
执行方法后
上面代码的注解非常详细,如果大家认真阅读,应该对动态代理应该明白的差不多了。阅读上面代码,动态代理可以动态地代理你说需要代理的对象,这里我们代理的是RealDemo1对象。如果我们想代理RealDemo2对象,那么我们只要首先实例RealDemo2对象,得到demo2,然后method.invoke(demo1,new Object[]{args[0]});中的demo1改成demo2即可。这样这个动态代理就可以代理很多主题类,那么系统的类就不会急剧增加了。