Java设计模式 之 代理模式
所谓的代理模式就是为其它类或对象提供一个代理以控制对这个对象的访问。那么常见的代理有远程代理,虚拟代理,保护代理,智能代理。
1. 远程代理:为一个不同地址空间的对象提供一个本地代理对象。
2. 虚拟代理:根据需要创建一个开销很大的对象。
3. 保护代理:控制原始对象的访问。
4. 智能代理:取代简单的指针,它在访问对象时执行一些附件操作
实现代理的有两种方式
1. 静态代理:就是代理和被代理的对象在代理之前是确定的,他们可以通过继承抽象类或者实现相同的接口来实现。
下面使用代理模式来模拟实现我一天的生活。
<1>. 首先先通过继承方式来实现代理模式, 创建被代理的接口和实现类
package com.dcz.proxy; public interface IWork { /** * 工作 */ public void working(); }
package com.dcz.proxy; public class Work implements IWork { @Override public void working() { System.out.println("开始一天的工作...."); } }
<2>. 通过使用继承的方法来实现对工作类的代理,代码如下
package com.dcz.proxy; public class InheritProxy extends Work { @Override public void working() { System.out.println("出家门,驾车去公司..."); super.working(); System.out.println("出公司门,驾车回家..."); } }
<3>. 通过使用聚合的方法来实现对工作类的代理,代码如下
package com.dcz.proxy; public class AggregationProxy implements IWork { private IWork work; public AggregationProxy(IWork work) { super(); this.work = work; } @Override public void working() { System.out.println("出家门,驾车去公司..."); work.working(); System.out.println("出公司门,驾车回家..."); } }
那么既然有两种方法可以实现代理模式,那么毕竟会 有一种比较优越的方法,哪会是哪一种 呢。那好,思考一个问题,假如我们有多层代理去代理一个目标方法,如果使用继承的话就会一类依赖一个类,并且有很多层继承。聚合就不同了,他们不管要实现多少层代理,都是统一实现一个接口。这样具有灵活性,并且类的设计原则告诉我们要少用继承多用聚合。
下面使用代码来模拟我一天的工作内容。
<1>. 还是针对上面的Work接口和类,创建代理类1
package com.dcz.proxy; public class WorkProxy1 implements IWork { private IWork work; public WorkProxy1(IWork work) { super(); this.work = work; } @Override public void working() { System.out.println("出家门,驾车去公司..."); work.working(); System.out.println("出公司门,驾车回家..."); } }
<2>. 创建代理类2
package com.dcz.proxy; public class WorkProxy2 implements IWork { private IWork work; public WorkProxy2(IWork work) { super(); this.work = work; } @Override public void working() { System.out.println("吃早饭..."); work.working(); System.out.println("吃晚饭..."); } }
<3>. 创建代理类3
package com.dcz.proxy; public class WorkProxy3 implements IWork { private IWork work; public WorkProxy3(IWork work) { super(); this.work = work; } @Override public void working() { System.out.println("早锻炼..."); work.working(); System.out.println("晚散步"); } }
<4>. 测试
package com.dcz.proxy; public class ProxyTest2 { public static void main(String[] args) { IWork work = new Work(); // 代理1 WorkProxy1 workProxy1 = new WorkProxy1(work); // 代理2 WorkProxy2 workProxy2 = new WorkProxy2(workProxy1); // 调用 workProxy2.working(); } }
<5> . 输出
吃早饭... 出家门,驾车去公司... 开始一天的工作.... 出公司门,驾车回家... 吃晚饭...
假如你要将代理类1和代理类2调换一下,这将很容易做到。这就是静态代理模式,但是这也将使用具有一定的范围,思考一个问题,我们做代理的时候是知道代理和被代理对象,假如我们想为我们项目中的某些类方法实现代理,而现在我们不知道具体是哪些类方法,那么该如何做呢——动态代理。
2. 动态代理
动态代理有两种实现的方式,一种是jdk原生支持的动态代理,一种是第三方的实现cglib动态代理,两者有一定的区别,下面分别使用代码实现。
<1> jdk动态代理
实现步骤:
(1). 创建一个实现接口InvocationHandler的类,实现invoke方法。
(2). 创建代理类和接口
(3). 调用Proxy的静态方法,创建一个代理实例
(4). 通过代理调用目标方法
代码实现:
(1). 首先先定义代理类接口
package com.dcz.jdkproxy; public interface IDoSomething { /** * 做某事 */ public void doSomething(); }
(2). 创建实现类
package com.dcz.jdkproxy; import java.util.Random; public class DoSomething implements IDoSomething { @Override public void doSomething() { try { Thread.sleep(new Random().nextInt(1000)); System.out.println("做事中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }
(3). 代理实现
package com.dcz.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeProxy implements InvocationHandler { private Object target; public TimeProxy(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("开始计时..."); method.invoke(target); long endTime = System.currentTimeMillis(); System.out.println("计时结束... 用时:" + (endTime-startTime)+"毫秒"); return null; } }
(4). 测试
package com.dcz.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { // JDK动态代理测试 IDoSomething doSomething = new DoSomething(); InvocationHandler timeProxy = new TimeProxy(doSomething); /** * loader 类加载器 * interfaces 实现接口 * h */ IDoSomething ds = (IDoSomething)Proxy.newProxyInstance(doSomething.getClass().getClassLoader(), doSomething.getClass().getInterfaces(), timeProxy); ds.doSomething(); } }
从上面代码可以看到,jdk内置实现的代理是需要代理类实现一个接口的,也就是说使用jdk动态代理要求代理类必须要实现一个接口。
2. cglib动态代理
代码实现:
(1). 创建代理类
package com.dcz.cglibproxy; import java.util.Random; public class DoSomething { public void doSomething() { try { Thread.sleep(new Random().nextInt(1000)); System.out.println("做事中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }
(2). 创建cglib代理
package com.dcz.cglibproxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { private Enhancer enhance = new Enhancer(); public Object getProxy(Class<?> clazz){ // 设置创建子类的类 enhance.setSuperclass(clazz); enhance.setCallback(this); return enhance.create(); } /** * 拦截所有目标类方法的调用 * object 目标类实例 * method 目标方法反射对象 * args 方法参数 * proxy 代理类实例 */ @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("计时开始..."); // 代理类调用父类的方法 proxy.invokeSuper(object, args); long endTime = System.currentTimeMillis(); System.out.println("计时结束...用时:" + (endTime - startTime) + "毫秒"); return null; } }
(3). 测试
package com.dcz.cglibproxy; public class CglibProxyTest { public static void main(String[] args) { CglibProxy poxy = new CglibProxy(); DoSomething doSomething = (DoSomething)poxy.getProxy(DoSomething.class); doSomething.doSomething(); } }
cglib动态代理可以为任何的类实现代理