IT评测·应用市场-qidao123.com技术社区
标题:
深入解析署理模式:静态署理与动态署理的比较及JDK与CGLIB动态署理技术
[打印本页]
作者:
麻花痒
时间:
2024-7-12 11:33
标题:
深入解析署理模式:静态署理与动态署理的比较及JDK与CGLIB动态署理技术
1. 静态署理与动态署理的区别
静态署理和动态署理都是实现署理模式的方式,它们在实现上有很大的不同。下面是它们的重要区别:
实现方式不同
静态署理
静态署理是在编译期就已经确定署理对象的类型。署理类需要手动编写,并实现被署理类的接口。
动态署理
动态署理是在运行时动态天生署理对象,署理类不需要手动编写,而是由框架自动天生。Java中的动态署理通常利用Proxy类和InvocationHandler接口实现。
实用范围不同
静态署理
静态署理只实用于署理对象类型固定、接口较少的情况下。每增加一个被署理的接口,就需要编写一个新的署理类。
动态署理
动态署理可以署理恣意的接口,无需编写新的署理类,因此更加机动。实用于署理对象类型不固定、接口较多、机动性要求较高的情况。
性能体现不同
静态署理
由于静态署理在编译期就已经确定署理对象的类型,因此在运行时执行服从较高。
动态署理
动态署理在运行时需要进行额外的署理对象天生、方法调用转发等操作,因此会存在肯定的性能损失。
动态署理的类天生过程
Java假造机类加载过程重要分为五个阶段:加载、验证、准备、解析、初始化。
加载阶段
加载阶段需要完成以下三件事变:
通过一个类的全限定名来获取定义此类的二进制字节省。
将这个字节省所代表的静态存储结构转化为方法区的运行时数据结构。
在内存中天生一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。
获取类的二进制字节省的方法
从当地获取
:Java假造机可以从当地文件系统加载类的字节码文件。
从网络中获取
:Java假造机也可以从网络中加载类的字节码数据。利用类加载器的getResourceAsStream()方法,通过指定URL的方式来获取InputStream,然后通过读取InputStream获取字节码数据。
运行时计算天生
:这种场景利用最多的是动态署理技术,在java.lang.reflect.Proxy类中,就是用了ProxyGenerator.generateProxyClass来为特定接口天生形式为*$Proxy的署理类的二进制字节省。
总结
静态署理实用于署理对象类型固定、接口较少、性能要求较高的情况。
动态署理实用于署理对象类型不固定、接口较多、机动性要求较高的情况。
通过动态署理,可以根据接口或目的对象,计算出署理类的字节码,然后再加载到JVM中利用,使得署理对象的天生和方法调用更加机动和动态。
JDK动态署理和CGLIB动态署理是Java语言中实现动态署理的两种方式。它们之间的重要区别如下:
2. JDK动态署理与CGLIB动态署理的区别?
基于的技术不同
JDK动态署理
:基于Java的反射机制实现。利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来创建动态署理类。
CGLIB动态署理
:基于字节码天生技术实现。利用CGLIB库天生署理类,通过操作字节码来天生署理类的子类。
被署理类的要求不同
JDK动态署理
:只能署理实现了接口的类。署理类必须实现被署理类的所有接口。
CGLIB动态署理
:可以署理没有实现接口的类。署理类通过继续被署理类来天生署理对象。
署理性能不同
JDK动态署理
:天生的署理类性能相对较低,由于它是基于反射实现的,每次方法调用都需要通过反射机制来处理。
CGLIB动态署理
:天生的署理类性能相对较高,由于它是基于字节码天生技术实现的,直接天生字节码来处理方法调用。
署理方式不同
JDK动态署理
:基于接口实现的署理方式。署理类必须实现被署理类的所有接口。
CGLIB动态署理
:基于继续实现的署理方式。署理类通过继续被署理类来天生署理对象。
选择依据
如果被署理类实现了接口,优先选择JDK动态署理。
如果被署理类没有实现接口,只能利用CGLIB动态署理。
JDK动态署理示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("Real subject request.");
}
}
public class ProxyHandler implements InvocationHandler {
private Object realSubject;
public ProxyHandler(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
preRequest();
Object result = method.invoke(realSubject, args);
postRequest();
return result;
}
private void preRequest() {
System.out.println("Pre request processing.");
}
private void postRequest() {
System.out.println("Post request processing.");
}
}
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new ProxyHandler(realSubject)
);
proxy.request();
}
}
复制代码
CGLIB动态署理示例
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class RealSubject {
public void request() {
System.out.println("Real subject request.");
}
}
public class ProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
preRequest();
Object result = proxy.invokeSuper(obj, args);
postRequest();
return result;
}
private void preRequest() {
System.out.println("Pre request processing.");
}
private void postRequest() {
System.out.println("Post request processing.");
}
}
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new ProxyInterceptor());
RealSubject proxy = (RealSubject) enhancer.create();
proxy.request();
}
}
复制代码
底层实现
JDK动态署理
JDK天生署理对象依赖的是反射。动态署理类对象继续了Proxy类,并且实现了被署理的所有接口。
CGLIB动态署理
CGLIB(Code Generation Library)是一个第三方代码天生类库,运行时在内存中动态天生一个子类对象从而实现对目的对象功能的扩展。CGLIB基于ASM字节码工具操作字节码(即动态天生署理,对方法进行加强)。Spring AOP(面向切面编程)基于CGLIB进行封装,实现CGLIB方式的动态署理。
总结
JDK动态署理
:实用于署理接口方法,性能稍低,利用反射机制。
CGLIB动态署理
:实用于署理普通类方法,性能较高,利用字节码天生技术。如果被署理类实现了接口,优先选择JDK动态署理;如果被署理类没有实现接口,那么只能利用CGLIB动态署理。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4