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

文章目录

      • [特征一:出现了核心的 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 凭空造一个出来,用来在不修改原代码的前提下,给方法神不知鬼不觉地"包装、加料"。
相关推荐
都说名字长不会被发现1 小时前
Spring Boot Starter 中间件账号密码加密方案设计与实现
java·spring boot·后端·中间件
摇滚侠1 小时前
Maven 依赖范围
java·maven
AKA__Zas1 小时前
芝士算法(滑动窗口片 2.0)
java·算法·leetcode·学习方法
Zella折耳根4 小时前
复习篇-常用实用类
java
devilnumber9 小时前
Java 递归算法 详解 + 核心要点 + 实战运用 + 避坑指南
java·开发语言·算法
asdfg125896311 小时前
JavaBean是什么?怎么理解?有什么用途?
java·开发语言
摇滚侠12 小时前
SpringMVC 入门到实战 文件上传 75-77
java·后端·spring·maven·intellij-idea
GIS数据转换器13 小时前
城市排水生命线安全运行监测平台深度解析
java·运维·人工智能·python·安全·数据挖掘·无人机
华如锦13 小时前
面了很多 Java转AI Agent方向,一些面试题总结
java·开发语言·人工智能·python·ai