Java基础知识之设计模式--代理模式
Java设计模式--代理模式
声明:本文根据慕课网David老师的精品课程整理来的:慕课网
什么是设计模式(Design Pattern)?
设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结。
代理模式的定义?
代理模式就是为其他对象提供一种代理,以控制对这个对象的访问。
代理对象起到中介作用,可去掉功能服务或增加额外的服务。
代理对象和目标对象的关系?
代理对象:增强后的对象
目标对象:被增强的对象
他们不是绝对的,会根据情况发生变化。
代理模式的两种实现方式?
1.静态代理:代理和被代理对象在代理之前是确定的,它们都实现相同的接口或者继承相同的抽象类。
2.动态代理:JDK通过接口反射得到字节码,然后把字节码转换成class(通过native方法)
静态代理实现的两种方式?
使用继承方式实现和使用聚合方式实现。
继承:代理对象继承目标对象,重写需要增强的方法。缺点:代理类过多,产生类爆炸。
聚合:目标对象和代理对象实现同一个接口,代理对象当中要包含目标对象。
动态代理的实现方式?
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
1.Interface InvocationHandler : 该接口中仅定义了一个方法,public Object invoke(Object obj,Method method,Object[] args),在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args是该方法的参数数组,这个抽象方法在代理类中动态实现。
2.Proxy 该类即为动态代理类,static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类在接口中声明过的方法)
所谓的动态代理是这样一种class:它是在运行时生成的class,该class需要实现一组interface,使用动态代理类时,必须实现InvocationHandler接口。
JDK动态代理和CGLIB动态代理的区别?
1.JDK动态代理只能代理实现了接口的类,没有实现接口的类不能实现JDK的动态代理。
2.CGLIB动态代理针对类来实现代理的,对指定目标类产生一个子类,通过方法拦截技术拦截所有的父类方法的调用。
动态代理实现的思路:
1.声明一段源码(动态产生代理)
2.编译源码(JDK Compiler API ),产生新的类(代理类)
3.将这个类load到内存中,产生一个新的对象(代理对象)
4.return 代理对象。
使用静态代理的例子:
1.首先创建业务逻辑接口
1 /** 2 * 接口 3 * @author Administrator 4 * 5 */ 6 public interface Moveable { 7 /** 8 * 9 * 接口中的方法 10 * @Description: TODO 11 * @returnType: void 12 */ 13 void move(); 14 }
2.创建实现类,实现接口中的方法
1 /** 2 * 实现类 3 * @author Administrator 4 * 5 */ 6 public class Car implements Moveable { 7 8 @Override 9 public void move() { 10 //实现开车 11 try { 12 Thread.sleep(new Random().nextInt(1000)); 13 System.out.println("汽车行驶中..."); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 19 }
3.使用继承方式实现对实现类的代理
1 /** 2 * 使用继承方式实现代理 3 * @author Administrator 4 * 5 */ 6 public class Car2 extends Car { 7 8 /* (non-Javadoc) 9 * @see com.wk.design.proxy.Car#move() 10 * 直接调用父类的move方法,这样就形成了一个Car2对Car的代理 11 */ 12 @Override 13 public void move() { 14 long startTime = System.currentTimeMillis(); 15 System.out.println("汽车开始行驶..."); 16 //使用继承的方式调用父类的move()方法 17 super.move(); 18 long endTime = System.currentTimeMillis(); 19 System.out.println("汽车行驶结束... 汽车行驶时间:"+(endTime-startTime)+"毫秒。"); 20 } 21 22 }
4.创建测试类
1 /** 2 * 测试类 3 * @author Administrator 4 * 5 */ 6 public class Test { 7 8 public static void main(String[] args) { 9 // Car car = new Car(); 10 // car.move(); 11 12 //使用继承方式实现代理 13 Moveable car2 = new Car2(); 14 car2.move(); 15 16 //使用聚合方式实现代理 17 // Car car = new Car(); 18 // Moveable car3 = new Car3(car); 19 // car3.move(); 20 21 } 22 }
5.使用聚合方式实现对实现类的代理
日志代理类
1 /** 2 * 3 * 日志代理类 4 * @author Administrator 5 * 6 */ 7 public class CarLogProxy implements Moveable { 8 9 /** 10 * 使用接口声明代理类 11 */ 12 private Moveable m; 13 /** 14 * 通过构造方法的参数传入代理类 15 * @param m 16 */ 17 public CarLogProxy(Moveable m) { 18 super(); 19 this.m = m; 20 } 21 22 @Override 23 public void move() { 24 System.out.println("日志开始"); 25 //调用代理类的方法 26 m.move(); 27 System.out.println("日志结束"); 28 29 } 30 31 }
时间代理类
1 /** 2 * 时间代理类 3 * @author Administrator 4 * 5 */ 6 public class CarTimeProxy implements Moveable { 7 8 /** 9 * 使用接口声明代理类 10 */ 11 private Moveable m; 12 /** 13 * 通过构造方法的参数传入代理类 14 * @param m 15 */ 16 public CarTimeProxy(Moveable m) { 17 super(); 18 this.m = m; 19 } 20 21 @Override 22 public void move() { 23 long startTime = System.currentTimeMillis(); 24 System.out.println("汽车开始行驶..."); 25 //调用代理类的方法 26 m.move(); 27 long endTime = System.currentTimeMillis(); 28 System.out.println("汽车行驶结束... 汽车行驶时间:"+(endTime-startTime)+"毫秒。"); 29 } 30 31 }
6.创建聚合方式测试类
1 /** 2 * 聚合代理测试类 3 * @author Administrator 4 * 5 */ 6 public class TestJuHeProxy { 7 public static void main(String[] args) { 8 Car car = new Car(); 9 //先记录日志,再记录时间 10 // CarTimeProxy ctp = new CarTimeProxy(car); 11 // CarLogProxy clp = new CarLogProxy(ctp); 12 // clp.move(); 13 14 //先记录时间,再记录日志 15 CarLogProxy clp = new CarLogProxy(car); 16 CarTimeProxy ctp = new CarTimeProxy(clp); 17 ctp.move(); 18 } 19 20 }
使用JDK动态代理实现的例子:
1.创建一个实现接口InvocationHandler的类,它必须实现invoke()方法。
2.创建被代理类及接口
3.调用Proxy的静态方法,创建一个代理类
4.通过代理调用方法
1 /** 2 * 使用jdk的动态代理 3 * @author Administrator 4 * 5 */ 6 public class TimeHandler implements InvocationHandler { 7 8 /** 9 * 被代理对象 10 */ 11 private Object target; 12 13 public TimeHandler(Object target) { 14 super(); 15 this.target = target; 16 } 17 18 /** 19 * 参数: 20 * proxy : 被代理对象 21 * method : 被代理对象的方法 22 * args : 方法的参数 23 * 返回值: 24 * Object 方法的返回值 25 */ 26 @Override 27 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 28 //在执行被代理对象的方法之前执行自己的逻辑 29 long startTime = System.currentTimeMillis(); 30 System.out.println("汽车开始行驶..."); 31 //执行被代理对象的方法 32 method.invoke(target); 33 //在执行被代理对象的方法之后执行自己的逻辑 34 long endTime = System.currentTimeMillis(); 35 System.out.println("汽车行驶结束... 汽车行驶时间:"+(endTime-startTime)+"毫秒。"); 36 return null; 37 } 38 39 }
1 /** 2 * JDK动态代理测试类 3 * @author Administrator 4 * 5 */ 6 public class JdkProxyTest { 7 8 public static void main(String[] args) { 9 Car car = new Car(); 10 InvocationHandler h = new TimeHandler(car); 11 Class<?> cls = car.getClass(); 12 /** 13 * 参数: 14 * loader : 类加载器 15 * interfaces : 实现接口 16 * h InvocationHandler 17 */ 18 Moveable m= (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); 19 //执行被代理类的方法 20 m.move(); 21 } 22 23 }
使用CGLIB动态代理实现的例子:
1.创建代理类,实现MethodInterceptor接口
2.使用Enhancer类创建代理方法
3.创建被代理类,并编写代理方法
4.通过代理调用方法
1 /** 2 * 使用cglib动态代理 3 * @author Administrator 4 * 5 */ 6 public class Train { 7 public void move(){ 8 System.out.println("火车行驶中。。。"); 9 } 10 }
1 public class CglibProxy implements MethodInterceptor { 2 3 private Enhancer enhancer = new Enhancer(); 4 //创建代理类方法 5 public Object getProxy(Class clazz){ 6 //设置创建子类的类 7 enhancer.setSuperclass(clazz); 8 //回调函数 9 enhancer.setCallback(this); 10 //创建并返回子类的实例 11 return enhancer.create(); 12 } 13 /** 14 * 作用:拦截所有目标类方法的调用 15 * obj : 目标类的实例 16 * m : 目标方法的反射对象 17 * args : 方法的参数 18 * proxy : 代理类的实例 19 */ 20 @Override 21 public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable { 22 //在调用方法时实现自己的业务逻辑 23 System.out.println("日志开始..."); 24 //代理类调用父类的方法 25 proxy.invokeSuper(obj, args); 26 //调用方法之后实现自己的业务逻辑 27 System.out.println("日志结束..."); 28 return null; 29 } 30 }
1 /** 2 * 使用cglib动态代理的测试类 3 * @author Administrator 4 * 5 */ 6 public class CglibProxyTest { 7 8 public static void main(String[] args) { 9 CglibProxy proxy = new CglibProxy(); 10 //传入要代理的类 11 Train t = (Train)proxy.getProxy(Train.class); 12 //执行方法 13 t.move(); 14 } 15 16 }