标签:intercept 注意 back jdk动态代理 math override over 优点 temp
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介,代理模式也叫做委托模式。
代理模式的主要优点有:
代理模式的主要缺点是:
代理的实现是有多种方式的,常见就是静态代理、动态代理(JDK动态代理、CGLIB动态代理),因此接下来一一讲解这三种实现方式。
静态代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问。代理模式的主要角色如下:
其结构图如图所示。
代码如下:
public class ProxyTest { public static void main(String[] args) { Proxy proxy=new Proxy(); proxy.Request(); } } //抽象主题 interface Subject { void Request(); } //真实主题 class RealSubject implements Subject { public void Request() { System.out.println("访问真实主题方法..."); } } //代理 class Proxy implements Subject { private RealSubject realSubject; public void Request() { if (realSubject==null) { realSubject=new RealSubject(); } preRequest(); realSubject.Request(); postRequest(); } public void preRequest() { System.out.println("访问真实主题之前的预处理。"); } public void postRequest() { System.out.println("访问真实主题之后的后续处理。"); } }
输出结果为:
访问真实主题之前的预处理。
访问真实主题方法...
访问真实主题之后的后续处理。
静态代理优缺点
静态代理会手动创建很多代理类的问题,动态代理就解决了这个问题,其中一种就是JDK自带动态代理。其通过自己实现InvocationHandler来实现动态代理,真正的代理对象由JDK再运行时为我们动态的来创建。其结构图如下:
本例展示一个车启动的例子,其代码实现如下:
//目标类接口 interface Car{ void run(); } //目标类 class Benz implements Car{ @Override public void run() { System.out.println("奔驰车跑起来了"); } } class CarUtils{ public static void methodBefore() { System.out.println("跑之前要点火 ... ..."); } public static void methodAfter() { System.out.println("跑起来后会换挡 ... ..."); } } class MyInvocationHandle implements InvocationHandler{ private Object target; public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { CarUtils.methodBefore(); method.invoke(target, args); CarUtils.methodAfter(); return null; } } //生产代理对象的工厂 class MyProxyFactory{ public static Object getProxy(Object target) { MyInvocationHandle handle = new MyInvocationHandle(); handle.setTarget(target); Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handle); return proxy; } } public class ProxyTest { public static void main(String[] args) { Car car = new Benz(); Car proxy =(Car) MyProxyFactory.getProxy(car); proxy.run(); } }
注意Proxy.newProxyInstance()方法接受三个参数:
ClassLoader loader
: 指定当前目标对象使用的类加载器,获取加载器的方法是固定的Class<?>[] interfaces
: 指定目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler:
指定
动态处理器,
执行目标对象的方法时,会触发事件处理器的方法JDK动态代理总结:虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。但是JDK自带动态代理只能支持实现了Interface的类。
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLIB了。CGLIB采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。
我们通过实现MethodInterceptor来实现CGLIB动态代理,CGLIB动态代理类图关系如下图所示:
代码如下:
class ArraySort{ public void quickSort(int[] arr) { Arrays.sort(arr); } public void selectSort(int[] arr) { for (int i = 0; i < arr.length; i++) { for (int j = i+1; j < arr.length; j++) { if (arr[i] > arr[j]) { int temp = 0; temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } } public void bubbleSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = 0; temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } } class CglibInteceptor implements MethodInterceptor { private Object object; public CglibInteceptor(Object object) { this.object = object; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("CGLIB动态代理执行前"); Object result = method.invoke(object,objects); System.out.println("CGLIB动态代理执行后"); return result; } public Object getProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setCallback(this); enhancer.setSuperclass(object.getClass()); return enhancer.create(); } }
public class CGLibProxyTest { public static void main(String[] args) { int[] arr = new int[100000]; for (int i = 0; i < arr.length; i++) { arr[i] = (int) (Math.random() * 1000); } ArraySort arraySort = new ArraySort(); arraySort = (ArraySort) new CglibInteceptor(arraySort).getProxy(); arraySort.bubbleSort(arr); arraySort.selectSort(arr); arraySort.quickSort(arr); } }
CGLIB代理总结: CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。
以上就是三种代理具体实现。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。在Spring的AOP编程中: 如果加入容器的目标对象有实现接口,用JDK代理;如果目标对象没有实现接口,用Cglib代理。
标签:intercept 注意 back jdk动态代理 math override over 优点 temp
原文地址:https://www.cnblogs.com/jing99/p/12596334.html