推荐答案
在 Spring AOP 中,JDK 动态代理和 CGLIB 代理是两种常见的代理方式,它们的区别主要体现在以下几个方面:
实现方式:
- JDK 动态代理:基于接口实现,要求目标类必须实现至少一个接口。
- CGLIB 代理:基于继承实现,通过生成目标类的子类来创建代理对象,不要求目标类实现接口。
性能:
- JDK 动态代理:在代理接口方法时性能较好,但在代理类方法时性能较差。
- CGLIB 代理:在代理类方法时性能较好,但在生成代理对象时性能较差。
依赖:
- JDK 动态代理:无需额外依赖,JDK 自带。
- CGLIB 代理:需要引入 CGLIB 库。
适用场景:
- JDK 动态代理:适用于代理接口方法。
- CGLIB 代理:适用于代理类方法,尤其是没有实现接口的类。
本题详细解读
JDK 动态代理
JDK 动态代理是 Java 标准库提供的一种代理机制,它通过 java.lang.reflect.Proxy 类来创建代理对象。JDK 动态代理的核心是 InvocationHandler 接口,开发者需要实现该接口并在 invoke 方法中定义代理逻辑。
优点:
- 无需引入第三方库,JDK 自带。
- 对于接口方法的代理性能较好。
缺点:
- 只能代理实现了接口的类。
- 对于类方法的代理性能较差。
示例代码:
// www.javascriptcn.com code example
public interface UserService {
void save();
}
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户");
}
}
public class UserServiceProxy implements InvocationHandler {
private Object target;
public UserServiceProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
public static void main(String[] args) {
UserService userService = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new UserServiceProxy(new UserServiceImpl())
);
userService.save();
}
}CGLIB 代理
CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它通过生成目标类的子类来实现代理。CGLIB 代理的核心是 MethodInterceptor 接口,开发者需要实现该接口并在 intercept 方法中定义代理逻辑。
优点:
- 可以代理没有实现接口的类。
- 对于类方法的代理性能较好。
缺点:
- 需要引入 CGLIB 库。
- 在生成代理对象时性能较差。
示例代码:
// www.javascriptcn.com code example
public class UserService {
public void save() {
System.out.println("保存用户");
}
}
public class UserServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置处理");
return result;
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new UserServiceInterceptor());
UserService userService = (UserService) enhancer.create();
userService.save();
}
}总结
- JDK 动态代理:适用于代理接口方法,无需额外依赖,但只能代理实现了接口的类。
- CGLIB 代理:适用于代理类方法,尤其是没有实现接口的类,但需要引入 CGLIB 库。
在实际开发中,Spring AOP 会根据目标类是否实现了接口自动选择使用 JDK 动态代理还是 CGLIB 代理。如果目标类实现了接口,则使用 JDK 动态代理;否则,使用 CGLIB 代理。