为目标对象提供一种代理,以控制对其的访问。代理对象相当于中介,可以去掉功能服务或者增加添加额外功能服务。 举例: 今天我想去服装店A买件衣服,一般都是直接去A的实体店进行购买,但是今天下雨了不想出门,于是我就打开淘宝在A的官方旗舰店B把想要的衣服买了,那么B就是相当于A的一个代理。B又提供了其它一些服务,比如:七天无理由退换货、送货上门等(添加额外功能)。B又没有现场试穿等服务(去掉功能服务)。
代理可以在不改变目标类原有代码的基础上拓展其功能。例如:对一些方法进行性能测试,添加操作日志等。AOP便是使用动态代理来实现拦截切入功能。
需要定义父类或者接口,代理对象和被代理对象需要同时继承父类或者实现该接口。
每进行一个代理都要建立一个代理类,随着代理类增多会造成类膨胀。
有两种实现方式,继承与聚合,由于聚合的方式优于继承,这里只演示聚合的实现。 创建接口:目标类和代理类同时实现该接口。
public interface Moveable { void move(); }目标对象:
public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车行驶中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }代理对象:
public class CarProxy implements Moveable { private Car car; public CarProxy(Car car) { this.car = car; } @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽车开始行驶......"); car.move(); long endTime = System.currentTimeMillis(); System.out.println("汽车结束行驶...... 汽车行驶时间:"+(endTime-startTime)+"毫秒!"); } }测试:
public class ProxyTest { public static void main(String[] args) { Car car = new Car(); Moveable proxy = new CarProxy(car); proxy.move(); } }测试结果
汽车开始行驶...... 汽车行驶中...... 汽车结束行驶...... 汽车行驶时间:724毫秒!没有实现接口的类不能进行动态代理。
Java动态代理类位于java.lang.reflect包下,主要涉及以下两个类 (1) public interface InvocationHandler:该接口定义了一个抽象方法:
/** * @param proxy 代理类 * @param method 被代理的方法 * @param args 被代理方法的参数 */ public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;该抽象方法在代理类中动态实现。 (2)public class Proxy:该类为动态代理类,该类产生代理类的方法为:
/** * @param loader 目标对象的类加载器 * @param interfaces 目标对象的接口类型 * @param h 事件处理函数,实现对目标对象的操作。 */ public static Object newProxyInstance( ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException创建接口:
public interface Moveable { void move(); }目标对象:
public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车行驶中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }代理工厂类:
public class TimeProxyFactory { //代理的目标对象 private Object target; public TimeProxyFactory(Object target) { this.target = target; } //获取目标对象 public Object getInstance() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("汽车开始行驶......"); Object obj = method.invoke(target, args); long endTime = System.currentTimeMillis(); System.out.println("汽车结束行驶...... 汽车行驶时间:"+(endTime-startTime)+"毫秒!"); return obj; } }); } }测试:
public class ProxyTest { public static void main(String[] args) { Moveable move = new Car(); TimeProxyFactory factory = new TimeProxyFactory(move); Moveable proxy =(Moveable) factory.getInstance(); proxy.move(); } }测试结果
汽车开始行驶...... 汽车行驶中...... 汽车结束行驶...... 汽车行驶时间:123毫秒!Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
目标对象:
public class Train { public void move() { System.out.println("火车行驶中......"); } }代理类:
public class CGLibProxy implements MethodInterceptor { //创建代理对象 public Object getProxyInstance(Class c) { //Enhancer可以为接口或者非接口类型创建一个子类作为代理类,可以拦截所有方法 Enhancer enhancer = new Enhancer(); //设置创建子类的类,也就是说为每个代理类创建子类 enhancer.setSuperclass(c); //设置回掉函数(因为MethodInterceptor继承了Callback类,默认执行intercept方法) enhancer.setCallback(this); //创建子类实例,返回去 return enhancer.create(); } /** * 拦截所有目标类方法的调用 * @param o 目标类的实例 * @param method 目标方法的反射对象 * @param objects 目标方法的参数 * @param proxy 代理类的实例 */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("汽车开始行驶......"); //代理类调用父类的方法,来实现代理类的方法 Object returnObject = proxy.invokeSuper(o, objects); long endTime = System.currentTimeMillis(); System.out.println("汽车结束行驶...... 汽车行驶时间:"+(endTime-startTime)+"毫秒!"); return returnObject; } }测试:
public class ProxyTest { public static void main(String[] args) { Train train = (Train) new CGLibProxy().getProxyInstance(Train.class); train.move(); } }测试结果
汽车开始行驶...... 火车行驶中...... 汽车结束行驶...... 汽车行驶时间:297毫秒!