代理模式
一、代理模式的基本概念与分类 代理的定义:为其他对象提供一种代理,以控制对这个对象的访问。
常见的代理模式有:远程代理、虚拟代理、保护代理、智能引用代理。
二、常用代理模式原理 下面以智能引用代理来介绍静态代理模式与动态代理模式。
静态代理:代理和被代理对象在代理之前是确定的。他们都实现了相同的接口或继承了相同的抽象类。
有这样一个需求:有一辆小汽车,有一个行驶的方法move,还需要一个记录行驶时间的方法。
方案一: 1 2 3 public interface Moveable { public void move(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Car implements Moveable { @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽车形式开始......."); //实现开车 try { System.out.println("汽车形式中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } long endTime = System.currentTimeMillis(); System.out.println("汽车形式结束.....,汽车形式时间:"+(endTime-startTime)); } }
方案二:通过继承的方式实现静态代理实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车形式中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 9 10 public class Car2 extends Car { @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽车形式开始......."); super.move(); long endTime = System.currentTimeMillis(); System.out.println("汽车形式结束.....,汽车形式时间:"+(endTime-startTime)); } }
方案三:聚合的方式实现静态代理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车形式中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Car3 extends Car { public Car3(Car car) { super(); this.car = car; } private Car car; @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽车形式开始......."); car.move(); long endTime = System.currentTimeMillis(); System.out.println("汽车形式结束.....,汽车形式时间:"+(endTime-startTime)); } }
1 2 3 4 5 6 7 8 public class main { public static void main(String[] args) { Car car = new Car(); // car.move(); Car3 car3 = new Car3(car); car3.move(); } }
汽车形式开始.......
汽车形式中......
汽车形式结束.....,汽车形式时间:48
那么继承与聚合的方式实现静态代理,谁更好呢?
那么现在又有需要,在move方法前不紧有记录时间的功能,还有权限的功能,记录日志的功能:如先日志-->权限,权限-->日志,用继承方式实现难道要继续新建Car4、Car5?那么聚合就不用么?看如下实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车形式中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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("记录日志结束......"); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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)); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class main { public static void main(String[] args) { Car car = new Car(); CarTimeProxy carTimeProxy = new CarTimeProxy(car); CarLogProxy logProxy = new CarLogProxy(carTimeProxy); logProxy.move(); System.out.println("-----------------------------"); CarLogProxy logProxy1 = new CarLogProxy(car); CarTimeProxy carTimeProxy1 = new CarTimeProxy(logProxy1); carTimeProxy1.move(); } }
日志记录开始.....
汽车形式开始.......
汽车形式中......
汽车形式结束.....,汽车形式时间:767
记录日志结束......
-----------------------------
汽车形式开始.......
日志记录开始.....
汽车形式中......
记录日志结束......
汽车形式结束.....,汽车形式时间:288
这样就决解了上面的问题,但是如果我们又要为火车,公交车、飞机实现这样的功能呢,难道又要新建TrainTimePoxy,TrainLogPoxy,BusTimeProxy........?这个时候动态代理就出现了。
三、理解JDK动态代理实现
Java动态代理位于java.lang.reflect包下,,一般主要涉及两个类:
(1)、Interface InvocationHandler:该接口中仅定义了一个方法:public Object invoke(Object proxy, Method method, Object[] args),
在实际的使用中,第一个参数obj一般指被代理类,method指被代理的方法,arg代理方法的参数。
(2)、该类即为动态代理类:static newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在接口中声明的方法)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class TimeHandler implements InvocationHandler{ public TimeHandler(Object target) { super(); this.target = target; } private Object target; /** * * @param proxy:被代理的对象 * @param method:被代理对象的方法 * @param args:方法的参数 * @return:Object对象,方法的返回值 * @throws Throwable */ @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; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class main { public static void main(String[] args) { Car car = new Car(); Class c = car.getClass(); InvocationHandler h = new TimeHandler(car); /** * loader:类加载器 * interfaces:实现的接口 * h:InvocationHander */ Moveable m = (Moveable) Proxy.newProxyInstance(c.getClassLoader(),c.getInterfaces(),h); m.move(); } }
汽车形式开始.......
汽车形式中......
汽车形式结束.....,汽车形式时间:432
总结:所谓的Dynamic Proxy是这样一种class:
它是在运行时生产的Class;
该class需要实现一组interface;
使用动态代理时,需要实现InvocationHandler接口;
实现动态代理的步骤:
(1)、创建一个实现InvocationHandler的类,他必须实现invoke()方法;
(2)、创建被代理的类以及接口;
(3)、调用Proxy的静态方法,创建一个代理类,Proxy.newProxyInstance(c.getClassLoader(),c.getInterfaces(),h)
(4)、通过代理调用方法。
四、JAK动态代理实现原理分析