当前位置: 首页 > article >正文

Java 动态代理

目录

一、动态代理是什么

二、动态代理的实现原理

2.1 JDK 动态代理

2.2 CGLIB 动态代理

三、动态代理的应用场景


 

家人们,今天咱来聊聊 Java 里特别神奇的动态代理,这可是让代码灵活性和扩展性大幅提升的 “秘密武器”。很多厉害的 Java 框架都离不开它,理解并掌握它,能让你在 Java 编程的道路上更进一步。

一、动态代理是什么

想象一下,你要去买房子,但自己没时间,就找了个房产中介。中介帮你找房源、谈价格、办手续,你只需要告诉中介你的需求,剩下的事都由中介来处理。在 Java 里,动态代理就像这个中介,它可以在不修改目标对象代码的情况下,为目标对象添加额外的功能。比如在方法执行前记录日志,在方法执行后进行事务提交等。动态代理基于反射机制实现,在运行时动态创建代理对象,为我们的代码赋予了极大的灵活性。

二、动态代理的实现原理

Java 中实现动态代理主要有两种方式:JDK 动态代理和 CGLIB 动态代理。

2.1 JDK 动态代理

JDK 动态代理是 Java 自带的动态代理实现方式,它只能为实现了接口的类创建代理对象。JDK 动态代理主要涉及两个核心类:ProxyInvocationHandler

  • Proxy:用于创建代理对象,它提供了一个静态方法newProxyInstance(),通过这个方法可以创建一个代理对象。这个方法接收三个参数:类加载器、目标对象实现的接口数组、实现了InvocationHandler接口的对象。
  • InvocationHandler:是一个接口,它定义了一个invoke()方法。当通过代理对象调用方法时,实际上会调用invoke()方法,在这个方法中我们可以添加额外的逻辑,然后再调用目标对象的方法。

下面是一个 JDK 动态代理的示例代码:

// 定义一个接口
interface HelloService {
    void sayHello();
}

// 实现接口的类
class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello() {
        System.out.println("Hello, world!");
    }
}

// 定义一个InvocationHandler实现类
class MyInvocationHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用前的额外逻辑,比如记录日志");
        Object result = method.invoke(target, args);
        System.out.println("方法调用后的额外逻辑,比如事务提交");
        return result;
    }
}

public class JDKProxyExample {
    public static void main(String[] args) {
        HelloService target = new HelloServiceImpl();
        HelloService proxy = (HelloService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new MyInvocationHandler(target));
        proxy.sayHello();
    }
}

在这个示例中,我们创建了一个HelloService接口和实现该接口的HelloServiceImpl类。然后定义了MyInvocationHandler类,实现了InvocationHandler接口,在invoke()方法中添加了方法调用前后的额外逻辑。最后使用Proxy.newProxyInstance()方法创建代理对象,通过代理对象调用sayHello方法时,就会执行我们添加的额外逻辑。

2.2 CGLIB 动态代理

CGLIB(Code Generation Library)是一个第三方的代码生成库,它可以为没有实现接口的类创建代理对象。CGLIB 通过继承目标类,创建一个子类,在子类中重写父类的方法,从而实现代理功能。使用 CGLIB 需要引入相应的依赖。

下面是一个 CGLIB 动态代理的示例代码:

<!-- 在Maven项目中添加CGLIB依赖 -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

// 没有实现接口的类
class UserService {
    public void addUser() {
        System.out.println("添加用户");
    }
}

// 定义一个MethodInterceptor实现类
class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("方法调用前的额外逻辑");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("方法调用后的额外逻辑");
        return result;
    }
}

public class CGLIBProxyExample {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new MyMethodInterceptor());
        UserService proxy = (UserService) enhancer.create();
        proxy.addUser();
    }
}

在这个示例中,我们定义了一个没有实现接口的UserService类。然后创建了MyMethodInterceptor类,实现了MethodInterceptor接口,在intercept()方法中添加了额外逻辑。最后使用Enhancer类创建代理对象,设置代理对象的父类为UserService,并设置回调函数为MyMethodInterceptor。通过代理对象调用addUser方法时,就会执行我们添加的额外逻辑。

三、动态代理的应用场景

动态代理在很多 Java 框架中都有广泛应用,比如在 Spring AOP(面向切面编程)中,动态代理是实现 AOP 的核心技术之一。通过动态代理,Spring 可以在不修改目标对象代码的情况下,为目标对象添加事务管理、日志记录、权限控制等功能。在 MyBatis 框架中,动态代理也用于创建 Mapper 接口的代理对象,实现 SQL 语句的执行和结果映射。

家人们,动态代理虽然有点难理解,但一旦掌握,就能让你的代码变得超级灵活强大。要是在学习过程中有什么疑问,随时找我交流,咱们一起把这个技术吃透!


http://www.kler.cn/a/516631.html

相关文章:

  • 常见的二进制序列化方法汇总
  • 缓存商品、购物车(day07)
  • 工程数学速记手册(下)
  • 工作~酒场指南
  • 嵌入式知识点总结 操作系统 专题提升(一)-进程和线程
  • 使用 `scanpy` 观察 `AnnData` 对象内部数据结构
  • C++AVL树(一)详解
  • Alibaba Spring Cloud 二 Seata 的详细介绍、使用场景以及集成方法
  • Docker—搭建Harbor和阿里云私有仓库
  • 一文讲清楚深度学习和机器学习
  • CentOS7使用源码安装PHP8教程整理
  • 告警架构高可用怎么做?
  • RCWL-93000一款微波雷达传感器模块
  • 关闭在后台运行的 MySQL 容器
  • 一文大白话讲清楚webpack基本使用——5——babel的配置和使用
  • 高效简洁的个人网站解决方案:Hugo建站与远程访问详细教程
  • 消息队列篇--原理篇--RocketMQ和Kafka对比分析
  • K8S中Pod控制器之CronJob(CJ)控制器
  • 汇编语法及相关指令
  • 学生管理系统C++版(简单版)详解
  • 东南亚静态住宅IP的优势与应用
  • 关于java实现word(docx、doc)转html的解决方案
  • ubuntu 布暑python项目
  • 数据统计–图形报表(day11)
  • c语言中的数组(上)
  • FTP 与 LFTP 命令的介绍及常用功能