JDK 与 CGLIB 的区别及应用
简介
动态代理是一种在运行时动态创建代理对象的机制,它可以在不修改源码的情况下为原始对象添加额外的功能。在软件开发中,动态代理被广泛应用于AOP(面向切面编程)、事务管理、远程调用等方面。
JDK动态代理和CGLIB动态代理是两种常见的动态代理实现方式。JDK动态代理是基于接口的代理,它要求目标对象实现一个接口,然后通过反射机制来创建代理对象。而CGLIB动态代理则是基于继承的代理,它可以代理没有实现接口的类,并通过生成目标类的子类来实现代理。
本文将对比JDK动态代理和CGLIB动态代理的特点、优缺点以及适用场景,以帮助读者更好地理解它们的差异和选择合适的动态代理实现方式。
两者有何区别
- 基于接口 vs 基于继承:
◦ JDK动态代理是通过反射机制来实现的,它要求目标对象必须实现一个接口。在运行时,JDK动态代理会创建一个实现了代理接口的代理类,并在代理类中调用目标对象的方法。
◦ CGLIB动态代理则是通过继承目标类来实现的,它可以代理没有实现接口的类。在运行时,CGLIB动态代理会生成目标类的子类,并在子类中重写目标对象的方法来实现代理。 - 性能:
◦ 一般情况下,JDK动态代理的性能要略优于CGLIB动态代理,因为JDK动态代理是基于接口的代理,而CGLIB动态代理是基于继承的代理,生成代理类的过程更为复杂。 - 适用场景:
◦ JDK动态代理适用于需要代理接口的情况,比如对服务层方法进行切面处理、事务管理等。
◦ CGLIB动态代理适用于代理没有实现接口的类的情况,比如对类的方法进行切面处理、性能监控等。 - 对目标对象的要求:
◦ JDK动态代理要求目标对象实现接口,而CGLIB动态代理则可以代理没有实现接口的类。 - 注意事项:
◦ 如果想要实现JDK动态代理那么代理类必须实现接口,否则不能使用。
◦ CGLIB通过生成继承自目标类的子类来实现代理,因此目标类和目标方法不能被声明为final,否则CGLIB无法生成代理类。
代码实现
JDK动态代理
UserService接口
public interface UserService {
void addUser();
void updateUser(String str);
}
UserServiceImpl实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void updateUser(String str) {
System.out.println("更新用户信息" + str);
}
}
UserProxy代理类
public class UserProxy implements InvocationHandler {
private Object target;
public UserProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("===增强开始===");
Object res = method.invoke(target, args);
System.out.println("===增强结束===");
return res;
}
}
Test测试类
public class Test {
public static void main(String[] args) {
UserServiceImpl impl = new UserServiceImpl();
UserProxy userProxy = new UserProxy(impl);
UserService userService = (UserService) Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), userProxy);
userService.addUser();
userService.updateUser(":我是零陵上将军邢道荣");
}
}
运行Test类main方法
CGlib动态代理
UserServiceImpl被代理类
public class UserServiceImpl {
public void addUser() {
System.out.println("添加了一个用户");
}
public void deleteUser() {
System.out.println("删除了一个用户");
}
}
UserServiceCGlib代理类
public class UserServiceCGlib implements MethodInterceptor {
private Object target;
public UserServiceCGlib() {
}
public UserServiceCGlib(Object target) {
this.target = target;
}
// 返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
// 创建一个工具类
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(target.getClass());
// 设置回调函数
enhancer.setCallback(this);
// 创建子类对象,即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("===增强开始===");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("===增强结束===");
return result;
}
}
Test测试类
public class Test {
public static void main(String[] args) {
UserServiceCGlib serviceCGlib = new UserServiceCGlib(new UserServiceImpl());
UserServiceImpl userService = (UserServiceImpl)serviceCGlib.getProxyInstance();
userService.addUser();
userService.deleteUser();
}
}
运行Test类main方法
Spring AOP 创建代理
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
-
如果目标对象实现了接口,默认情况下会采用JDK的动态代理
-
如果目标对象实现了接口,也可以强制使用CGLIB
-
如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK和CGLIB之间转换
如果需要强制使用CGLIB来实现AOP,需要配置spring.aop.proxy-target-class=true或@EnableAspectJAutoProxy(proxyTargetClass = true)