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中的代码完全解耦!快去试试吧!

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql 添加索引卡死_mysql添加索引,查询反而变慢

    mysql 添加索引卡死_mysql添加索引,查询反而变慢依照楼主的数据,我也造了400万数据:mysql>select*fromindex_testlimit5;id1id211111111112222222222111111111122222222221111111111id1创建索引执行确实是id2谓词条件比较快:mysql>select*fromindex_testwhereid1=11111;2097152…

    2022年5月22日
    128
  • 十大安全数字货币钱包排行榜_全球数字货币排行

    十大安全数字货币钱包排行榜_全球数字货币排行链客,专为开发者而生,有问必答!此文章来自区块链技术社区,未经允许拒绝转载。随着全球加密数字货币规模正在超高速的增长,数字货币的安全存储成为了关键的一环,也是决定其健康可持续发展的基石。市场崛起引发了全球对加密数字货币未来前景的关注和期待,数字货币钱包也就应运而生。大批投资者涌入币圈炒币,都离不开数字货币钱包,那么哪些数字货币钱包比较安全呢?下面我们就来一起探讨一下吧。1、Imtoken…

    2022年10月9日
    3
  • js网页特效

    js网页特效br 我平时特别喜欢研究网页特效 这里是平时 截流 下来的几个 JavaScript 网页特效 在此跟大家一起分享 br 反续排列 br 代码 在需要处加入 br nbsp br bdodir rtl 反续列 br 特点 当你需要把一段话反起来排列时 你怎么办呢 反起来一个一个地输入吗 只要使用以上代码 即可实现 br 自动刷新 br 代码 在网页的和之间加入 br metahttpequi refresh content

    2026年1月19日
    1
  • Java list转set;JDK8 下list 集合转Set 集合

    Java list转set;JDK8 下list 集合转Set 集合**List集合转Set集合**List集合和Set集合的区别在说如何List集合转Set集合之前我们先回顾一下List集合和Set集合的区别。他们之间比较细致的区别有蛮多的,不过比较粗糙地来说List和Set之间的区别有以下那么几点(1)llist和…

    2022年6月21日
    133
  • wing是什么_数独算法代码

    wing是什么_数独算法代码原题链接设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示:某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。此人从 A 点到 B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。输入格式第一行为一个整数N,表示 N×N 的方格图。接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。行和列编号从

    2022年8月9日
    8
  • 关键部分CCriticalSection使用

    关键部分CCriticalSection使用类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻仅仅同意一个线程存取资源或代码区。临界区在控制一次仅仅有一个线程改动数据或其他的控制资源时很实用。比如,在链表中添加一个结点就仅仅同意一次一个线程进行。通过使用CCriticalSection对象来控制链表,就能够达到这个目的。它就像是一把钥匙,哪个线程获得了它就获得了执行线程的权力,而把其他线程统统堵…

    2022年7月20日
    17

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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