那用到动态代理,关键的特征又是什么呢

文章目录

      • [特征一:出现了核心的 API "老三样"](#特征一:出现了核心的 API “老三样”)
        • [🧱 典型的 JDK 动态代理代码长这样:](#🧱 典型的 JDK 动态代理代码长这样:)
      • [特征二:出现了 `Enhancer` 和 `MethodInterceptor`(CGLIB 动态代理)](#特征二:出现了 EnhancerMethodInterceptor(CGLIB 动态代理))
      • 特征三:打印对象类名时,带有特殊的"魔法后缀"
      • [特征四:经典的"方法拦截"与 AOP(面向切面编程)](#特征四:经典的“方法拦截”与 AOP(面向切面编程))
      • [总结:反射 VS 动态代理](#总结:反射 VS 动态代理)

要判断一段代码是不是用到了动态代理(Dynamic Proxy),核心的特征可以用一句话来概括:

💡 你手头明明没有这个接口的实现类(没写过实现类的代码),但程序在运行的时候,却凭空产生了一个"神秘的代理对象",不仅能帮你执行方法,还能在方法前后偷偷"加料"(比如加日志、加事务)。

动态代理根据实现技术不同,分为两种:JDK 动态代理CGLIB 动态代理。只要你看到代码里出现以下核心特征,那就是用到了动态代理:


特征一:出现了核心的 API "老三样"

如果是用 JDK 动态代理(基于接口),你的代码里百分之百会包含以下三个固定班底:

  1. InvocationHandler 接口 :这是代理对象的"灵魂"。所有被代理的方法被调用时,都会被塞进它的 invoke() 方法里处理。
  2. Proxy.newProxyInstance() 方法:这是动态代理的"生产线"。调用它,就会在内存中凭空造出一个代理对象。
  3. Method.invoke():在拦截完之后,用来真正执行原本的方法(这里通常会结合反射)。
🧱 典型的 JDK 动态代理代码长这样:
java 复制代码
// 1. 实现 InvocationHandler 接口
public class MyLogHandler implements InvocationHandler {
    private Object target; // 被代理的真实对象

    public MyLogHandler(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;
    }
}

// 2. 在业务中用 Proxy 凭空凭造代理对象
UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class[] { UserService.class }, // 必须提供接口
    new MyLogHandler(new UserServiceImpl())
);

// 3. 调用代理对象
userServiceProxy.createUser(); 

特征二:出现了 EnhancerMethodInterceptor(CGLIB 动态代理)

如果你的类没有实现任何接口 ,JDK 代理就失效了。这时候框架会转而使用 CGLIB (基于继承)。

如果代码中出现了以下类,说明使用的是 CGLIB 动态代理:

  • Enhancer:CGLIB 的动态类生成器。
  • MethodInterceptor :方法拦截器,里面的 intercept() 方法等同于上面的 invoke()

特征三:打印对象类名时,带有特殊的"魔法后缀"

如果你在调试程序时,把一个对象 System.out.println(obj.getClass().getName()) 打印出来,它的类名不是你熟悉的 com.walissh.service.UserServiceImpl,而是变成了类似下面这种怪异的字符串:

  • JDK 代理的特征类名com.sun.proxy.$Proxy24(带有 $Proxy 字样)
  • CGLIB 代理的特征类名com.walissh.service.UserServiceImpl$$EnhancerBySpringCGLIB$$b3f27a4e(带有 $$EnhancerBy... 字样)

只要看到类名里带了这些后缀,说明这个对象根本不是你写出来的,而是框架在内存中动态织入生成的代理类。


特征四:经典的"方法拦截"与 AOP(面向切面编程)

在写 Spring 业务代码时,动态代理最核心的特征就是 AOP(切面)

比如你在方法上加了一个 @Transactional(声明式事务)

java 复制代码
@Transactional
public void transferMoney() {
    // 你的业务代码:转账 100 块
}

你明明只写了"转账 100 块"的代码,为什么程序能自动帮你开启事务、提交事务、甚至在报错时自动回滚事务?

  • 幕后黑手就是动态代理 :Spring 在启动时,用动态代理在内存中悄悄把你的类包装了一下,生成了一个代理类。当别人调用 transferMoney() 时,实际上调用的是代理类。代理类先帮你执行 connection.setAutoCommit(false)(开启事务),然后再去调用你写的转账代码,最后帮你 commit()

总结:反射 VS 动态代理

  • 反射(Reflection) 是:原本 这个类,但我写代码时不知道它是谁,我在运行时动态地去探查和调用它。
  • 动态代理(Dynamic Proxy) 是:原本没有 这个实现类,我通过规则在运行时让 JVM 凭空造一个出来,用来在不修改原代码的前提下,给方法神不知鬼不觉地"包装、加料"。
相关推荐
维天说8 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane19948 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了9 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品9 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘9 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记10 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
糖果店的幽灵10 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph
极光代码工作室11 小时前
基于SpringBoot的在线博客系统
java·springboot·web开发·后端开发
我是唐青枫11 小时前
Java Spring Security 实战详解:从登录认证到 JWT 权限控制
java·spring
ihuyigui12 小时前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端