前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >cglib实现动态代理_cglib和jdk动态代理

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

作者头像
全栈程序员站长
发布2022-11-03 10:38:39
2900
发布2022-11-03 10:38:39
举报
文章被收录于专栏:全栈程序员必看
一、前言

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

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

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

二、使用场景

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

三、主要组件
  • MethodInterceptor:方法拦截器 在调用目标方法时,cglib会回调MethodInterceptor接口方法,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
代码语言:javascript
复制
/** * 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依赖。

代码语言:javascript
复制
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.6</version>
</dependency>
  1. 定义目标类:UserService
代码语言:javascript
复制
public class UserService { 
   
    public String getUserName(Long userId) { 
   
        System.out.println("获取用户名..");
        return "user" + userId;
    }
}
  1. 实现MethodInterceptor,定义事务拦截器
代码语言:javascript
复制
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. 使用
代码语言:javascript
复制
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.cn/180061.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
    • 两者区别
    • 二、使用场景
    • 三、主要组件
    • 四、示例
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档