Skip to content
清晨的一缕阳光
返回

代理模式实战详解

代理模式实战详解

代理模式是最常用的设计模式,Spring AOP、RPC 框架都基于代理实现。

一、代理模式基础

1.1 什么是代理

代理模式 = 为对象提供一种代理以控制对这个对象的访问

角色:
- 抽象主题(Subject):接口
- 真实主题(RealSubject):实际对象
- 代理(Proxy):代理对象

1.2 应用场景

1. 远程代理(RPC)
2. 虚拟代理(延迟加载)
3. 安全代理(权限控制)
4. 智能代理(日志、缓存)
5. AOP(事务、日志)

二、静态代理

2.1 实现

// 抽象主题
interface UserService {
    void addUser(String name);
}

// 真实主题
class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
}

// 代理
class UserServiceProxy implements UserService {
    private UserService target;
    
    public UserServiceProxy(UserService target) {
        this.target = target;
    }
    
    @Override
    public void addUser(String name) {
        System.out.println("Before addUser");
        target.addUser(name);
        System.out.println("After addUser");
    }
}

// 使用
UserService target = new UserServiceImpl();
UserService proxy = new UserServiceProxy(target);
proxy.addUser("Alice");

2.2 优缺点

优点:
- 简单易懂
- 编译期检查

缺点:
- 每个类需要单独代理
- 代码重复
- 难以维护

三、JDK 动态代理

3.1 实现原理

// 核心类
Proxy.newProxyInstance(
    ClassLoader loader,           // 类加载器
    Class<?>[] interfaces,        // 接口数组
    InvocationHandler h           // 调用处理器
)

3.2 实现示例

// 接口
interface UserService {
    void addUser(String name);
    void deleteUser(Long id);
}

// 实现类
class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
    
    @Override
    public void deleteUser(Long id) {
        System.out.println("Deleting user: " + id);
    }
}

// 代理工厂
public class ProxyFactory {
    
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                System.out.println("Before: " + method.getName());
                Object result = method.invoke(target, args);
                System.out.println("After: " + method.getName());
                return result;
            }
        );
    }
}

// 使用
UserService target = new UserServiceImpl();
UserService proxy = ProxyFactory.createProxy(target);
proxy.addUser("Alice");
proxy.deleteUser(1L);

3.3 InvocationHandler

// 自定义 InvocationHandler
public class LoggingHandler implements InvocationHandler {
    private final Object target;
    
    public LoggingHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable {
        long start = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long cost = System.currentTimeMillis() - start;
        System.out.println(method.getName() + " cost: " + cost + "ms");
        return result;
    }
}

// 使用
UserService proxy = (UserService) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new LoggingHandler(target)
);

四、CGLIB 动态代理

4.1 为什么需要 CGLIB

JDK 动态代理限制:
- 只能代理接口
- 不能代理类

CGLIB 优势:
- 可以代理类
- 通过继承实现

4.2 实现示例

// 添加依赖
// <dependency>
//     <groupId>cglib</groupId>
//     <artifactId>cglib</artifactId>
//     <version>3.3.0</version>
// </dependency>

// 目标类(无接口)
class UserService {
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
    
    public void deleteUser(Long id) {
        System.out.println("Deleting user: " + id);
    }
}

// 代理工厂
public class CglibProxyFactory {
    
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
            System.out.println("Before: " + method.getName());
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("After: " + method.getName());
            return result;
        });
        return (T) enhancer.create();
    }
}

// 使用
UserService target = new UserService();
UserService proxy = CglibProxyFactory.createProxy(target);
proxy.addUser("Alice");

4.3 MethodInterceptor

// 自定义 MethodInterceptor
public class LoggingInterceptor implements MethodInterceptor {
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, 
                           MethodProxy proxy) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = proxy.invokeSuper(obj, args);
        long cost = System.currentTimeMillis() - start;
        System.out.println(method.getName() + " cost: " + cost + "ms");
        return result;
    }
}

// 使用
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new LoggingInterceptor());
UserService proxy = (UserService) enhancer.create();

五、JDK vs CGLIB

5.1 对比

特性JDK 动态代理CGLIB
实现方式接口继承
代理对象接口实现类任意类
性能稍低
依赖JDK 自带第三方库
final 方法❌ 不能代理❌ 不能代理
Spring 选择有接口用 JDK无接口用 CGLIB

5.2 选择建议

// ✅ 有接口:JDK 动态代理
interface UserService {}
class UserServiceImpl implements UserService {}
// Spring 默认使用 JDK 代理

// ✅ 无接口:CGLIB
class UserService {}
// Spring 强制 CGLIB
proxyFactory.setProxyTargetClass(true);

// ✅ 性能敏感:JDK 代理
// ✅ 类代理:CGLIB

六、Spring AOP

6.1 AOP 核心概念

Aspect(切面) = 横切关注点的模块化
Pointcut(切入点) = 匹配连接点的谓词
Advice(通知) = 切面在特定执行的动作
Joinpoint(连接点) = 程序执行的点(方法调用)
Weaving(织入) = 将切面应用到目标对象

6.2 Spring AOP 实现

// 切面定义
@Aspect
@Component
public class LoggingAspect {
    
    // 切入点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 前置通知
    @Before("serviceMethods()")
    public void before(JoinPoint joinPoint) {
        System.out.println("Before: " + joinPoint.getSignature());
    }
    
    // 后置通知
    @After("serviceMethods()")
    public void after(JoinPoint joinPoint) {
        System.out.println("After: " + joinPoint.getSignature());
    }
    
    // 环绕通知
    @Around("serviceMethods()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long cost = System.currentTimeMillis() - start;
        System.out.println("Cost: " + cost + "ms");
        return result;
    }
    
    // 返回通知
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("Result: " + result);
    }
    
    // 异常通知
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
    public void afterThrowing(Exception ex) {
        System.out.println("Exception: " + ex.getMessage());
    }
}

6.3 Spring 代理选择

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    
    // 默认:有接口用 JDK,无接口用 CGLIB
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
    
    // 强制使用 CGLIB
    @Bean
    public ProxyFactoryBean proxyFactoryBean() {
        ProxyFactoryBean factory = new ProxyFactoryBean();
        factory.setProxyTargetClass(true); // 强制 CGLIB
        return factory;
    }
}

七、实战场景

7.1 事务代理

public class TransactionProxy {
    
    public static <T> T createProxy(T target, DataSource dataSource) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                Connection conn = dataSource.getConnection();
                try {
                    conn.setAutoCommit(false);
                    Object result = method.invoke(target, args);
                    conn.commit();
                    return result;
                } catch (Exception e) {
                    conn.rollback();
                    throw e;
                } finally {
                    conn.close();
                }
            }
        );
    }
}

7.2 权限代理

public class AuthProxy {
    
    public static <T> T createProxy(T target, User currentUser) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                // 检查权限
                if (!hasPermission(currentUser, method)) {
                    throw new SecurityException("No permission");
                }
                return method.invoke(target, args);
            }
        );
    }
    
    private boolean hasPermission(User user, Method method) {
        // 检查权限逻辑
        return true;
    }
}

7.3 缓存代理

public class CacheProxy {
    private final Map<String, Object> cache = new ConcurrentHashMap<>();
    
    public <T> T createProxy(T target) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                // 生成缓存 key
                String key = method.getName() + ":" + Arrays.toString(args);
                
                // 读缓存
                Object cached = cache.get(key);
                if (cached != null) {
                    return cached;
                }
                
                // 执行方法
                Object result = method.invoke(target, args);
                
                // 写缓存
                cache.put(key, result);
                return result;
            }
        );
    }
}

7.4 RPC 代理

public class RpcProxy {
    
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(Class<T> interfaceClass, String host, int port) {
        return (T) Proxy.newProxyInstance(
            interfaceClass.getClassLoader(),
            new Class[] { interfaceClass },
            (proxy, method, args) -> {
                // 网络调用
                Socket socket = new Socket(host, port);
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                
                // 发送请求
                oos.writeUTF(method.getName());
                oos.writeObject(args);
                
                // 接收响应
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Object result = ois.readObject();
                
                return result;
            }
        );
    }
}

八、总结

代理模式核心要点:

代理类型实现方式适用场景
静态代理手动编写代理类简单场景
JDK 动态代理接口 + InvocationHandler有接口
CGLIB继承 + MethodInterceptor无接口
Spring AOP注解 + 切面企业应用

Spring AOP 默认有接口用 JDK,无接口用 CGLIB,理解代理原理对掌握框架至关重要。


分享这篇文章到:

上一篇文章
Spring Boot 异步编程实战
下一篇文章
MySQL JOIN 优化实战