1. 引言
在 Java 开发中,代理模式是一种常见的设计模式,它可以为对象提供额外的功能,例如权限控制、日志记录、事务管理等。Java 提供了两种代理方式:静态代理和动态代理。本文重点讨论动态代理的概念、实现方式及其应用场景。
2. Java 代理模式概述
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过代理对象访问目标对象。代理对象可以在不修改目标对象的情况下,增强其功能。
静态代理 是在编译期就确定代理类,需要为每个目标类编写代理类,代码重复度较高。
动态代理 则是在运行时动态生成代理对象,减少代码冗余,提高灵活性。
3. Java 动态代理的实现方式
Java 提供了两种主要的动态代理实现方式:
- JDK 动态代理(基于
java.lang.reflect.Proxy
)
- CGLIB 动态代理(基于字节码增强)
3.1 JDK 动态代理
JDK 提供了 Proxy
类和 InvocationHandler
接口来实现动态代理。其核心思想是创建一个实现目标接口的代理类,并在方法调用时,使用 InvocationHandler
进行方法拦截。
3.1.1 代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
interface Service { void serve(); }
class RealService implements Service { @Override public void serve() { System.out.println("Executing real service..."); } }
class ServiceInvocationHandler implements InvocationHandler { private final Object target;
public ServiceInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before invoking method: " + method.getName()); Object result = method.invoke(target, args); System.out.println("After invoking method: " + method.getName()); return result; } }
public class JDKProxyDemo { public static void main(String[] args) { Service realService = new RealService(); Service proxyInstance = (Service) Proxy.newProxyInstance( realService.getClass().getClassLoader(), realService.getClass().getInterfaces(), new ServiceInvocationHandler(realService) ); proxyInstance.serve(); } }
|
3.1.2 运行结果
1 2 3
| Before invoking method: serve Executing real service... After invoking method: serve
|
3.2 CGLIB 动态代理
JDK 动态代理要求目标类必须实现接口,而 CGLIB 通过继承目标类并生成子类的方式进行代理,因此可以代理没有实现接口的类。
3.2.1 代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
class RealServiceCGLIB { public void serve() { System.out.println("Executing real service..."); } }
class CGLIBProxy implements MethodInterceptor { private final Object target;
public CGLIBProxy(Object target) { this.target = target; }
public Object createProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); }
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before invoking method: " + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("After invoking method: " + method.getName()); return result; } }
public class CGLIBProxyDemo { public static void main(String[] args) { RealServiceCGLIB realService = new RealServiceCGLIB(); RealServiceCGLIB proxyInstance = (RealServiceCGLIB) new CGLIBProxy(realService).createProxy(); proxyInstance.serve(); } }
|
3.2.2 运行结果
1 2 3
| Before invoking method: serve Executing real service... After invoking method: serve
|
4. Java 动态代理的应用场景
- AOP(面向切面编程):如 Spring 框架的事务管理、日志记录等。
- RPC(远程过程调用):动态代理用于拦截调用并执行远程调用。
- 权限控制:在访问目标方法前进行权限验证。
- 缓存:在调用目标方法前检查缓存,提高性能。
5. JDK 动态代理与 CGLIB 代理的对比
特性 |
JDK 动态代理 |
CGLIB 动态代理 |
是否需要接口 |
是 |
否 |
代理方式 |
生成接口实现类 |
继承目标类 |
性能 |
略慢 |
较快 |
Spring 默认选择 |
是(如果有接口) |
否(无接口时) |
6. 总结
Java 动态代理是实现代理模式的重要方式,JDK 动态代理适用于接口代理,而 CGLIB 代理适用于类代理。在实际开发中,应根据需求选择合适的动态代理方式。例如,在 Spring AOP 中,默认使用 JDK 动态代理,但如果目标类没有实现接口,则使用 CGLIB 代理。
了解并灵活运用 Java 动态代理,有助于提升代码的复用性和可维护性,在实际项目中带来更高的开发效率。