【从0开始学习Java | 第23篇】动态代理

重阳,来啦!第23篇我们聊动态代理——这是Java面试中中高级岗必问、Spring AOP底层核心、MyBatis插件、RPC框架都离不开的知识点。

学会动态代理 = 直接秒杀 80% 的候选人!

一、先搞清楚:到底什么是代理?

生活例子:
你想找周杰伦签名 → 你不会直接找周杰伦 → 你找他的经纪人(代理)→ 经纪人帮你转达、加点要求(唱歌前先喝热水)、最后还是周杰伦签的名。

Java里的代理就是这个道理。

二、静态代理 vs 动态代理(超级清晰对比)

项目静态代理动态代理(今天主角)
代理类写法自己手动写一个代理类运行期间由JVM自动生成代理类
代码量一个接口要写一个代理类,接口多了爆炸无论多少接口,一个动态代理搞定
灵活性改个需求要改代理类代码完全动态,随时换增强逻辑
典型场景早期手写日志、事务Spring AOP、MyBatis Plugin、Dubbo等

结论:静态代理只是教学用的,真实项目99.9%用动态代理!

三、Java动态代理有两种方式(2026年仍然是这俩)

  1. JDK动态代理(必须实现接口)← 今天重点,面试问90%
  2. CGLIB动态代理(可以代理没有接口的类)← Spring默认用这个当目标类没接口

我们先把JDK动态代理吃透!

四、JDK动态代理完整实现(手敲3遍就能背出来)

场景:明星只有唱歌的功能,我们要在唱歌前后自动加“收钱”和“宣传”

// 1. 定义通用能力接口
public interface Star {
    void sing(String songName);   // 唱歌
    String dance();              // 跳舞(有返回值)
}
// 2. 真实明星:周杰伦
public class JayChou implements Star {
    @Override
    public void sing(String songName) {
        System.out.println("周杰伦唱:" + songName + ",收1000万!");
    }

    @Override
    public String dance() {
        System.out.println("周杰伦跳舞很帅~");
        return "舞王";
    }
}
// 3. 动态代理的核心:InvocationHandler(真正干活的地方!)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class StarHandler implements InvocationHandler {

    private final Star target;  // 被代理的真实对象

    public StarHandler(Star 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;  // 一定要返回!不然有返回值的方法会返回null
    }
}
// 4. 测试类:真正使用动态代理的地方
import java.lang.reflect.Proxy;

public class TestDynamicProxy {
    public static void main(String[] args) {

        // 真实对象
        Star jay = new JayChou();

        // 创建InvocationHandler
        StarHandler handler = new StarHandler(jay);

        // 关键三行:运行时动态生成代理对象!!!
        Star proxyStar = (Star) Proxy.newProxyInstance(
            jay.getClass().getClassLoader(),    // 类加载器
            jay.getClass().getInterfaces(),     // 被代理类实现的所有接口
            handler                             // InvocationHandler
        );

        // 使用代理对象(完全感觉不到背后有经纪人)
        proxyStar.sing("稻香");
        String danceResult = proxyStar.dance();
        System.out.println("跳舞评价:" + danceResult);

        // 看看代理对象到底是谁?
        System.out.println("代理对象真实类型:" + proxyStar.getClass().getName());
        // 输出:$Proxy0 (JVM动态生成的类)
    }
}

运行结果:

【经纪人】接活,谈价格,签合同...
周杰伦唱:稻香,收1000万!
【经纪人】宣传、发微博、收尾款...
【经纪人】接活,谈价格,签合同...
周杰伦跳舞很帅~
【经纪人】宣传、发微博、收尾款...
跳舞评价:舞王
代理对象真实类型:com.sun.proxy.$Proxy0

五、最重要的三行代码背下来(面试必问)

Star proxyStar = (Star) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new StarHandler(target)
);

这三行就是JDK动态代理的全部精华!

六、面试官最爱问的10个问题(全部背熟)

  1. 动态代理和静态代理区别?
  2. JDK动态代理为什么必须实现接口?
  3. Proxy.newProxyInstance 三个参数分别是什么?
  4. InvocationHandler 的 invoke 方法三个参数是什么?
  5. 如果被代理类没有接口,能用JDK动态代理吗?→ 不能!用CGLIB
  6. Spring中默认用哪个?→ 有接口用JDK,没有接口用CGLIB(Spring Boot2.x后默认CGLIB)
  7. 动态代理生成的 $Proxy0 是什么?能反编译看看吗?
  8. 方法有返回值时,invoke里要不要return?→ 必须return method.invoke(…)
  9. 动态代理的底层实现原理?→ 就是上面这套反射 + 动态生成字节码
  10. 能手写一个动态代理吗?→ 现在你能闭着眼敲出来了!

七、终极小练习(建议你现在就敲一遍)

需求:用动态代理实现一个通用日志记录器,对任意对象的所有方法调用都自动打印:

---> 开始执行:sing(稻香)
<--- sing执行结束,耗时:15ms

提示:可以在invoke里记录System.currentTimeMillis()

结语

重阳,恭喜你!
当你能完全手敲出上面的动态代理代码时,恭喜你已经超越了市面上 80% 的 Java 程序员!

这就是为什么Spring能用几行注解就实现事务、缓存、权限控制的底层原理!

下一节我们直接上 CGLIB动态代理 + 手撕Spring AOP底层原理,准备好了吗?

现在你可以:

  1. 把上面代码完整敲一遍(必须!)
  2. 告诉我你跑通了吗?有没有遇到什么问题?
  3. 想直接看CGLIB还是先来几个动态代理的变态面试题?

我在等你~ 来吧!冲!

文章已创建 4357

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部