Java常见设计模式之代理模式
指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其它相关业务的处理。比如生活中的通过代理访问网络,客户通过网络代理连接网络(具体业务),由代理服务器完成用户权限和访问限制等与上网相关的其他操作(相关业务)。代理的思想在我们日常生活中无处不在。下面我通过一个简单的代码先大致了解一下代理的相关内。
示例代码如下:
package com.yonyou.test; /** * 创建一个上网的接口 * @author 小浩 * @创建日期 2015-4-6 */ public interface Network { //用户真正的上网需求 void browse(); }
package com.yonyou.test; /** * 真正的上网需求类,实现Network接口 * @author 小浩 * @创建日期 2015-4-6 */ public class Real implements Network{ @Override public void browse() { System.out.println("您好,当前用户正在上网操作~~~"); } }
package com.yonyou.test; /** * 创建一个代理接口 * @author 小浩 * @创建日期 2015-4-6 */ public class Proxy implements Network{ Network network=null; //初始化被代理对象 public Proxy(Network network){ this.network=network; } //模式权限检查的操作 public void check(){ // 模拟权限检查 System.out.println("您好,我们正在检查当前用户是否有上网的权限..."); } @Override public void browse() { //增强操作,模拟权限检查 check(); //用户真正的操作 network.browse(); } }
package com.yonyou.test; /** * TreeSet测试类 * @author 小浩 * @创建日期 2015-4-3 */ public class Test{ public static void main(String[] args) { //创建代理类 Network network=new Proxy(new Real()); network.browse(); } }
一般在哪些地方需要使用代理:
1 创建目标对象的开销比较大,而且在当前程序中,还有可能使用不到目标对象的全部方法
2 需要对目标对象进行增强处理
下面对常见的代理方式进行讲解。
1、静态代理(static proxy)
因为静态代理比较简单,下面我们就直接上例子:
package com.xiaohao.proxystatic; /** 定义电脑的通用接口 */ public interface Computer { //定义电脑开机的接口 public void power(); }
package com.xiaohao.proxystatic; public class ComputerProxy implements Computer{ private Computer computer; public ComputerProxy(Computer computer){ this.computer=computer; } @Override public void power() { //增强处理的方法,before System.out.println("您好,系统正在加载中,请稍后............."); //调用相应的原来的方法 computer.power(); //增强处理的方法,after System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); } }
package com.xiaohao.proxystatic; public class Hp implements Computer{ @Override public void power() { System.out.println("您好,欢迎使用惠普电脑~~~~~"); } }
package com.xiaohao.proxystatic; public class Lenovo implements Computer{ @Override public void power() { System.out.println("您好,欢迎您使用联想电脑~~~~~~~~"); } }
package com.xiaohao.proxystatic; public class Test { public static void main(String[] args) { //创建惠普电脑对象 Hp hp=new Hp(); //创建联想电脑对象
Lenovo lenovo=new Lenovo(); //创建电脑的代理类,使相应的电脑的方法得到相应的加强 ComputerProxy computerProxyHp=new ComputerProxy(hp); ComputerProxy computerProxyLenovo=new ComputerProxy(lenovo); computerProxyHp.power(); System.out.println("-------------------------------------------------------------------"); computerProxyLenovo.power(); System.out.println("-------------------------------------------------------------------"); } }
2、动态代理(dynamic proxy)
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。常见的动态代理有两种方式,一种为jdk动态代理,一种为cglib动态代理。下面我们分别来介绍一下它们。
JDK动态代理:
package com.xiaohao.proxydynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ComputerProxy implements InvocationHandler{ //创建被代理的对象 private Object computer; //绑定需要代理的对象 public Object bind(Computer computer){ this.computer=computer; return Proxy.newProxyInstance(computer.getClass().getClassLoader(), computer.getClass().getInterfaces() ,this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //增强处理的方法,before System.out.println("您好,系统正在加载中,请稍后............."); //调用相应的原来的方法 Object result=method.invoke(computer,args); //增强处理的方法,after System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); return result; } }
package com.xiaohao.proxydynamic; public class Test { public static void main(String[] args) { //创建惠普电脑对象
Hp hp=new Hp(); //创建联想电脑对象 Lenovo lenovo=new Lenovo(); //创建电脑的代理类,使相应的电脑的方法得到相应的加强 ComputerProxy computerProxy=new ComputerProxy(); Computer computer=(Computer) computerProxy.bind(hp); computer.power(); System.out.println("-------------------------------------------------------------------"); computer=(Computer) computerProxy.bind(lenovo); computer.power(); System.out.println("-------------------------------------------------------------------"); } }
对于jdk动态代理而言,我们需要被代理的目标类实现相应的接口。对于jdk动态代理的原理的讲解可以参考:
http://www.cnblogs.com/xiohao/p/4397359.html
cglib动态代理:
针对于jdk动态代理需要在被代理类实现相应的接口,但是针对于某些没有实现指定接口的类,就显得无能为力了。
这时我们可以使用第三方插件cglib,来实现对目标对象的增强处理。(在使用的过程中需要导入cglib的相关包)。
具体的使用格式请看下面的内容吧。
package com.xiaohao.proxycglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; //import org.aopalliance.intercept.MethodInterceptor; //import org.aopalliance.intercept.MethodInvocation; public class ComputerProxy implements MethodInterceptor{ //创建被代理对象 private Object computer; public Object bind(Object computer){ this.computer=computer; Enhancer enhancer=new Enhancer(); //设置要代理的类,使代理类作为被代理类的父类 enhancer.setSuperclass(this.computer.getClass()); //回调相应的方法 enhancer.setCallback(this); //创建相应的代理对象,并返回相应的代理对象 return enhancer.create(); } // 回调方法 @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { System.out.println("您好,系统正在加载中,请稍后............."); arg3.invokeSuper(arg0,arg2); System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); return null; } }
package com.xiaohao.proxycglib; public class Test { public static void main(String[] args) { //创建被代理对象
Hp hp=new Hp(); //创建被代理对象
Lenovo lenovo=new Lenovo(); ComputerProxy computerProxy=new ComputerProxy(); //绑定相应的目标代理类 hp=(Hp) computerProxy.bind(hp); lenovo=(Lenovo) computerProxy.bind(lenovo); hp.power(); System.out.println("-------------------------------------------------------------------"); lenovo.power(); System.out.println("-------------------------------------------------------------------"); } }
下面是Spring整合cglib后的一种使用方式,原理差不多,感兴趣的可以简单的看一下:
package com.xiaohao.proxycgli; import java.lang.reflect.Method; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; //import org.aopalliance.intercept.MethodInterceptor; //import org.aopalliance.intercept.MethodInvocation; public class ComputerProxy implements MethodInterceptor{ @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { //增强处理的方法,before System.out.println("您好,系统正在加载中,请稍后............."); //调用相应的原来的方法 Object result=arg3.invokeSuper(arg0, arg2); //增强处理的方法,after System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); return result; } // @Override // public Object invoke(MethodInvocation arg0) throws Throwable { // //增强处理的方法,before // System.out.println("您好,系统正在加载中,请稍后............."); // //调用相应的原来的方法 // Object result=arg0.proceed(); // //增强处理的方法,after // System.out.println("恭喜您,您已经成功开机,Congratulation~~~~~~~"); // return result; // } }