cglib实现动态代理_cglib和jdk动态代理

cglib实现动态代理_cglib和jdk动态代理一、前言  说到动态代理,开发者们第一时间想到的就是JDK动态代理和cglib动态代理。了解Spring的同学应该知道,SpringAOP功能的底层实现,就是使用的这两种动态代理。两者区别JDK的动态代理机制只能代理实现了接口的类,而没有实现接口的类就不能实现JDK的动态代理;cglib动态代理是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强。使用cglib实现动态代理,完全不受代理类必须实现接口的限制。cglib底层采用ASM字节码生成框架,使用字节码技术生

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、前言

  说到动态代理,开发者们第一时间想到的就是JDK动态代理cglib动态代理。了解Spring的同学应该知道,Spring AOP功能的底层实现,就是使用的这两种动态代理。

两者区别
  • JDK的动态代理机制只能代理实现了接口的类,而没有实现接口的类就不能实现JDK的动态代理;
  • cglib动态代理是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强。使用cglib实现动态代理,完全不受代理类必须实现接口的限制。
  • cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。

因为cglib动态代理采用的是继承,所以不能对final修饰的类进行代理

二、使用场景

  “代理”二字,从字面意思上来看,就是代替目标类做一些预处理的事情。常用来把一些通用的与业务逻辑无关的逻辑放到代理类中处理。如:事务管理、参数校验、统计接口访问量、调用前后打印日志等等。

三、主要组件

  • MethodInterceptor:方法拦截器
    在调用目标方法时,cglib会回调MethodInterceptor接口方法,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
/** * proxy:代理对象,CGLib动态生成的代理类实例 * method:目标对象的方法,上文中实体类所调用的被代理的方法引用 * args:目标对象方法的参数列表,参数值列表 * methodProxy:代理对象的方法,生成的代理类对方法的代理引用 */
 public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                           MethodProxy proxy) throws Throwable;

可以使用methodProxy.invokeSuper(obj,arg)来调用代理类实例上的proxy方法的父类方法,这样比反射调用方法快!

  • Enhancer:字节码增强器
    用来关联目标类代理处理逻辑类,并创建代理实例。

四、示例

需求:在进入方法前开启事务,方法调用结束后关闭事务。
由于cglib是一个第三方的框架,不是JDK自带的,所以要引入maven依赖。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.6</version>
</dependency>
  1. 定义目标类:UserService
public class UserService { 
   
    public String getUserName(Long userId) { 
   
        System.out.println("获取用户名..");
        return "user" + userId;
    }
}
  1. 实现MethodInterceptor,定义事务拦截器
public class TransactionInterceptor implements MethodInterceptor { 
   
    Object target;

    public TransactionInterceptor(Object target) { 
   
        this.target = target;
    }

    /** * proxy:代理对象,CGLib动态生成的代理类实例 * method:目标对象的方法,上文中实体类所调用的被代理的方法引用 * args:目标对象方法的参数列表,参数值列表 * methodProxy:代理对象的方法,生成的代理类对方法的代理引用 */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 
   
        System.out.println("开启事务..." + proxy.getClass().getSimpleName());
        Object objValue = null;
        try { 
   
            // 反射调用目标类方法
            objValue = method.invoke(target, args);
            System.out.println("返回值为:" + objValue);
        } catch (Exception e) { 
   
            System.out.println("调用异常!" + e.getMessage());
        } finally { 
   
            System.out.println("调用结束,关闭事务...");
        }
        return objValue;
    }

    /** * 获取代理实例 */
    public Object getTargetProxy() { 
   
        // Enhancer类是cglib中的一个字节码增强器,它可以方便的为你所要处理的类进行扩展
        Enhancer eh = new Enhancer();
        // 1.将目标对象所在的类作为Enhancer类的父类
        eh.setSuperclass(target.getClass());
        // 2.通过实现MethodInterceptor实现方法回调
        eh.setCallback(this);
        // 3. 创建代理实例
        return eh.create();
    }
}

一般把获取代理实例的方法,也放在自定义的MethodInterceptor中。

  1. 使用
public static void main(String[] args) { 
   
    // 1. 创建目标实例
    UserService userService = new UserService();
    // 2. 创建事务拦截器
    TransactionInterceptor transactionInterceptor = new TransactionInterceptor(userService);
    // 3. 创建代理实例
    UserService userServiceProxy = (UserService) transactionInterceptor.getTargetProxy();
    // 4. 使用代理实例调用目标方法
    userServiceProxy.getUserName(6L);
}

在这里插入图片描述
这样便达到了代理的效果,开启、关闭事务的代码模块化到自定义的MethodInterceptor中,与UserService中的代码完全解耦!快去试试吧!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/180061.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • pycharm配置远程服务器解释器_pycharm中使用jupyter

    pycharm配置远程服务器解释器_pycharm中使用jupyter前段时间,在pycharm里配置了远程的Python解释器,然后在使用过程中,发现pycharm原来是可以使用Jupyter的文件,而且还可以配置远程的Jupyter环境,今天试了一下,一开始还是走了一些坑,今天梳理一下。我们可以通过以下方式创建JupyterNotebook文件:根据自己需要,给文件命名。然后就创建了一个后缀为ipynb文件。用一段测试代码测试一下:importnumpyasnpx=np.arange(15,dtype=np.int64)

  • jsessionId的使用

    jsessionId的使用jsessionid的作用  在web应用的开发中我们会经常看到这样的url:http://www.xxx.com/xxx_app;jsessionid=xxxxxxxxxx?a=x&amp;b=x…。这跟一般的url基本一样,只有一个地方有区别,那就是“;jessionid=xxxxxxxx”。这个参数有时候有,有时候又没有,说它是参数可又跟一般传递的参数不同,它是紧跟在url后面用分号…

  • mysql常用函数参考

    推荐:http://www.cnblogs.com/roucheng/p/ubuntumysql.htmlend

    2021年12月24日
  • 御用导航提示提醒_AR实景导航,让你安全驾驶,不再“绕弯”

    御用导航提示提醒_AR实景导航,让你安全驾驶,不再“绕弯”虽然现在手机、车机的导航能力越来越强,但是当我们遇到不熟悉的路况,特别是在立交桥和高速匝道口时还是会出拐错弯或错过路口的情况,而往往错过了一个出口,就意味着你要多跑几公里甚至更远!!基于当前复杂的行车环境,EASYOWN联合高德地图,推出了AR系列行车记录仪,在应对相关行车痛点问题上拥有完美的解决方案。EASYOWN-E3AR行车记录仪通过连接高德地图,在真实的路况信息中,加入3D…

  • Android ListView 的简单用法

    Android ListView 的简单用法参考API和《第一行代码》-ListViewisaviewgroupthatdisplaysalistofscrollableitems.ThelistitemsareautomaticallyinsertedtothelistusinganAdapterthatpullscontentfromasourcesuchasan…

  • linux安装jdk8[通俗易懂]

    目录1.下载jdk82.源码包解压3.配置jdk环境变量4.测试是否安装成功操作系统:Centos6.464位工具:Xftp5、Xshell51.下载jdk8方法一:官网手动下载下载Linux环境下的jdk1.8http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号