mybatis源碼解讀之executor包懶加載功能?
ProxyFactory是創(chuàng)建代理類的工廠接口,其中的setProperties方法用來(lái)對(duì)工廠進(jìn)行屬性設(shè)置,但是mybatis內(nèi)置的兩個(gè)實(shí)現(xiàn)類都沒(méi)有實(shí)現(xiàn)該接口,所以不支持屬性設(shè)置。createProxy方法用來(lái)創(chuàng)建一個(gè)代理對(duì)象
public interface ProxyFactory {
? // 設(shè)置工廠屬性
? default void setProperties(Properties properties) {
? }
? // 創(chuàng)建代理對(duì)象
? Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
}ProxyFactory接口有2個(gè)實(shí)現(xiàn)類,CglibProxyFactory和JavassistProxyFactor類。這兩個(gè)實(shí)現(xiàn)類整體結(jié)構(gòu)高度一致,內(nèi)部類、方法設(shè)置都一樣,只是實(shí)現(xiàn)原理不同。CglibProxyFactory基于cglib實(shí)現(xiàn),JavassistProxyFactor基于javassist實(shí)現(xiàn)。
接下來(lái)以CglibProxyFactory類為源碼進(jìn)行分析:
CglibProxyFactory類中提供了兩個(gè)創(chuàng)建代理對(duì)象的方法。其中createProxy方法重寫了一個(gè)普通的代理對(duì)象,createDeserializationProxy方法用來(lái)創(chuàng)建一個(gè)反序列化的代理對(duì)象。
public class CglibProxyFactory implements ProxyFactory {
? private static final String FINALIZE_METHOD = "finalize";
? private static final String WRITE_REPLACE_METHOD = "writeReplace";
? public CglibProxyFactory() {
? ? try {
? ? ? Resources.classForName("net.sf.cglib.proxy.Enhancer");
? ? } catch (Throwable e) {
? ? ? throw new IllegalStateException("Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.", e);
? ? }
? }
? // 創(chuàng)建一個(gè)代理
? @Override
? public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
? ? return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
? }
? // 創(chuàng)建一個(gè)反序列化的代理
? public Object createDeserializationProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
? ? return EnhancedDeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs);
? }
? private static class EnhancedResultObjectProxyImpl implements MethodInterceptor {
? ? // 被代理類
? ? private final Class<?> type;
? ? // 要懶加載的屬性Map
? ? private final ResultLoaderMap lazyLoader;
? ? // 是否是激進(jìn)懶加載
? ? private final boolean aggressive;
? ? // 能夠觸發(fā)懶加載的方法名“equals”, “clone”, “hashCode”, “toString”。這四個(gè)方法名在Configuration中被初始化。
? ? private final Set<String> lazyLoadTriggerMethods;
? ? // 對(duì)象工廠
? ? private final ObjectFactory objectFactory;
? ? // 被代理類構(gòu)造函數(shù)的參數(shù)類型列表
? ? private final List<Class<?>> constructorArgTypes;
? ? // 被代理類構(gòu)造函數(shù)的參數(shù)列表
? ? private final List<Object> constructorArgs;
? ? private EnhancedResultObjectProxyImpl(Class<?> type, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
? ? ? this.type = type;
? ? ? this.lazyLoader = lazyLoader;
? ? ? this.aggressive = configuration.isAggressiveLazyLoading();
? ? ? this.lazyLoadTriggerMethods = configuration.getLazyLoadTriggerMethods();
? ? ? this.objectFactory = objectFactory;
? ? ? this.constructorArgTypes = constructorArgTypes;
? ? ? this.constructorArgs = constructorArgs;
? ? }
? ? public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
? ? ? final Class<?> type = target.getClass();
? ? ? EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl(type, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
? ? ? Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs);
? ? ? PropertyCopier.copyBeanProperties(type, target, enhanced);
? ? ? return enhanced;
? ? }
? ? /**
? ? ?* 代理類的攔截方法
? ? ?* @param enhanced 代理對(duì)象本身
? ? ?* @param method 被調(diào)用的方法
? ? ?* @param args 每調(diào)用的方法的參數(shù)
? ? ?* @param methodProxy 用來(lái)調(diào)用父類的代理
? ? ?* @return 方法返回值
? ? ?* @throws Throwable
? ? ?*/
? ? @Override
? ? public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
? ? ? // 取出被代理類中此次被調(diào)用的方法的名稱
? ? ? final String methodName = method.getName();
? ? ? try {
? ? ? ? synchronized (lazyLoader) { // 防止屬性的并發(fā)加載
? ? ? ? ? if (WRITE_REPLACE_METHOD.equals(methodName)) { // 被調(diào)用的是writeReplace方法
? ? ? ? ? ? // 創(chuàng)建一個(gè)原始對(duì)象
? ? ? ? ? ? Object original;
? ? ? ? ? ? if (constructorArgTypes.isEmpty()) {
? ? ? ? ? ? ? original = objectFactory.create(type);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? original = objectFactory.create(type, constructorArgTypes, constructorArgs);
? ? ? ? ? ? }
? ? ? ? ? ? // 將被代理對(duì)象的屬性拷貝進(jìn)入新創(chuàng)建的對(duì)象
? ? ? ? ? ? PropertyCopier.copyBeanProperties(type, enhanced, original);
? ? ? ? ? ? if (lazyLoader.size() > 0) { // 存在懶加載屬性
? ? ? ? ? ? ? // 則此時(shí)返回的信息要更多,不僅僅是原對(duì)象,還有相關(guān)的懶加載的設(shè)置等信息。因此使用CglibSerialStateHolder進(jìn)行一次封裝
? ? ? ? ? ? ? return new CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? // 沒(méi)有未懶加載的屬性了,那直接返回原對(duì)象進(jìn)行序列化
? ? ? ? ? ? ? return original;
? ? ? ? ? ? }
? ? ? ? ? } else {
? ? ? ? ? ? if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) { // 存在懶加載屬性且被調(diào)用的不是finalize方法
? ? ? ? ? ? ? if (aggressive || lazyLoadTriggerMethods.contains(methodName)) { // 設(shè)置了激進(jìn)懶加載或者被調(diào)用的方法是能夠觸發(fā)全局懶加載的方法
? ? ? ? ? ? ? ? // 完成所有屬性的懶加載
? ? ? ? ? ? ? ? lazyLoader.loadAll();
? ? ? ? ? ? ? } else if (PropertyNamer.isSetter(methodName)) { // 調(diào)用了屬性寫方法
? ? ? ? ? ? ? ? // 則先清除該屬性的懶加載設(shè)置。該屬性不需要被懶加載了
? ? ? ? ? ? ? ? final String property = PropertyNamer.methodToProperty(methodName);
? ? ? ? ? ? ? ? lazyLoader.remove(property);
? ? ? ? ? ? ? } else if (PropertyNamer.isGetter(methodName)) { // 調(diào)用了屬性讀方法
? ? ? ? ? ? ? ? final String property = PropertyNamer.methodToProperty(methodName);
? ? ? ? ? ? ? ? // 如果該屬性是尚未加載的懶加載屬性,則進(jìn)行懶加載
? ? ? ? ? ? ? ? if (lazyLoader.hasLoader(property)) {
? ? ? ? ? ? ? ? ? lazyLoader.load(property);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? }
? ? ? ? // 觸發(fā)被代理類的相應(yīng)方法。能夠進(jìn)行到這里的是除去writeReplace方法外的方法,例如讀寫方法、toString方法等
? ? ? ? return methodProxy.invokeSuper(enhanced, args);
? ? ? } catch (Throwable t) {
? ? ? ? throw ExceptionUtil.unwrapThrowable(t);
? ? ? }
? ? }
? }
? }代理類最核心的方法是intercept方法,當(dāng)被代理對(duì)象的其他方法被調(diào)用時(shí),intercept方法的處理方式是:
如果設(shè)置了激進(jìn)懶加載或者被調(diào)用的是觸發(fā)全局加載的方法,則直接加載所有未加載的屬性。
如果被調(diào)用的是屬性寫方法,則將該方法從懶加載列表中刪除,因?yàn)榇藭r(shí)數(shù)據(jù)庫(kù)中的數(shù)據(jù)已經(jīng)不是最新的,沒(méi)有必要再去加載,然后進(jìn)行屬性的寫入操作。
如果被調(diào)用的是讀方法,則該屬性尚未被懶加載的情況下,則加載該屬性,如果該屬性已經(jīng)被懶加載過(guò),則直接讀取該屬性。
ResultLoaderMap類:
被代理對(duì)象可能會(huì)有多個(gè)屬性可以被懶加載,這些尚未完成加載的屬性是在ResultLoaderMap類的實(shí)例中存儲(chǔ)的。ResultLoaderMap類主要就是一個(gè)map類,該類key為屬性名的大寫,value為L(zhǎng)oadPair對(duì)象。LoadPair類是ResultLoaderMap類的內(nèi)部類,它能實(shí)現(xiàn)對(duì)應(yīng)屬性的懶加載功能。
public static class LoadPair implements Serializable {
? ? private static final long serialVersionUID = 20130412;
??
? ? // 用來(lái)根據(jù)反射得到數(shù)據(jù)庫(kù)連接的方法名
? ? private static final String FACTORY_METHOD = "getConfiguration";
? ??
? ? // 判斷是否經(jīng)過(guò)了序列化的標(biāo)志位,因?yàn)樵搶傩员辉O(shè)置了transient,經(jīng)過(guò)一次序列化和反序列化后會(huì)變?yōu)閚ull
? ? private final transient Object serializationCheck = new Object();
? ?
? ? // 輸出結(jié)果對(duì)象的封裝
? ? private transient MetaObject metaResultObject;
? ?
? ? // 用以加載未加載屬性的加載器
? ? private transient ResultLoader resultLoader;
??
? ? // 日志記錄器
? ? private transient Log log;
? ??
? ? // 用來(lái)獲取數(shù)據(jù)庫(kù)連接的工廠
? ? private Class<?> configurationFactory;
? ??
? ? // 未加載的屬性的屬性名
? ? private String property;
? ?
? ? // 能夠加載未加載屬性的SQL的編號(hào)
? ? private String mappedStatement;
??
? ? // 能夠加載未加載屬性的SQL的參數(shù)
? ? private Serializable mappedParameter;
? ? private LoadPair(final String property, MetaObject metaResultObject, ResultLoader resultLoader) {
? ? ? this.property = property;
? ? ? this.metaResultObject = metaResultObject;
? ? ? this.resultLoader = resultLoader;
? ? ? if (metaResultObject != null && metaResultObject.getOriginalObject() instanceof Serializable) {
? ? ? ? final Object mappedStatementParameter = resultLoader.parameterObject;
? ? ? ? if (mappedStatementParameter instanceof Serializable) {
? ? ? ? ? this.mappedStatement = resultLoader.mappedStatement.getId();
? ? ? ? ? this.mappedParameter = (Serializable) mappedStatementParameter;
? ? ? ? ? this.configurationFactory = resultLoader.configuration.getConfigurationFactory();
? ? ? ? } else {
? ? ? ? ? Log log = this.getLogger();
? ? ? ? ? if (log.isDebugEnabled()) {
? ? ? ? ? ? log.debug("Property [" + this.property + "] of ["
? ? ? ? ? ? ? ? ? ? + metaResultObject.getOriginalObject().getClass() + "] cannot be loaded "
? ? ? ? ? ? ? ? ? ? + "after deserialization. Make sure it's loaded before serializing "
? ? ? ? ? ? ? ? ? ? + "forenamed object.");
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? }
? ? public void load() throws SQLException {
? ? ? if (this.metaResultObject == null) {
? ? ? ? throw new IllegalArgumentException("metaResultObject is null");
? ? ? }
? ? ? if (this.resultLoader == null) {
? ? ? ? throw new IllegalArgumentException("resultLoader is null");
? ? ? }
? ? ? this.load(null);
? ? }
? ? /**
? ? ?* 進(jìn)行加載操作
? ? ?* @param userObject 需要被懶加載的對(duì)象(只有當(dāng)this.metaResultObject == null || this.resultLoader == null才生效,否則會(huì)采用屬性metaResultObject對(duì)應(yīng)的對(duì)象)
? ? ?* @throws SQLException
? ? ?*/
? ? public void load(final Object userObject) throws SQLException {
? ? ? if (this.metaResultObject == null || this.resultLoader == null) { // 輸出結(jié)果對(duì)象的封裝不存在或者輸出結(jié)果加載器不存在
? ? ? ? // 判斷用以加載屬性的對(duì)應(yīng)的SQL語(yǔ)句存在
? ? ? ? if (this.mappedParameter == null) {
? ? ? ? ? throw new ExecutorException("Property [" + this.property + "] cannot be loaded because "
? ? ? ? ? ? ? ? ? + "required parameter of mapped statement ["
? ? ? ? ? ? ? ? ? + this.mappedStatement + "] is not serializable.");
? ? ? ? }
? ? ? ? final Configuration config = this.getConfiguration();
? ? ? ? // 取出用來(lái)加載結(jié)果的SQL語(yǔ)句
? ? ? ? final MappedStatement ms = config.getMappedStatement(this.mappedStatement);
? ? ? ? if (ms == null) {
? ? ? ? ? throw new ExecutorException("Cannot lazy load property [" + this.property
? ? ? ? ? ? ? ? ? + "] of deserialized object [" + userObject.getClass()
? ? ? ? ? ? ? ? ? + "] because configuration does not contain statement ["
? ? ? ? ? ? ? ? ? + this.mappedStatement + "]");
? ? ? ? }
? ? ? ? // 創(chuàng)建結(jié)果對(duì)象的包裝
? ? ? ? this.metaResultObject = config.newMetaObject(userObject);
? ? ? ? // 創(chuàng)建結(jié)果加載器
? ? ? ? this.resultLoader = new ResultLoader(config, new ClosedExecutor(), ms, this.mappedParameter,
? ? ? ? ? ? ? ? metaResultObject.getSetterType(this.property), null, null);
? ? ? }
? ? ? // 只要經(jīng)歷過(guò)持久化,則可能在別的線程中了。為這次惰性加載創(chuàng)建的新線程ResultLoader
? ? ? if (this.serializationCheck == null) {
? ? ? ? // 取出原來(lái)的ResultLoader中的必要信息,然后創(chuàng)建一個(gè)新的
? ? ? ? // 這是因?yàn)閘oad函數(shù)可能在不同的時(shí)間多次執(zhí)行(第一次加載屬性A,又過(guò)了好久加載屬性B)。
? ? ? ? // 而該對(duì)象的各種屬性是跟隨對(duì)象的,加載屬性B時(shí)還保留著加載屬性A時(shí)的狀態(tài),即ResultLoader是加載屬性A時(shí)設(shè)置的
? ? ? ? // 則此時(shí)ResultLoader中的Executor在ResultLoader中被替換成了一個(gè)能運(yùn)行的Executor,而不是ClosedExecutor
? ? ? ? // 能運(yùn)行的Executor的狀態(tài)可能不是close,這將導(dǎo)致它被復(fù)用,從而引發(fā)多線程問(wèn)題
? ? ? ? // 是不是被兩次執(zhí)行的一個(gè)關(guān)鍵點(diǎn)就是有沒(méi)有經(jīng)過(guò)序列化,因?yàn)閳?zhí)行完后會(huì)被序列化并持久化
? ? ? ? final ResultLoader old = this.resultLoader;
? ? ? ? this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement,
? ? ? ? ? ? ? ? old.parameterObject, old.targetType, old.cacheKey, old.boundSql);
? ? ? }
? ? ? this.metaResultObject.setValue(property, this.resultLoader.loadResult());
? ? }
? ? private Configuration getConfiguration() {
? ? ? if (this.configurationFactory == null) {
? ? ? ? throw new ExecutorException("Cannot get Configuration as configuration factory was not set.");
? ? ? }
? ? ? Object configurationObject;
? ? ? try {
? ? ? ? final Method factoryMethod = this.configurationFactory.getDeclaredMethod(FACTORY_METHOD);
? ? ? ? if (!Modifier.isStatic(factoryMethod.getModifiers())) {
? ? ? ? ? throw new ExecutorException("Cannot get Configuration as factory method ["
? ? ? ? ? ? ? ? ? + this.configurationFactory + "]#["
? ? ? ? ? ? ? ? ? + FACTORY_METHOD + "] is not static.");
? ? ? ? }
? ? ? ? if (!factoryMethod.isAccessible()) {
? ? ? ? ? configurationObject = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
? ? ? ? ? ? try {
? ? ? ? ? ? ? factoryMethod.setAccessible(true);
? ? ? ? ? ? ? return factoryMethod.invoke(null);
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? factoryMethod.setAccessible(false);
? ? ? ? ? ? }
? ? ? ? ? });
? ? ? ? } else {
? ? ? ? ? configurationObject = factoryMethod.invoke(null);
? ? ? ? }
? ? ? } catch (final ExecutorException ex) {
? ? ? ? throw ex;
? ? ? } catch (final NoSuchMethodException ex) {
? ? ? ? throw new ExecutorException("Cannot get Configuration as factory class ["
? ? ? ? ? ? ? ? + this.configurationFactory + "] is missing factory method of name ["
? ? ? ? ? ? ? ? + FACTORY_METHOD + "].", ex);
? ? ? } catch (final PrivilegedActionException ex) {
? ? ? ? throw new ExecutorException("Cannot get Configuration as factory method ["
? ? ? ? ? ? ? ? + this.configurationFactory + "]#["
? ? ? ? ? ? ? ? + FACTORY_METHOD + "] threw an exception.", ex.getCause());
? ? ? } catch (final Exception ex) {
? ? ? ? throw new ExecutorException("Cannot get Configuration as factory method ["
? ? ? ? ? ? ? ? + this.configurationFactory + "]#["
? ? ? ? ? ? ? ? + FACTORY_METHOD + "] threw an exception.", ex);
? ? ? }
? ? ? if (!(configurationObject instanceof Configuration)) {
? ? ? ? throw new ExecutorException("Cannot get Configuration as factory method ["
? ? ? ? ? ? ? ? + this.configurationFactory + "]#["
? ? ? ? ? ? ? ? + FACTORY_METHOD + "] didn't return [" + Configuration.class + "] but ["
? ? ? ? ? ? ? ? + (configurationObject == null ? "null" : configurationObject.getClass()) + "].");
? ? ? }
? ? ? return Configuration.class.cast(configurationObject);
? ? }
? ? private Log getLogger() {
? ? ? if (this.log == null) {
? ? ? ? this.log = LogFactory.getLog(this.getClass());
? ? ? }
? ? ? return this.log;
? ? }
? }
到此這篇關(guān)于mybatis源碼解讀之executor包懶加載功能 的文章就介紹到這了,更多相關(guān)executor包懶加載功能 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Dubbo在Spring和Spring Boot中的使用詳解
這篇文章主要介紹了Dubbo在Spring和Spring Boot中的使用詳解,需要的朋友可以參考下2017-10-10
SpringCloud @RefreshScope刷新機(jī)制深入探究
RefeshScope這個(gè)注解想必大家都用過(guò),在微服務(wù)配置中心的場(chǎng)景下經(jīng)常出現(xiàn),他可以用來(lái)刷新Bean中的屬性配置,那大家對(duì)他的實(shí)現(xiàn)原理了解嗎?它為什么可以做到動(dòng)態(tài)刷新呢2023-03-03
教你Spring Cloud保證各個(gè)微服務(wù)之間調(diào)用安全性
在微服務(wù)的架構(gòu)下,系統(tǒng)會(huì)根據(jù)業(yè)務(wù)拆分為多個(gè)服務(wù),各自負(fù)責(zé)單一的職責(zé),在這樣的架構(gòu)下,我們需要確保各api的安全性,今天通過(guò)本文給大家分享Spring Cloud中如何保證各個(gè)微服務(wù)之間調(diào)用的安全性,需要的朋友參考下吧2021-08-08
SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)一角色權(quán)限校驗(yàn)
這篇文章主要介紹了SpringBoot如何使用AOP實(shí)現(xiàn) 統(tǒng)一角色權(quán)限校驗(yàn),文中有詳細(xì)的代碼示例講解和操作流程,具有一定的參考價(jià)值,需要的朋友可以參考下2023-07-07
Intellij Idea 多模塊Maven工程中模塊之間無(wú)法相互引用問(wèn)題
這篇文章主要介紹了Intellij Idea 多模塊Maven工程中模塊之間無(wú)法相互引用問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
SpringBoot如何使用RateLimiter通過(guò)AOP方式進(jìn)行限流
這篇文章主要介紹了SpringBoot如何使用RateLimiter通過(guò)AOP方式進(jìn)行限流,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
最值得Java開(kāi)發(fā)者收藏的網(wǎng)站
這篇文章主要為大家分享了最值得Java開(kāi)發(fā)者收藏的11個(gè)網(wǎng)站,幫助Java開(kāi)發(fā)者提升編程能力2016-11-11

