首先大家要知道,在Java中,动态代理是一种机制,允许在运行时动态地创建代理对象来代替某个实际对象,从而在其前后执行额外的逻辑。
在Spring框架中提供了两种动态代理方式:CGLIB和JDK动态代理。
CGLIB是一个强大的高性能的代码生成库,它可以在运行时动态生成字节码,从而实现对类的动态代理。CGLIB可以代理没有实现接口的类,因此它比JDK动态代理更加灵活,但是它的代理速度相对较慢。
JDK动态代理是Java自带的动态代理机制,它只能代理实现了接口的类,但是它的代理速度相对较快。JDK动态代理使用反射机制实现代理,因此它的代理对象必须实现一个或多个接口。
在使用Spring框架时,我们可以根据需要选择使用CGLIB或JDK动态代理来实现对类的动态代理。如果被代理的类没有实现接口,我们可以选择使用CGLIB动态代理;如果被代理的类实现了接口,我们可以选择使用JDK动态代理。
JDK动态代理代码实例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo {
public static void main(String[] args) {
RealObject real = new RealObject();
InvocationHandler handler = new DynamicProxy(real);
// 创建代理对象
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class<?>[] { MyInterface.class },
handler);
// 调用代理对象的方法
proxy.doSomething();
}
}
interface MyInterface {
void doSomething();
}
class RealObject implements MyInterface {
public void doSomething() {
System.out.println("RealObject doSomething");
}
}
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
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 CGLIBProxyDemo {
public static void main(String[] args) {
RealObject real = new RealObject();
MethodInterceptor handler = new CGLIBProxy(real);
// 创建代理对象
RealObject proxy = (RealObject) Enhancer.create(
RealObject.class,
handler);
// 调用代理对象的方法
proxy.doSomething();
}
}
class CGLIBProxy implements MethodInterceptor {
private Object target;
public CGLIBProxy(Object target) {
this.target = target;
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invocation");
Object result = proxy.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
在此需要注意的是,CGLIB代理使用字节码技术来生成代理对象,因此它的效率比JDK动态代理要高,但是它也需要额外的库依赖。
两者优缺点
JDK动态代理和CGLIB代理都有它们自己的优缺点。
JDK动态代理的优点:
-
JDK动态代理是Java标准库的一部分,因此它不需要引入任何外部依赖。
-
JDK动态代理只需要实现接口即可生成代理对象,不需要改变原有类的结构。
-
由于JDK动态代理是基于接口实现的,因此它更适合用于代理接口实现类的场景。
JDK动态代理的缺点:
-
JDK动态代理只能代理实现了接口的类,无法代理没有实现接口的类。
-
JDK动态代理在生成代理对象时,需要使用反射机制,因此它的效率相对较低。
CGLIB代理的优点:
-
CGLIB代理是基于字节码技术实现的,因此它的效率比JDK动态代理更高。
-
CGLIB代理可以代理没有实现接口的类。
CGLIB代理的缺点:
-
CGLIB代理需要引入外部依赖。
-
CGLIB代理在生成代理对象时,需要改变原有类的结构,因此它可能会引起一些问题,例如无法代理final类或final方法等问题。
综上所述,JDK动态代理适用于代理接口实现类的场景,而CGLIB代理适用于代理没有实现接口的类的场景。如果你需要代理接口实现类,而且不想引入额外的依赖,那么JDK动态代理是一个不错的选择;如果你需要代理没有实现接口的类,那么CGLIB代理可能更适合你的需求。
此文章转载于面试官:为什么JDK动态代理只能代理接口?
如有侵权 联系 必删