JAVA代理-静态代理和动态代理详解
2017-03-13 15:58
477 查看
一 前言
代理在我们Java和Android学习中经常用到,例如Android插件化用到了大量的代理。代理包含静态代理和动态代理,我先来了解一下静态代理。二 静态代理
2.1 什么是静态代理
代理和被代理对象在代理之前就是确定的,他们都实现相同的接口或者继承相同的抽象类。2.2 实现静态代理方式
(1)继承法:代理类直接继承被代理类,实现其原有方法,并添加一些额外功能。(2)聚合方法:代理类实现相同的功能接口(实现相同接口,不同代理也可以进行相互代理),并在内声明一个被代理类的对象(类似封装),通过内部对象实现其原有方法,并添加额外功能。简单说
聚合:一个类中使用另一个类的对象。
我们举个例子是汽车行驶 ,记录汽车行驶的时间,分别用继承法和聚合方法实现。
1.继承法实现代码
Car被代理类,InheritProxyCar是代理类,InheritProxyCar类继承Car类
//汽车行驶接口 public interface Movable { void move(); } //Car被代理类 Car类实现 Movable接口 public class Car implements Movable { @Override public void move() { try { //随机睡眠充当行驶 Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 继承代理 * InheritProxyCar是代理类 * InheritProxyCar类继承Car类 */ public class InheritProxyCar extends Car { private final static String TAG = "ProxyCar"; public void move(){ long startTime = System.currentTimeMillis(); Log.e(TAG, "move: 开始行使"); super.move();//调用父类的move方法 long endTime = System.currentTimeMillis(); Log.e(TAG, "move: 汽车行驶结束的时间 "+(endTime-startTime)+"毫秒" ); } } //继承方法实现代理 InheritProxyCar是代理类 Car被代理类 InheritProxyCar inheritProxyCar =new InheritProxyCar(); //代理类执行 move方法 inheritProxyCar.move();
控制台日志
03-16 16:46:51.871 4110-4110/zhangqilu.com.proxy E/ProxyCar: move: 开始行使 03-16 16:46:52.869 4110-4110/zhangqilu.com.proxy E/ProxyCar: move: 汽车行驶总时间 998毫秒
2.聚合方法实现代码
//PolymerProxyCar是代理类实现Movable接口 public class PolymerProxyCar implements Movable { private final static String TAG = "PolymerProxyCar"; private Car car;//被代理类对象 public PolymerProxyCar(Car car){//被代理类对象传入 this.car = car; } @Override public void move() { long startTime = System.currentTimeMillis(); Log.e(TAG, "move: 开始行使"); car.move();//执行被代理类对象方法 long endTime = System.currentTimeMillis(); Log.e(TAG, "move: 汽车行驶总时间 "+(endTime-startTime)+"毫秒"); } } //创建代理对象实例 PolymerProxyCar polymerProxyCar = new PolymerProxyCar(new Car()); //代理类执行 move方法 polymerProxyCar.move();
控制台日志
03-16 17:03:05.246 18786-18786/zhangqilu.com.proxy E/PolymerProxyCar: move: 开始行使 03-16 17:03:05.903 18786-18786/zhangqilu.com.proxy E/PolymerProxyCar: move: 汽车行驶总时间 657毫秒
3静态代理的两种实现方式对比(继承方式和聚合方式)
继承的方式:如果使用继承的方式来实现我们代理功能的叠加,
我们的代理类会无限的膨胀下去。
聚合的方式:
由于代理类和被代理类都实现了相同的接口,那么代理类的构造参数就可以传入该相同的接口,这样在后面功能叠加的时候就可以传入其他功能的代理类,因为他们都实现了相同的父接口。从而达到功能叠加的作用。
聚合代理优于继承代理。因为实现功能叠加的情况下,聚合代理通过相互代理可以实现功能重用,而继承代理必须写多个类来实现多功能叠加。
聚合的方式比继承的方式灵活很多,通过聚合的方式,代理之间也是可以相互传递的,相互组合。
但静态代理只能代理一种类型的被代理类,换个类型的就不行了,这需要动态代理。
三 动态代理
动态代理我们主要说JDK动态代理和CGLIB动态代理。JDK动态代理 :只能代理实现接口的类,对没有实现接口的类不能实现JDK动态代理。
CGLIB动态代理:针对类来实现代理的,对指定目标类产生一个子类,通过方法拦截技术,拦截所有父类方法调用。
3.1 JDK动态代理
JDK动态代理 只能代理实现接口的类,对没有实现接口的类不能实现JDK动态代理JDK动态代理实现步骤:
1. 创建被代理的类及接口(示例代码 Car 类就是被代理类,Movable接口)。
2. 创建一个实现接口InvocationHandler的类,必须实现invoke方法(示例代码 CarInvocationHandler类)。
3. 调用Proxy的静态方法( newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)),创建一个代理类。
4. 通过代理调用方法。
我们来看看Proxy这个类
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
代码实现 Car类 和Movable接口代码在见静态代理:
public class CarInvocationHandler implements InvocationHandler { private final static String TAG = "CarInvocationHandler"; private Object targetObject; public CarInvocationHandler(Object object){ this.targetObject = object; } /** * @param proxy 被代理对象 * @param method 被代理对象的方法 * @param args 方法的参数 * @return 方法的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); Log.e(TAG, "move: 开始行使"); Object object = method.invoke(targetObject); long endTime = System.currentTimeMillis(); Log.e(TAG, "move: 汽车行驶总时间 "+(endTime-startTime)+"毫秒"); return object; } } //创建被代理类Car实例 Car car = new Car(); //创建CarInvocationHandler 实例 CarInvocationHandler carInvocationHandler = new CarInvocationHandler(car); //获取Car的类类型 Class aClass = car.getClass(); Movable movable = (Movable) Proxy.newProxyInstance(aClass.getClassLoader(),aClass.getInterfaces(),carInvocationHandler); movable.move();
控制台日志
03-16 19:25:58.845 29772-29772/zhangqilu.com.proxy E/CarInvocationHandler: move: 开始行使 03-16 19:25:59.270 29772-29772/zhangqilu.com.proxy E/CarInvocationHandler: move: 汽车行驶总时间 425毫秒
JDK动态代理局限性:jdk中的动态代理通过反射类Proxy和InvocationHandler回调接口实现,要求委托类必须实现一个接口,只能对该类接口中定义的方法实现代理,这在实际编程中有一定的局限性。这就引入了CJLIB动态代理。
3.2 CJLIB动态代理
CJLIB是一个开源项目,地址如下:https://github.com/cglib/cglib针对类来实现代理的,对指定目标类产生一个子类,通过方法拦截技术,拦截所有父类方法调用。
使用时我们要添加cglib依赖或者jar。
下面我们来看使用代码
// AirPlane 被代理类 public class AirPlane { public void move() { try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } public class CGLIBProxy implements MethodInterceptor{ private final static String TAG = "CGLIBProxy"; private Enhancer enhancer ; public Object getProxy(Class c1){ enhancer = new Enhancer(); enhancer.setSuperclass(c1);//设置创建子类的类 enhancer.setCallback(this);//设置回调 return enhancer.create(); } /** *拦截所有目标类方法的调用 * @param o 目标类的实例 * @param method 目标方法的反射对象 * @param objects 目标方法的参数 * @param methodProxy 代理类的实例 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { long startTime = System.currentTimeMillis(); Log.e(TAG, "move: 开始行使"); //代理类调用父类的方法 methodProxy.invokeSuper(o,objects); long endTime = System.currentTimeMillis(); Log.e(TAG, "move: 汽车行驶总时间 "+(endTime-startTime)+"毫秒" ); return null; } } 主函数执行 CGLIBProxy cglibProxy = new CGLIBProxy(); AirPlane airPlane = (AirPlane) cglibProxy.getProxy(AirPlane.class); airPlane.move();
注意:CGLIB不能对“final”修饰的类进行代理。
相关文章推荐
- java 静态代理和动态代理详解
- java 静态代理,jdk动态代理,CGLIB动态代理详解
- Java代理方式——静态代理和动态代理详解
- Java静态代理以及动态代理使用详解
- Java中静态代理和动态代理介绍
- Java 静态代理和动态代理
- java动态代理详解
- java 代理模式(静态代理+动态代理)
- Java中静态代理和动态代理介绍
- Java动态代理学习1——静态代理
- java 静态代理 动态代理 CGLib代理 浅析
- java 设计模式之四-代理模式 java静态代理和动态代理
- Java动态代理和静态代理的区别
- Java 静态代理和动态代理
- Java静态代理、动态代理实例
- Java中静态代理和动态代理介绍
- Java静态代理与动态代理
- java静态代理和动态代理
- Java 静态代理和动态代理
- Java动态代理学习2——静态代理和动态代理并对照spring的通知