Java中的代理模式属于结构型设计模式,核心思想是在不修改目标对象代码的前提下,通过代理对象对目标对象的功能进行增强或者控制访问。根据代理类的生成时机不同,代理模式可以分为静态代理和动态代理两大类,下面分别介绍两者的实现方式和特点。

静态代理的实现
静态代理的代理类是在代码编写阶段就手动创建好的,代理类和目标类需要实现相同的接口,代理类内部持有目标类的实例,在调用目标方法前后可以添加增强逻辑。
静态代理示例
首先定义一个公共的接口,目标类和代理类都实现这个接口:
// 定义业务接口
public interface UserService {
void addUser(String username);
}
// 目标类,实现业务接口
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户:" + username);
}
}
// 静态代理类,同样实现业务接口
public class UserServiceStaticProxy implements UserService {
// 持有目标对象的实例
private UserService target;
public UserServiceStaticProxy(UserService target) {
this.target = target;
}
@Override
public void addUser(String username) {
System.out.println("静态代理:方法执行前,记录日志");
// 调用目标对象的方法
target.addUser(username);
System.out.println("静态代理:方法执行后,记录日志");
}
}
测试静态代理的使用:
public class StaticProxyTest {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建静态代理对象
UserService proxy = new UserServiceStaticProxy(target);
// 调用代理对象的方法
proxy.addUser("张三");
}
}
静态代理的优点是逻辑简单,容易理解,缺点也很明显:如果需要代理的接口很多,或者接口的方法很多,就需要编写大量的代理类,代码冗余度高,维护成本大。
动态代理的实现
动态代理的代理类是在程序运行期间动态生成的,不需要手动编写代理类的代码。Java中常见的动态代理实现有两种:JDK动态代理和CGLIB动态代理。
JDK动态代理
JDK动态代理是Java原生支持的动态代理方式,要求目标类必须实现接口,代理对象会实现和目标类相同的接口。核心是通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现。
JDK动态代理示例,复用上面的UserService和UserServiceImpl:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 实现InvocationHandler接口,定义代理逻辑
public class JdkDynamicProxyHandler implements InvocationHandler {
// 持有目标对象
private Object target;
public JdkDynamicProxyHandler(Object target) {
this.target = target;
}
// 生成代理对象的方法
public Object getProxyInstance() {
// 使用Proxy.newProxyInstance生成代理对象
// 第一个参数是目标类的类加载器
// 第二个参数是目标类实现的接口数组
// 第三个参数是当前InvocationHandler实例
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
// 代理对象调用方法时会执行这个方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理:方法执行前,记录日志");
// 调用目标对象的方法
Object result = method.invoke(target, args);
System.out.println("JDK动态代理:方法执行后,记录日志");
return result;
}
}
测试JDK动态代理的使用:
public class JdkDynamicProxyTest {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建InvocationHandler实例
JdkDynamicProxyHandler handler = new JdkDynamicProxyHandler(target);
// 获取代理对象
UserService proxy = (UserService) handler.getProxyInstance();
// 调用代理对象的方法
proxy.addUser("李四");
}
}
CGLIB动态代理
CGLIB动态代理是基于ASM字节码框架实现的,不需要目标类实现接口,它通过生成目标类的子类作为代理类。CGLIB是第三方库,需要额外引入依赖,核心是通过net.sf.cglib.proxy.Enhancer和net.sf.cglib.proxy.MethodInterceptor接口来实现。
CGLIB动态代理示例,目标类不需要实现接口:
// 目标类,不需要实现接口
public class OrderService {
public void createOrder(String orderId) {
System.out.println("创建订单:" + orderId);
}
}
实现CGLIB的代理逻辑:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 实现MethodInterceptor接口,定义代理逻辑
public class CglibDynamicProxy implements MethodInterceptor {
// 生成代理对象的方法
public Object getProxyInstance(Class<?> targetClass) {
Enhancer enhancer = new Enhancer();
// 设置父类,即目标类
enhancer.setSuperclass(targetClass);
// 设置回调,即当前MethodInterceptor实例
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
// 代理对象调用方法时会执行这个方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB动态代理:方法执行前,记录日志");
// 调用目标对象的方法,通过MethodProxy的invokeSuper方法调用父类的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("CGLIB动态代理:方法执行后,记录日志");
return result;
}
}
测试CGLIB动态代理的使用:
public class CglibDynamicProxyTest {
public static void main(String[] args) {
// 创建CGLIB代理实例
CglibDynamicProxy proxy = new CglibDynamicProxy();
// 获取代理对象
OrderService orderService = (OrderService) proxy.getProxyInstance(OrderService.class);
// 调用代理对象的方法
orderService.createOrder("ORDER_001");
}
}
静态代理和动态代理的核心差异
两者的核心差异可以通过下面的表格对比:
| 对比维度 | 静态代理 | 动态代理 |
|---|---|---|
| 代理类生成时机 | 编译期手动编写,生成class文件 | 运行期动态生成,不需要提前编写代理类 |
| 实现要求 | 代理类和目标类需要实现相同接口 | JDK动态代理要求目标类实现接口;CGLIB不需要目标类实现接口 |
| 代码冗余度 | 高,每个目标类或接口都需要对应一个代理类 | 低,一个代理处理器可以处理多个目标类 |
| 灵活性 | 低,代理逻辑修改需要修改代理类代码 | 高,代理逻辑可以统一管理,修改方便 |
| 适用场景 | 代理类少、接口稳定的简单场景 | 需要批量代理、框架开发等复杂场景 |
使用场景总结
如果业务场景中需要代理的类很少,接口也比较稳定,静态代理的实现方式足够简单直观,不需要引入额外的复杂度。如果是在框架开发、AOP实现、RPC调用等需要批量生成代理的场景中,动态代理的优势会非常明显,能够大幅减少重复代码,提升开发和维护效率。在实际开发中,Spring框架的AOP功能就是基于动态代理实现的,默认情况下如果目标类实现了接口就使用JDK动态代理,否则使用CGLIB动态代理。