JDK动态代理与CGLIB动态代理代码实现详解
1. 实现原理对比
| 实现方式 | 基于接口,使用Proxy类和InvocationHandler接口 | 基于继承,使用字节码技术生成目标类的子类 |
| 依赖 | Java标准库(java.lang.reflect) | 第三方库(cglib) |
| 性能 | JDK6+版本性能优化,通常不逊于CGLIB | 早期版本性能优势明显,但生成字节码有开销 |
| 限制 | 只能代理实现了接口的类 | 无法代理final类和方法 |
| Spring默认 | 目标对象实现接口时使用 | 目标对象未实现接口时使用 |
2. JDK动态代理代码实现
2.1 定义接口
// 定义业务接口
public interface UserService {
String getUserName(Long userId);
void updateUser(Long userId, String userName);
}
2.2 实现目标类
// 实现接口的目标类
public class UserServiceImpl implements UserService {
@Override
public String getUserName(Long userId) {
System.out.println("查询用户ID: " + userId);
return "用户" + userId;
}
@Override
public void updateUser(Long userId, String userName) {
System.out.println("更新用户ID: " + userId + ",新名称: " + userName);
}
}
2.3 实现InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class JdkProxyHandler implements InvocationHandler {
private Object target; // 目标对象
public JdkProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
System.out.println("【JDK代理】方法执行前: " + method.getName());
System.out.println("【JDK代理】参数: " + Arrays.toString(args));
long startTime = System.currentTimeMillis();
// 执行目标方法
Object result = method.invoke(target, args);
// 后置增强
long endTime = System.currentTimeMillis();
System.out.println("【JDK代理】方法执行后,耗时: " + (endTime – startTime) + "ms");
return result;
}
}
2.4 创建代理对象
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
public static void main(String[] args) {
// 1. 创建目标对象
UserService target = new UserServiceImpl();
// 2. 创建InvocationHandler
JdkProxyHandler handler = new JdkProxyHandler(target);
// 3. 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 实现的接口数组
handler // InvocationHandler
);
// 4. 使用代理对象
System.out.println("代理对象类型: " + proxy.getClass());
System.out.println("代理对象父类: " + proxy.getClass().getSuperclass());
System.out.println("代理对象接口: " + Arrays.toString(proxy.getClass().getInterfaces()));
// 5. 调用代理方法
String userName = proxy.getUserName(1001L);
System.out.println("获取的用户名: " + userName);
proxy.updateUser(1002L, "新用户名");
}
}
输出结果示例:
代理对象类型: class com.sun.proxy.$Proxy0
代理对象父类: class java.lang.reflect.Proxy
代理对象接口: [interface com.example.UserService]
【JDK代理】方法执行前: getUserName
【JDK代理】参数: [1001]
查询用户ID: 1001
【JDK代理】方法执行后,耗时: 1ms
获取的用户名: 用户1001
3. CGLIB动态代理代码实现
3.1 添加依赖(Maven)
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
3.2 定义目标类(无需接口)
// 目标类,不需要实现接口
public class UserServiceCglib {
public String getUserName(Long userId) {
System.out.println("CGLIB – 查询用户ID: " + userId);
return "CGLIB用户" + userId;
}
public void updateUser(Long userId, String userName) {
System.out.println("CGLIB – 更新用户ID: " + userId + ",新名称: " + userName);
}
// final方法无法被代理
public final String getFinalInfo() {
return "这是final方法";
}
}
3.3 实现MethodInterceptor
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Arrays;
public class CglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 前置增强
System.out.println("【CGLIB代理】方法执行前: " + method.getName());
System.out.println("【CGLIB代理】参数: " + Arrays.toString(args));
// 过滤final方法
if (method.getName().equals("getFinalInfo")) {
System.out.println("【CGLIB代理】final方法直接执行");
return proxy.invokeSuper(obj, args);
}
long startTime = System.currentTimeMillis();
// 执行目标方法 – 注意这里使用invokeSuper调用父类方法
Object result = proxy.invokeSuper(obj, args);
// 后置增强
long endTime = System.currentTimeMillis();
System.out.println("【CGLIB代理】方法执行后,耗时: " + (endTime – startTime) + "ms");
return result;
}
}
3.4 创建代理对象
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyDemo {
public static void main(String[] args) {
// 1. 创建Enhancer对象
Enhancer enhancer = new Enhancer();
// 2. 设置父类(目标类)
enhancer.setSuperclass(UserServiceCglib.class);
// 3. 设置回调(拦截器)
enhancer.setCallback(new CglibInterceptor());
// 4. 创建代理对象
UserServiceCglib proxy = (UserServiceCglib) enhancer.create();
// 5. 分析代理对象
System.out.println("代理对象类型: " + proxy.getClass());
System.out.println("代理对象父类: " + proxy.getClass().getSuperclass());
System.out.println("是否继承目标类: " + UserServiceCglib.class.isAssignableFrom(proxy.getClass()));
// 6. 调用代理方法
String userName = proxy.getUserName(2001L);
System.out.println("获取的用户名: " + userName);
proxy.updateUser(2002L, "CGLIB新用户名");
// 7. 测试final方法
System.out.println("final方法结果: " + proxy.getFinalInfo());
}
}
输出结果示例:
代理对象类型: class com.example.UserServiceCglib$$EnhancerByCGLIB$$xxxx
代理对象父类: class com.example.UserServiceCglib
是否继承目标类: true
【CGLIB代理】方法执行前: getUserName
【CGLIB代理】参数: [2001]
CGLIB – 查询用户ID: 2001
【CGLIB代理】方法执行后,耗时: 2ms
获取的用户名: CGLIB用户2001
4. 综合对比示例
4.1 性能测试代码
public class ProxyPerformanceTest {
public static void main(String[] args) {
int iterations = 1000000;
// JDK代理性能测试
UserService jdkTarget = new UserServiceImpl();
JdkProxyHandler jdkHandler = new JdkProxyHandler(jdkTarget);
UserService jdkProxy = (UserService) Proxy.newProxyInstance(
jdkTarget.getClass().getClassLoader(),
jdkTarget.getClass().getInterfaces(),
jdkHandler
);
long jdkStart = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
jdkProxy.getUserName((long) i);
}
long jdkEnd = System.currentTimeMillis();
System.out.println("JDK代理执行" + iterations + "次耗时: " + (jdkEnd – jdkStart) + "ms");
// CGLIB代理性能测试
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceCglib.class);
enhancer.setCallback(new CglibInterceptor());
UserServiceCglib cglibProxy = (UserServiceCglib) enhancer.create();
long cglibStart = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
cglibProxy.getUserName((long) i);
}
long cglibEnd = System.currentTimeMillis();
System.out.println("CGLIB代理执行" + iterations + "次耗时: " + (cglibEnd – cglibStart) + "ms");
}
}
4.2 Spring中的选择策略
// Spring AOP配置示例
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
// Spring默认使用JDK动态代理
// 当目标对象实现接口时使用JDK代理
// 当目标对象未实现接口时使用CGLIB代理
// 强制使用CGLIB代理的配置
@Bean
public static BeanFactoryPostProcessor forceCglibProxy() {
return beanFactory -> {
if (beanFactory instanceof AbstractApplicationContext) {
((AbstractApplicationContext) beanFactory)
.getBeanFactory()
.addBeanPostProcessor(new DefaultAdvisorAutoProxyCreator() {
@Override
protected boolean shouldProxyTargetClass(Class<?> beanClass, String beanName) {
return true; // 强制使用CGLIB
}
});
}
};
}
}
5. 关键区别总结
代理机制不同:
- JDK动态代理基于接口,通过Proxy.newProxyInstance()创建代理对象
- CGLIB基于继承,通过Enhancer.create()生成目标类的子类
方法调用方式不同:
// JDK代理使用反射调用
Object result = method.invoke(target, args);
// CGLIB代理使用方法代理调用
Object result = proxy.invokeSuper(obj, args);
性能考虑:
- JDK8+版本中,JDK动态代理性能已显著提升
- CGLIB在创建代理对象时有额外开销,但方法调用可能更快
使用场景:
- JDK代理:Spring默认,适合有接口的类,符合面向接口编程原则
- CGLIB代理:需要代理没有接口的类,或需要代理类中的具体方法
兼容性:
- JDK代理是Java标准库的一部分,无需额外依赖
- CGLIB需要第三方库,且在Java 17+可能需要添加JVM参数
在实际开发中,Spring框架会根据目标对象是否实现接口自动选择代理方式。对于大多数应用,这种自动选择机制已经足够,只有在特定性能要求或功能需求时才需要手动指定代理方式。
参考来源
- java jdk动态代理和cglib动态代理对比,实现,区别
- JDK和CGLIB动态代理区别
- jdk动态代理和cglib动态代理对比
- jdk动态代理和CGLIB动态代理的区别
- JDK和CGLIB动态代理的区别
- JDK和CGLib动态代理实现和区别
网硕互联帮助中心






评论前必须登录!
注册