云计算百科
云计算领域专业知识百科平台

JDK与CGLIB动态代理实战解析

JDK动态代理与CGLIB动态代理代码实现详解

1. 实现原理对比

特性JDK动态代理CGLIB动态代理
实现方式 基于接口,使用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动态代理实现和区别

     

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » JDK与CGLIB动态代理实战解析
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!