代理模式(Proxy)就是为其他对象提供一种代理以控制这个对象的访问,去掉了某些功能或者是增加了一些额外的服务。
常见代理模式有:
远程代理(remoteProxy)
虚拟代理(virtualProxy)
保护代理(protectProxy)
智能引用代理(smartre reference proxy)--日志处理,权限处理,事务处理。
代理分为两种类型,静态代理和动态代理。
下面以我们经常使用的智能引用代理举例子
首先以简单的静态代理为例写一个开车的代理类以记录开车的日志和开车的时间。
静态代理有2种实现方式,一种是继承一种是聚合。我们使用更容易扩展的聚合方式为例:
代理方法接口类Moveable.java
package com.licong.proxy; public interface Moveable { void move(); }
汽车类car.java
package com.licong.proxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { //实现开车 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }
记录时间代理类CarTimeProxy.java
package com.licong.proxy; public class CarTimeProxy implements Moveable { public CarTimeProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶...."); m.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶.... 汽车行驶时间:" + (endtime - starttime) + "毫秒!"); } }
启动日志代理类CarLogProxy.java
package com.licong.proxy; public class CarLogProxy implements Moveable { public CarLogProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { System.out.println("日志开始...."); m.move(); System.out.println("日志结束...."); } }
测试类client.java
package com.licong.proxy; public class Client { /** * 测试类 */ public static void main(String[] args) { Car car = new Car(); CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move(); } }
利用聚合方式可以灵活的设置代理。
动态代理我们用jdk实现的动态代理为例
使用jdk的动态代理很简单,只要实现动态代理处理接口(InvocationHandler)即可
package com.licong.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { public TimeHandler(Object target) { super(); this.target = target; } private Object target; /* * 参数: * proxy 被代理对象 * method 被代理对象的方法 * args 方法的参数 * * 返回值: * Object 方法的返回值 * */ @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; } }
测试类
package com.licong.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import com.imooc.proxy.Car; import com.imooc.proxy.Moveable; public class Test { /** * JDK动态代理测试类 */ public static void main(String[] args) { Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /** * loader 类加载器 * interfaces 实现接口 * h InvocationHandler */ Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); m.move(); } }
使用代理模式,能够在不改变原来代码工商的基础上对某一对象进行额外的控制,从而更好的体现对象中的单一职责。但是对于静态代理来说,一个接口只能服务于一种类型,如果要代理方法很多的时候,则要为每一个方法定义接口。这样就要学习一下动态代理和反射机制。
jdk的动态代理实现的基本思路为:通过反射拿到需要代理类的源码,并添加代理处理类的逻辑生成新的代理类,该类的代码与静态代理类的代码相同,唯一不同的地方就是动态生成的。
另cglib可以生成没实现接口的代理类。