在说到动态代理模式,我们首先说一说什么是代理模式。
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即可。这样这个动态代理就可以代理很多主题类,那么系统的类就不会急剧增加了。