引言
在软件开发中,动态代理是一种强大的技术,它允许在运行时创建代理对象,从而为原对象添加额外的功能。Java中主要有两种动态代理机制:JDK动态代理和CGLIB动态代理。本篇文章将详细介绍这两种动态代理的概念、实现方式、应用场景,并进行对比分析。
1. 什么是动态代理?
动态代理是一种在运行时创建代理对象的技术,通过代理对象来控制对原对象的访问,能够在不修改原对象的情况下添加额外的功能。动态代理主要有以下两种实现方式:
- JDK动态代理:基于Java反射机制,只能代理实现了接口的类。
- CGLIB动态代理:基于字节码生成技术,可以代理没有实现接口的类。
2. JDK动态代理
原理
JDK动态代理利用反射机制在运行时生成代理类,并通过java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口实现代理功能。它只能代理实现了接口的类。
示例代码
接口定义
// 抽象主题接口
public interface BusinessService {
void performTask();
}
实现类
// 真实主题类
public class RealBusinessService implements BusinessService {
@Override
public void performTask() {
System.out.println("Performing the main task...");
}
}
动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 动态代理类
public class BusinessServiceProxy implements InvocationHandler {
private Object target;
public BusinessServiceProxy(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logBefore();
Object returnValue = method.invoke(target, args);
logAfter();
return returnValue;
}
private void logBefore() {
System.out.println("Log before method execution");
}
private void logAfter() {
System.out.println("Log after method execution");
}
}
客户端代码
public class JDKDynamicProxyDemo {
public static void main(String[] args) {
RealBusinessService realBusinessService = new RealBusinessService();
BusinessServiceProxy proxy = new BusinessServiceProxy(realBusinessService);
BusinessService businessService = (BusinessService) proxy.getProxyInstance();
// 调用方法前后会执行增强内容
businessService.performTask();
}
}
输出
Log before method execution
Performing the main task...
Log after method execution
3. CGLIB动态代理
原理
CGLIB(Code Generation Library)动态代理利用ASM字节码操作框架在运行时生成代理类,它通过继承的方式代理目标对象,因此可以代理没有实现接口的类。
示例代码
实现类
// 真实主题类
public class RealBusinessService {
public void performTask() {
System.out.println("Performing the main task...");
}
}
动态代理类
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 动态代理类
public class BusinessServiceProxy implements MethodInterceptor {
private Object target;
public BusinessServiceProxy(Object target) {
this.target = target;
}
public Object getProxyInstance() {
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 {
logBefore();
Object returnValue = proxy.invokeSuper(obj, args);
logAfter();
return returnValue;
}
private void logBefore() {
System.out.println("Log before method execution");
}
private void logAfter() {
System.out.println("Log after method execution");
}
}
客户端代码
public class CGLIBDynamicProxyDemo {
public static void main(String[] args) {
RealBusinessService realBusinessService = new RealBusinessService();
BusinessServiceProxy proxy = new BusinessServiceProxy(realBusinessService);
RealBusinessService businessService = (RealBusinessService) proxy.getProxyInstance();
// 调用方法前后会执行增强内容
businessService.performTask();
}
}
输出
Log before method execution
Performing the main task...
Log after method execution
4. JDK动态代理与CGLIB动态代理的比较
相同点
- 动态生成代理类:两者都在运行时生成代理类,能够在不修改原对象的情况下添加额外功能。
- 增强功能:两者都可以在方法调用前后添加增强功能,如日志记录、权限控制等。
不同点
特性 | JDK动态代理 | CGLIB动态代理 |
---|---|---|
代理对象 | 只能代理实现了接口的类 | 可以代理没有实现接口的类 |
实现方式 | 基于反射机制 | 基于字节码生成 |
性能 | 调用速度稍慢,因为使用了反射 | 调用速度较快,但创建代理对象的开销较大 |
依赖 | 无需额外依赖,JDK自带 | 需要引入CGLIB库(如Spring框架自带) |
继承方式 | 实现接口的代理 | 通过继承的方式代理目标类 |
选择建议
- JDK动态代理:如果目标类已经实现了接口,并且希望保持简单的依赖关系,使用JDK动态代理是一个好选择。
- CGLIB动态代理:如果目标类没有实现接口或者需要更高的性能,可以考虑使用CGLIB动态代理。
5. 总结
动态代理在Java中提供了一种灵活而强大的机制,能够在运行时为目标对象添加额外的功能。JDK动态代理和CGLIB动态代理各有优势和适用场景,开发者可以根据具体需求选择合适的代理机制。
希望这篇文章对你理解动态代理有所帮助。如果觉得本文内容有价值,请点赞、收藏和关注我们,获取更多设计模式的精彩内容!