JDK动态代理和CGLIB动态代理的区别
JDK 动态代理和 CGLIB 动态代理是两种常用的动态代理技术,它们在实现方式和适用场景上有所不同。理解它们的区别可以帮助开发者更好地选择适合的代理方式。
JDK 动态代理和 CGLIB 动态代理的区别
1. 实现方式
- JDK 动态代理:基于 Java 的反射机制实现,只能代理实现了接口的类。
- CGLIB 动态代理:通过生成目标类的子类来实现代理,可以代理没有实现接口的类。
2. 适用场景
- JDK 动态代理:适用于目标类实现了接口的情况。
- CGLIB 动态代理:适用于目标类没有实现接口的情况,或者需要代理类本身的方法。
3. 性能
- JDK 动态代理:性能相对较好,因为它是基于 Java 的反射机制实现的。
- CGLIB 动态代理:性能稍差,因为它需要生成字节码,但通常性能差异不大。
4. 使用方式
- JDK 动态代理:需要实现
InvocationHandler接口。 - CGLIB 动态代理:需要实现
MethodInterceptor接口。
实际场景及代码示例
场景 1:JDK 动态代理
假设我们有一个 UserService 接口和一个实现类 UserServiceImpl,我们希望为 UserServiceImpl 创建一个代理,以记录方法调用的日志。
代码示例
定义 UserService 接口:
public interface UserService {
void createUser(String name);
}
实现 UserServiceImpl:
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Override
public void createUser(String name) {
System.out.println("Creating user: " + name);
}
}
创建 JDK 动态代理:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LoggingInvocationHandler implements InvocationHandler {
private final Object target;
public LoggingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
}
public static <T> T createProxy(T target, Class<T> interfaceType) {
return (T) Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class<?>[]{interfaceType},
new LoggingInvocationHandler(target)
);
}
}
使用 JDK 动态代理:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
UserServiceImpl userServiceImpl = new UserServiceImpl();
return LoggingInvocationHandler.createProxy(userServiceImpl, UserService.class);
}
}
场景 2:CGLIB 动态代理
假设我们有一个 UserService 类,它没有实现任何接口,我们希望为 UserService 创建一个代理,以记录方法调用的日志。
代码示例
定义 UserService 类:
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void createUser(String name) {
System.out.println("Creating user: " + name);
}
}
创建 CGLIB 动态代理:
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 LoggingMethodInterceptor implements MethodInterceptor {
private final Object target;
public LoggingMethodInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
public static <T> T createProxy(T target, Class<T> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new LoggingMethodInterceptor(target));
return (T) enhancer.create();
}
}
使用 CGLIB 动态代理:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
UserService userService = new UserService();
return LoggingMethodInterceptor.createProxy(userService, UserService.class);
}
}
总结
- JDK 动态代理:基于反射机制,只能代理实现了接口的类,性能较好。
- CGLIB 动态代理:通过生成目标类的子类来实现代理,可以代理没有实现接口的类,性能稍差。
选择哪种代理方式取决于具体的业务需求。如果目标类实现了接口,推荐使用 JDK 动态代理;如果目标类没有实现接口,或者需要代理类本身的方法,可以使用 CGLIB 动态代理。

2583

被折叠的 条评论
为什么被折叠?



