JDK动态代理和CGLIB动态代理的区别?
大家好,我是锋哥。今天分享关于【JDK动态代理和CGLIB动态代理的区别?】面试题。希望对大家有帮助;
JDK动态代理和CGLIB动态代理的区别?
1000道 互联网大厂Java工程师 精选面试题-Java资源分享网
JDK动态代理和CGLIB动态代理是Java中实现代理模式的两种方式,它们的主要区别在于代理对象的生成方式和应用场景。以下是它们的具体区别:
1. 代理对象的生成方式:
-
JDK动态代理:
- JDK动态代理是基于接口的代理,代理对象必须实现一个或多个接口。
- 通过
java.lang.reflect.Proxy
类和InvocationHandler
接口来创建代理对象。 - 生成的代理对象是实现了接口的类。
示例代码:
public interface MyInterface {void doSomething(); }public class MyInterfaceImpl implements MyInterface {public void doSomething() {System.out.println("Doing something!");} }public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method call");Object result = method.invoke(target, args);System.out.println("After method call");return result;} }public class Main {public static void main(String[] args) {MyInterface target = new MyInterfaceImpl();MyInterface proxy = (MyInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MyInvocationHandler(target));proxy.doSomething();} }
-
CGLIB动态代理:
- CGLIB(Code Generation Library)是基于类的代理,代理对象是通过继承目标类来实现的。
- CGLIB使用字节码技术动态生成目标类的子类,并重写目标类的方法来创建代理对象。
- 生成的代理类继承了目标类,因此不需要目标类实现接口。
示例代码:
public class MyClass {public void doSomething() {System.out.println("Doing something!");} }public class MyCglibProxy implements MethodInterceptor {private Object target;public MyCglibProxy(Object target) {this.target = target;}public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method call");Object result = method.invoke(target, args);System.out.println("After method call");return result;} }public class Main {public static void main(String[] args) {MyClass target = new MyClass();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyClass.class);enhancer.setCallback(new MyCglibProxy(target));MyClass proxy = (MyClass) enhancer.create();proxy.doSomething();} }
2. 是否依赖接口:
- JDK动态代理:必须依赖接口,目标类需要实现一个或多个接口。
- CGLIB动态代理:不依赖接口,代理对象是通过继承目标类创建的,可以对普通类进行代理。
3. 性能差异:
- JDK动态代理:由于JDK动态代理依赖反射机制(
Method.invoke()
),在某些场景下性能较差,尤其是在方法调用频繁的情况下。 - CGLIB动态代理:由于是通过继承目标类并重写方法来实现的,性能比JDK动态代理更高,但生成的代理类比较重,且需要使用字节码生成库(CGLIB),所以性能不如直接实现接口的JDK代理。
4. 生成的代理类的特点:
- JDK动态代理:生成的代理类实现了目标类的所有接口,代理类和目标类的实例是完全不同的对象。
- CGLIB动态代理:生成的代理类是目标类的子类,代理类继承了目标类的方法,并重写了需要增强的方法。
5. 适用场景:
- JDK动态代理:适用于目标类实现了接口的情况。如果目标类没有实现接口,JDK动态代理不能使用。
- CGLIB动态代理:适用于目标类没有接口的情况,或者你希望通过类继承的方式进行代理。但需要注意,CGLIB无法代理
final
类和final
方法。
6. 代理对象的类型:
- JDK动态代理:生成的代理对象是接口类型的实例,实际调用会通过
InvocationHandler
来处理。 - CGLIB动态代理:生成的代理对象是目标类的子类,代理对象是目标类的类型。
总结:
特性 | JDK动态代理 | CGLIB动态代理 |
---|---|---|
代理方式 | 基于接口的代理 | 基于类的代理 |
是否需要接口 | 需要接口 | 不需要接口,使用类继承 |
性能 | 相对较慢,使用反射 | 更快,直接继承并重写方法 |
代理的对象类型 | 代理类实现接口 | 代理类是目标类的子类 |
适用场景 | 目标类实现了接口的情况 | 目标类没有接口或需要对类进行代理 |
对final 类的支持 | 支持,final 方法不可代理 | 不支持,final 类和final 方法无法代理 |
选择使用JDK动态代理还是CGLIB动态代理,主要取决于你的应用场景。如果目标类已经实现了接口,且希望通过接口代理,JDK动态代理是更优选择;如果目标类没有接口,则需要使用CGLIB动态代理。