笔友城堡 - 可定义的个人主页

前言

简单记录一下Java面试中的静态代理动态代理相关知识,记录一下,方便自己查阅。

正文

什么是代理

代理模式:为对象提供一个代理对象,由代理对象控制对目标对象的访问。

  1. 可以在不修改目标对象代码的情况下增强功能

  2. 典型场景:日志、事务、权限、监控、AOP

静态代理

定义:代理类在编译期就已经存在,手动编写代理类

示例

接口

public interface UserService {
    void save();
}

目标类

public class UserServiceImpl implements UserService {
    public void save() {
        System.out.println("保存用户");
    }
}

代理类

public class UserServiceProxy implements UserService {
    private UserService target;
    public UserServiceProxy(UserService target) {
        this.target = target;
    }
    @Override
    public void save() {
        System.out.println("开始事务");
        target.save();
        System.out.println("提交事务");
    }
}

使用

UserService service = new UserServiceProxy(new UserServiceImpl());
service.save();
特点
  1. 结构简单,容易理解

  2. 每个接口都要写一个代理类

  3. 接口变动 → 代理类也要改

  4. 扩展性差

动态代理

定义:代理类在运行时动态生成,不需要手写代理类。

Java 中主要有两种:

动态代理方式核心机制
JDK 动态代理反射 + 接口
CGLIB 动态代理(这里不介绍)字节码增强(继承)

这里我只介绍JDK动态代理

JDK 动态代理
  • 目标类必须实现接口

  • 使用java.lang.reflect.Proxy

PS:JDK动态代理基于接口和反射实现,要求目标类实现接口

示例
public class LogHandler implements InvocationHandler {
    private Object target;
    public LogHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法前:" + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("方法后:" + method.getName());
        return result;
    }
}
UserService proxy = (UserService) Proxy.newProxyInstance(
        UserService.class.getClassLoader(),
        new Class[]{UserService.class},
        new LogHandler(new UserServiceImpl())
);

proxy.save();
原理
  • 运行时生成一个实现了接口的代理类

  • 方法调用 → 转发给 InvocationHandler.invoke()

  • 代理类名类似:

    com.sun.proxy.$Proxy0

静态代理 vs 动态代理

对比点静态代理JDK 动态代理
代理类生成时机编译期运行期
是否手写代理类
是否依赖接口
实现方式实现接口反射
性能稍低

小结

  1. 静态代理是在编译期就存在的代理类

    需要手动实现,耦合度高、扩展性差

  2. 动态代理是在运行期动态生成代理类

    无需手写代理类,扩展性更强

  3. Java中常见的动态代理有两种:

    1. JDK动态代理基于接口和反射实现,要求目标类实现接口

    1. CGLIB通过继承目标类生成子类来实现代理,不要求接口,但不能代理final类和方法

问答
  1. 为什么 JDK 动态代理只能代理接口?

    因为生成的代理类已经继承了Proxy类,Java 不支持多继承,只能通过实现接口。

  1. 动态代理和装饰器模式的区别?

    • 代理:控制访问

    • 装饰器:增强功能

    • 实现方式相似,但语义不同

参考文章

AI

相关网址

笔友城堡 - 可定义的个人主页

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...