代理模式(Proxy):为其他对象提供一种代理以控制这个对象的访问。
代理模式类别:
1.远程代理:为一个对象在不同的地址空间提供局部代理,这样可以隐藏一个对象存在于不同地址空间的事实。比如:使用nexus构建私服就相当于是使用远程代
理的方式,使得工程依赖的jar包不要一直去远程访问。
2.虚拟代理:根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。这样就可以在一定的程度上提升系统的性能。
3.安全代理:用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候。
4.智能指引:是指当调用真实对象时,代理处理另外的一些事情。如:计算真实对象的引用次数,这样当该对象没有引用是,可以自动释放它;或当第一次引用一
个持久对象时,将它装入内存;或在访问一个实际对象前,检查是否已经锁定它,以确保其他对象不能改变它,这些都是通过代理在访问一个对象时附加一些内部的处
理。
总之,代理模式其实就是在访问对象时插入一定程度的间接性处理,因为这种机制可以附加多种用途。
上面讲解都是理论上的东西,下面结合代码来分析一下代理模式中的两种代理模式:静态代理和动态代理
代理模式一般涉及到三个角色:
1.抽象角色:声明真实角色的接口
2.真实角色:抽象角色的实现
3.代理角色:代理角色内可以含有真实角色的引用,同时可以实现一些附加操作
一、静态代理
静态代理:静态代理中就是简单的将真实角色中的方法重新实现,重载抽象类中声明的方法。
静态代理的缺点是代理与真实角色一一对应,所以对于每一个要被代理的类,都要有一个代理类与之对应,并且都要实现抽象角色中的所有方法。所以这样代码的
复用率就下降了。
下面就贴出代码:
A.抽象角色:
package com.jjyy.jdbc.inter; /** * 电话的接口 * * @author JiangYu 2015年3月29日 * */ public interface Phone { /** * call 方法 */ public void call(); /** * sendMsg 方法 */ public void sendMsg(); }
B.代理角色
package com.jjyy.jdbc.decoration; import com.jjyy.jdbc.inter.Phone; /** * 静态代理模式---前提是对象已经存在了 * @author JiangYu * 2015年3月29日 * */ public class DecorateSamsungPhone implements Phone{ private Phone phone = null; //通过构造方法传递对象 public DecorateSamsungPhone(Phone phone) { this.phone = phone; } @Override public void call() { phone.call(); } @Override public void sendMsg() { System.out.println("SamsungPhone sendMsg:Hello Samsung"); } }
C.真实对象
package com.jjyy.jdbc.decoration; import com.jjyy.jdbc.inter.Phone; /** * 静态代理设计模式 * 真实类要和代理类要实现相同的接口 * 在代理类的构造方法中传入被代理类的对象,这样就可以使用被代理对象的方法进行不同的装饰 * @author JiangYu * 2015年3月29日 * */ public class SamsungPhone implements Phone { @Override public void call() { System.out.println("SumsungPhone call..."); } @Override public void sendMsg() { System.out.println("Phone sendMsg..."); } }
D.测试类:
package com.jjyy.jdbc.decoration; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; import com.jjyy.jdbc.dynamicProxy.DynamicProxyIPhone; import com.jjyy.jdbc.inter.Phone; /** * 静态代理模式和动态代理设计模式 * @author JiangYu * 2015年3月29日 * */ public class DesignModel { /** * 静态代理设计模式 */ @Test public void decorationDesignTest(){ //被装饰类 SamsungPhone phone = new SamsungPhone(); //装饰类 DecorateSamsungPhone samsungPhone = new DecorateSamsungPhone(phone); //调用装饰之后的对象的方法 samsungPhone.call(); samsungPhone.sendMsg(); } }
二、动态代理
动态代理:为了解决静态代理的问题----代码的复用率低。动态代理一般要满足代理的三个角色,然后还要实现一个接口---InvocationHandler,该接口中有一
个invoke方法。
理论的知识有点抽象,贴出代码:
A.真实角色
package com.jjyy.jdbc.decoration; import com.jjyy.jdbc.inter.Phone; /** * 动态代理:真实角色 * @author JiangYu * 2015年3月29日 * */ public class IPhone implements Phone{ @Override public void call() { System.out.println("IPhone call..."); } @Override public void sendMsg() { System.out.println("IPhone sendMsg..."); } }
B.代理角色
package com.jjyy.jdbc.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理类--代理类 * @author JiangYu * 2015年3月29日 * */ public class DynamicProxyIPhone implements InvocationHandler { private Object obj = null; public Object registerObj(Object obj){ this.obj = obj; //所有的接口都绑定到了代理类对象上,保证真实对象和代理对象有着共同的行为 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("dynamic Proxy..."); //代理对象处理特殊的方法 if ("sendMsg".endsWith(method.getName())) { System.out.println("IPhone sendMsg:Hello IPhone From DynamicProxy..."); return null; }else { return method.invoke(this.obj, args); } } }
C.测试类
package com.jjyy.jdbc.decoration; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; import com.jjyy.jdbc.dynamicProxy.DynamicProxyIPhone; import com.jjyy.jdbc.inter.Phone; /** * 静态代理模式和动态代理设计模式 * @author JiangYu * 2015年3月29日 * */ public class DesignModel { /** * 动态代理设计模式--实现方式之二 * 1.真实类和代理类具有相同的行为 * 2.代理类要实现InvocationHandler接口,事项invoke方法 * 3.代理类可以对真实类的行为进行增强 * 4.调用代理类对象的方法 */ @Test public void dynamicProxyDesignTest(){ //真实类 IPhone phone = new IPhone(); //代理类 DynamicProxyIPhone proxy = new DynamicProxyIPhone(); //代理对象 IPhone proxyPhone = (IPhone) proxy.registerObj(phone); //调用代理对象的方法 proxyPhone.call(); proxyPhone.sendMsg(); } }
上面的动态代理方式是一种常规的方式,另外还有一种方式是比较常用的动态代理写法--在测试类中直接用内部类来实现InvocationHandler
package com.jjyy.jdbc.decoration; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; import com.jjyy.jdbc.dynamicProxy.DynamicProxyIPhone; import com.jjyy.jdbc.inter.Phone; /** * 静态代理模式和动态代理设计模式 * @author JiangYu * 2015年3月29日 * */ public class DesignModel { /** * 动态代理设计模式--实现方式之一 */ @Test public void proxyDesignTest(){ final IPhone iPhone = new IPhone(); //动态代理 Phone proxy = (Phone) Proxy.newProxyInstance(IPhone.class.getClassLoader(), IPhone.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("sendMsg".equals(method.getName())){//如果是sendMsg时,就进行特殊的处理 System.out.println("Iphone sendMsg:Hello IPhone"); return null; }else {//其他的方法还是按照原来的方法进行 return method.invoke(iPhone, args); } } }); //通过代理对象去执行响应的方法 proxy.call(); proxy.sendMsg(); } }
以上的动态代理是jdk的proxy,其实它也不是完美的,它只能代理实现了接口的类,不能对类本身实现代理,如果要完成对类本身实现代理,需要用到一个开源的
cglib。