• java 动态代理模式(jdk和cglib)


     1 package proxy.dynamicproxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 
     7 
     8 /**
     9  * 需要实现InvocationHandler接口,内部维护一个实际类实例
    10  *
    11  */
    12 public class JdkProxyHandler implements InvocationHandler {
    13 
    14     private Object realObject;
    15 
    16     public Object proxy(Object realObject){
    17         this.realObject = realObject;
    18         return Proxy.newProxyInstance(this.realObject.getClass().getClassLoader(),
    19                 this.realObject.getClass().getInterfaces(), this);
    20     }
    21 
    22     /**
    23      *
    24      * @param proxy 动态生成的代理类实例
    25      * @param method 方法实例
    26      * @param args 方法参数
    27      * @return
    28      * @throws Throwable
    29      */
    30     @Override
    31     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    32         System.out.println("我是代理人:大明星唱歌开始前,我先宣传一下:巴拉巴拉。。。");
    33 
    34         // 调用实际类的方法,并传入参数,内部是反射机制
    35         Object ret = method.invoke(this.realObject, args);
    36 
    37         System.out.println("我是代理人:大明星唱歌完毕了,我来总结一下:巴拉巴拉。。。");
    38 
    39         return ret;
    40     }
    41 }
     1 package proxy.dynamicproxy;
     2 
     3 import net.sf.cglib.proxy.Enhancer;
     4 import net.sf.cglib.proxy.MethodInterceptor;
     5 import net.sf.cglib.proxy.MethodProxy;
     6 
     7 import java.lang.reflect.Method;
     8 
     9 /**
    10  * 需要实现MethodInterceptor接口
    11  * cglib相关依赖:
    12  * ant-1.6.2.jar
    13  * asm-3.1.jar
    14  * asm-util-3.1.jar
    15  * cglib-2.2.2.jar
    16  */
    17 public class CglibProxyHandler implements MethodInterceptor {
    18 
    19     public Object proxy(Object realObject){
    20 
    21         // 使用字节码增强器 四个固定步骤:
    22         // 1、new字节码增强器
    23         // 2、设置当前类实例为回调
    24         // 3、将实际类实例设置为父类
    25         // 4、创建一个代理类
    26         Enhancer enhancer = new Enhancer();
    27         enhancer.setCallback(this);
    28         enhancer.setSuperclass(realObject.getClass());
    29         // 这里会生成代理类、代理类的FastClass辅助类、实际类的FastClass辅助类
    30         // 辅助类为代理类和实际类的每个方法生成一个唯一的id
    31         // 用于在调用intercept方法时,通过唯一id就可以调用对应的方法
    32         // 不再走反射机制,提高性能
    33         return enhancer.create();
    34     }
    35 
    36     /**
    37      *
    38      * @param o 代理类的实例
    39      * @param method 方法实例
    40      * @param objects 方法参数
    41      * @param methodProxy 方法代理
    42      * @return
    43      * @throws Throwable
    44      */
    45     @Override
    46     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    47 
    48         System.out.println("我是代理人:大明星唱歌开始前,我先宣传一下:巴拉巴拉。。。");
    49 
    50         // 这里如果使用 method.invoke方法,就等同于走了反射机制去调用方法,性能不高
    51         // 而且还需要另外维护实际类实例
    52         // Object ret = method.invoke(this.realObject, objects);
    53 
    54         Object ret = methodProxy.invokeSuper(o, objects);
    55 
    56         System.out.println("我是代理人:大明星唱歌完毕了,我来总结一下:巴拉巴拉。。。");
    57 
    58         return ret;
    59     }
    60 }
     1 package proxy.dynamicproxy;
     2 
     3 import net.sf.cglib.core.DebuggingClassWriter;
     4 import proxy.staticproxy.IStar;
     5 import proxy.staticproxy.RealStar;
     6 
     7 public class Test {
     8     public static void main(String[] args) {
     9 
    10         /**
    11          * 还是以“代理人”和“大明星”为例
    12          * jdk动态代理:适用于大明星实现某接口的情况,且只能用于实现接口的情况
    13          *      不能用于未实现任何接口的类,因为生成的动态代理类要继承自Proxy、同时实现大明星接口。
    14          * cglib动态代理:适用于任何类。它是采用动态代理类直接继承大明星类的方式,将大明星当作父类
    15          *      覆写大明星类的所有方法(除final修饰的方法,wait方法,notify方法)
    16          *
    17          * 优缺点:
    18          * jdk方式,只能针对接口,底层直接写字节码的方式生成代理类,所以生成代理类速度快
    19          *      但是代理类执行方法时,通过反射的方式去执行,速度不如cglib方式
    20          * cglib方式,可以适用于任何类,底层使用ASM框架生成字节码,因为采用FastClass机制
    21          *      在生成代理类的同时还要生成代理类和大明星类的对应FastClass类(辅助类)
    22          *      这两个辅助类的作用是:对应FastClass辅助类会为代理类和大明星类的每一个方法
    23          *      (除final修饰的方法,wait方法,notify方法)生成唯一id,这样在后面的调用方法时
    24          *      不再通过反射去执行逻辑,而是直接根据id找到对应的方法去执行,提高性能,但相对的,生成字节码速度较慢
    25          */
    26         boolean isUseJdkProxy = false;
    27 
    28         if (isUseJdkProxy) {
    29             System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    30 
    31             IStar star = (IStar) new JdkProxyHandler().proxy(new RealStar());
    32             star.sing();
    33         }
    34         else {
    35 
    36             System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
    37                     "C:\Users\Administrator\IdeaProjects\untitled\cglibClass");
    38 
    39             IStar star = (IStar) new CglibProxyHandler().proxy(new RealStar());
    40 
    41             // 这一步里面的具体流程:
    42             // 动态代理类的sing方法 --> CglibProxyHandler的intercept方法
    43             //  --> 实际类执行前的行为代理 --> MethodProxy.invokeSuper方法
    44             //  --> 根据唯一id在FastClass里找到对应的实际方法
    45             //  --> 代理类的FastClass内部:让代理类调用实际方法
    46             //  --> 代理类的实际方法内部一般就是直接调用父类(被代理类)的方法
    47             //  --> 返回父类方法的返回值
    48             star.sing();
    49 
    50         }
    51     }
    52 }
  • 相关阅读:
    研修班第四次课笔记
    形象革命——穿搭
    对管理者的几点要求
    全链路压测
    项目管理最忌的5件事,千万不要忽视!
    2018年计划小目标(9月)PMP
    NLP是什么
    (深度好文)重构CMDB,避免运维之耻
    《转》我们不得不面对的中年职场危机
    项目管理,让自己更从容
  • 原文地址:https://www.cnblogs.com/cnblogszs/p/10366696.html
Copyright © 2020-2023  润新知