代理(Proxy)

Administrator
发布于 2025-06-25 / 2 阅读
0
0

代理(Proxy)

✅ 一、什么是代理(Proxy)?

通俗一点讲:

代理就是代表别人做事的中间人,你通过代理对象去调用目标对象的方法,中间可以加点料,比如:记录日志、权限验证、事务控制、性能监控等。

在代码里,这通常指:

创建一个“代理对象”,用它去间接调用“目标对象”,在调用过程中可以做增强处理。


📌 举个例子:

你去访问一个数据库服务:

UserService userService = new UserServiceImpl();
userService.addUser("张三");

我们希望:

  • 调用前打印日志

  • 出异常时回滚事务

  • 调用后记录调用时间

直接在 UserServiceImpl 里写这些会污染业务逻辑。于是我们可以用一个“代理”:

UserService proxy = new UserServiceProxy(userService);
proxy.addUser("张三");

这个代理对象做的事情是:

public class UserServiceProxy implements UserService {
    private UserService target;
​
    public void addUser(String name) {
        System.out.println("日志:准备添加用户");
        try {
            target.addUser(name);
            System.out.println("日志:添加成功");
        } catch (Exception e) {
            System.out.println("日志:添加失败");
        }
    }
}

✅ 二、为什么需要代理?

🌟 核心目的:在不修改原有代码的基础上,实现功能增强。

🧩 场景总结:

场景

描述

日志记录

调用方法前后自动记录

权限控制

调用前检查是否有权限

性能监控

记录方法耗时

缓存

调用前先查缓存

事务管理

方法执行成功再提交,失败就回滚

远程调用

你调用的是一个“代理”,它实际向远程服务器发请求


✅ 三、代理的常见方式

类型

描述

技术

静态代理

自己写一个类来封装目标对象

代码量大,不灵活

动态代理

运行时自动生成代理类

JDK Proxy / CGLIB

框架级代理

Spring AOP、MyBatis Mapper、Feign 等都使用代理

本质还是动态代理


✅ 总结一句话:

代理是一种设计模式,目的是在不改变原始类的前提下,通过中间代理对象来“增强”方法执行的行为。

举例

✅ 1. 静态代理 — 自己写类封装目标对象

🌟 示例:用户服务加日志功能

// 接口
public interface UserService {
    void addUser(String name);
}
​
// 实现类
public class UserServiceImpl implements UserService {
    public void addUser(String name) {
        System.out.println("添加用户:" + name);
    }
}
​
// 静态代理类
public class UserServiceProxy implements UserService {
    private UserService target;
​
    public UserServiceProxy(UserService target) {
        this.target = target;
    }
​
    public void addUser(String name) {
        System.out.println("【日志】开始添加用户...");
        target.addUser(name);
        System.out.println("【日志】添加用户成功");
    }
}

✅ 使用:

UserService service = new UserServiceProxy(new UserServiceImpl());
service.addUser("张三");

✅ 2. 动态代理(运行时生成类)

🌟 示例:JDK 动态代理

public class LogHandler implements InvocationHandler {
    private Object target;
​
    public LogHandler(Object target) {
        this.target = target;
    }
​
    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("【日志】方法调用后");
        return result;
    }
}

✅ 使用 JDK Proxy 创建代理:

UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new LogHandler(target)
);
proxy.addUser("李四");

✅ 3. 框架级代理(Spring AOP / MyBatis Mapper / Feign)

🌟 示例 1:Spring AOP

@Aspect
@Component
public class LogAspect {
​
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeLog() {
        System.out.println("【AOP日志】方法执行前");
    }
}

自动代理由 Spring 在后台完成(JDK 或 CGLIB):

@Service
public class UserService {
    public void addUser(String name) {
        System.out.println("添加用户:" + name);
    }
}

✅ 使用:

userService.addUser("王五"); // 实际是代理对象调用,触发 AOP

🌟 示例 2:MyBatis Mapper

@Mapper
public interface UserMapper {
    User selectById(int id);
}

MyBatis 会用 JDK 动态代理创建这个接口的代理对象,自动生成 SQL 调用。


🌟 示例 3:Feign 远程调用(SpringCloud)

@FeignClient(name = "user-service")
public interface RemoteUserClient {
    @GetMapping("/user/{id}")
    User getUserById(@PathVariable Long id);
}

Feign 在运行时为这个接口创建 代理对象,发起 HTTP 请求。


✅ 总结对比表(含例子)

类型

描述

技术

示例

静态代理

手写代理类

传统写法

UserServiceProxy implements UserService

动态代理

运行时生成类(支持接口或类)

JDK / CGLIB

Proxy.newProxyInstance / CGLIB

框架级代理

框架封装,自动代理

本质是动态代理

Spring AOP、MyBatis Mapper、Feign


评论