在Java开发中,代理模式是一种常用的设计模式,它为其他对象提供一种代理以控制对这个对象的访问,代理模式可以在不改变原有代码的情况下,通过引入代理对象来扩展目标对象的功能,例如增加日志、权限控制、远程调用等,本文将详细介绍Java中代理模式的实现方式、应用场景及注意事项。

代理模式的基本概念
代理模式主要包含三个角色:抽象角色(Subject)、真实角色(RealSubject)和代理角色(Proxy),抽象角色是代理类和真实类共同实现的接口或继承的抽象类,定义了真实对象和代理对象的共同方法;真实角色是业务逻辑的具体执行者;代理角色负责对真实角色的方法进行预处理和后处理,例如权限校验、日志记录等。
代理模式分为静态代理和动态代理两种实现方式,静态代理在编译时就已经确定代理类,而动态代理在运行时动态生成代理类,更加灵活。
静态代理的实现
静态代理需要手动编写代理类,该代理类实现与真实类相同的接口,并在方法调用前后添加额外的逻辑,假设有一个Subject接口和RealSubject实现类,可以这样编写静态代理类:
// 抽象角色
public interface Subject {
void request();
}
// 真实角色
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: 处理请求");
}
}
// 代理角色
public class StaticProxy implements Subject {
private Subject realSubject;
public StaticProxy(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("StaticProxy: 前置处理");
realSubject.request();
System.out.println("StaticProxy: 后置处理");
}
}
使用时,只需创建代理类并调用方法即可:
public class Main {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxy = new StaticProxy(realSubject);
proxy.request();
}
}
优点:实现简单,易于理解。
缺点:代理类需要与真实类实现相同的接口,如果接口方法较多,代理类代码会变得冗余;且每个真实类都需要编写对应的代理类,扩展性较差。
动态代理的实现
动态代理通过Java反射机制在运行时动态生成代理类,避免了静态代理的代码冗余问题,Java提供了java.lang.reflect.Proxy类和InvocationHandler接口来实现动态代理。

使用JDK动态代理
JDK动态代理要求真实类必须实现接口,代理类通过Proxy.newProxyInstance方法创建,以下是实现步骤:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象角色(同上)
public interface Subject {
void request();
}
// 真实角色(同上)
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: 处理请求");
}
}
// 自定义InvocationHandler
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy: 前置处理");
Object result = method.invoke(target, args);
System.out.println("DynamicProxy: 后置处理");
return result;
}
}
// 测试类
public class Main {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new DynamicProxyHandler(realSubject)
);
proxy.request();
}
}
关键点:
Proxy.newProxyInstance方法需要传入类加载器、接口数组和InvocationHandler实例。invoke方法在代理对象调用方法时触发,可以通过method.invoke调用真实对象的方法。
缺点:JDK动态代理只能代理接口,如果真实类没有实现接口,则无法使用。
使用CGLIB动态代理
CGLIB(Code Generation Library)是一个强大的高性能代码生成库,可以在运行时创建子类来实现代理,它不需要真实类实现接口,因此弥补了JDK动态代理的不足。
添加CGLIB依赖(Maven):
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
然后实现CGLIB代理:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 真实类(无需实现接口)
public class RealSubject {
public void request() {
System.out.println("RealSubject: 处理请求");
}
}
// 自定义MethodInterceptor
public class CglibProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB Proxy: 前置处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("CGLIB Proxy: 后置处理");
return result;
}
}
// 测试类
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new CglibProxyInterceptor());
RealSubject proxy = (RealSubject) enhancer.create();
proxy.request();
}
}
关键点:
Enhancer类用于设置代理类的父类和回调方法。MethodInterceptor接口的intercept方法用于拦截目标方法。
优点:可以对没有实现接口的类进行代理。
缺点:CGLIB无法代理final类或final方法,因为它们无法被继承或重写。
代理模式的应用场景
- 日志记录:在方法调用前后记录日志,便于调试和监控。
- 权限控制:通过代理对象检查调用者是否有权限执行目标方法。
- 远程调用:如RMI(远程方法调用),代理对象将本地调用转换为远程调用。
- 延迟加载:如Hibernate中的懒加载,代理对象在真正需要时才加载数据。
- 事务管理:在方法执行前开启事务,执行后提交或回滚事务。
代理模式的注意事项
- 性能开销:动态代理通过反射调用方法,性能略低于直接调用,但通常可以忽略。
- 类加载问题:动态代理生成的类由
ProxyGenerator生成,需要确保类加载器正确。 - 异常处理:代理方法中的异常需要妥善处理,避免影响真实对象的业务逻辑。
- CGLIB的限制:CGLIB通过继承实现代理,因此无法代理
final类或方法。
代理模式是Java中一种重要的设计模式,通过引入代理对象可以在不修改原有代码的基础上扩展功能,静态代理实现简单但扩展性差,动态代理(JDK和CGLIB)则提供了更灵活的解决方案,开发者应根据实际需求选择合适的代理方式,例如如果目标对象实现了接口,优先使用JDK动态代理;否则可以使用CGLIB代理,合理使用代理模式可以提高代码的可维护性和扩展性,适用于日志、权限、事务等多种场景。



















