gball个人知识库
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)

ggball

后端界的小学生
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)
  • 面试

  • 数据库

  • linux

  • node

  • tensorFlow

  • 基础组件

  • 基础知识

    • java集合

    • jvm调优

    • java并发编程

    • java网络编程

    • java8新特性

    • javaAgent

    • java高级

      • 动态代理
        • CGLIB动态代理使用介绍
  • 算法与设计模式

  • 分布式

  • 疑难杂症

  • go学习之旅

  • 极客时间

  • 知识库
  • 基础知识
  • java高级
ggball
2023-08-17

动态代理

# CGLIB动态代理使用介绍

# 一、前言

说到动态代理,开发者们第一时间想到的就是JDK动态代理 (opens new window)和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;
1
2
3
4
5
6
7
8

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

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

# 四、示例

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

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.6</version>
</dependency>
1
2
3
4
5
  1. 定义目标类:UserService
public class UserService {
    public String getUserName(Long userId) {
        System.out.println("获取用户名..");
        return "user" + userId;
    }
}
1
2
3
4
5
6
  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();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

一般把获取代理实例的方法,也放在自定义的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);
}
1
2
3
4
5
6
7
8
9
10

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

上次更新: 2025/06/04, 15:06:15
javaAgent初探
设计模式概览

← javaAgent初探 设计模式概览→

最近更新
01
AIIDE
03-07
02
githubActionCICD实战
03-07
03
windows安装Deep-Live-Cam教程
08-11
更多文章>
Theme by Vdoing
总访问量 次 | 总访客数 人
| Copyright © 2021-2025 ggball | 赣ICP备2021008769号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×

评论

  • 评论 ssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
×