欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

mybatis源碼解讀之executor包懶加載功能?

 更新時間:2022年02月15日 17:23:34   作者:灰太狼_cxh  
這篇文章主要介紹了mybatis源碼解讀之executor包懶加載功能,mybatis的懶加載的實現(xiàn)由executor包的loader子包支持,下面文章詳細(xì)內(nèi)容需要的小伙伴可以參考一下

ProxyFactory是創(chuàng)建代理類的工廠接口,其中的setProperties方法用來對工廠進行屬性設(shè)置,但是mybatis內(nèi)置的兩個實現(xiàn)類都沒有實現(xiàn)該接口,所以不支持屬性設(shè)置。createProxy方法用來創(chuàng)建一個代理對象

public interface ProxyFactory {

? // 設(shè)置工廠屬性
? default void setProperties(Properties properties) {
? }

? // 創(chuàng)建代理對象
? Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

}

ProxyFactory接口有2個實現(xiàn)類,CglibProxyFactoryJavassistProxyFactor類。這兩個實現(xiàn)類整體結(jié)構(gòu)高度一致,內(nèi)部類、方法設(shè)置都一樣,只是實現(xiàn)原理不同。CglibProxyFactory基于cglib實現(xiàn),JavassistProxyFactor基于javassist實現(xiàn)。

接下來以CglibProxyFactory類為源碼進行分析:

CglibProxyFactory類中提供了兩個創(chuàng)建代理對象的方法。其中createProxy方法重寫了一個普通的代理對象,createDeserializationProxy方法用來創(chuàng)建一個反序列化的代理對象。

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)建一個代理
? @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)建一個反序列化的代理
? 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;
? ? // 是否是激進懶加載
? ? private final boolean aggressive;
? ? // 能夠觸發(fā)懶加載的方法名“equals”, “clone”, “hashCode”, “toString”。這四個方法名在Configuration中被初始化。
? ? private final Set<String> lazyLoadTriggerMethods;
? ? // 對象工廠
? ? 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 代理對象本身
? ? ?* @param method 被調(diào)用的方法
? ? ?* @param args 每調(diào)用的方法的參數(shù)
? ? ?* @param methodProxy 用來調(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)建一個原始對象
? ? ? ? ? ? Object original;
? ? ? ? ? ? if (constructorArgTypes.isEmpty()) {
? ? ? ? ? ? ? original = objectFactory.create(type);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? original = objectFactory.create(type, constructorArgTypes, constructorArgs);
? ? ? ? ? ? }
? ? ? ? ? ? // 將被代理對象的屬性拷貝進入新創(chuàng)建的對象
? ? ? ? ? ? PropertyCopier.copyBeanProperties(type, enhanced, original);
? ? ? ? ? ? if (lazyLoader.size() > 0) { // 存在懶加載屬性
? ? ? ? ? ? ? // 則此時返回的信息要更多,不僅僅是原對象,還有相關(guān)的懶加載的設(shè)置等信息。因此使用CglibSerialStateHolder進行一次封裝
? ? ? ? ? ? ? return new CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? // 沒有未懶加載的屬性了,那直接返回原對象進行序列化
? ? ? ? ? ? ? return original;
? ? ? ? ? ? }
? ? ? ? ? } else {
? ? ? ? ? ? if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) { // 存在懶加載屬性且被調(diào)用的不是finalize方法
? ? ? ? ? ? ? if (aggressive || lazyLoadTriggerMethods.contains(methodName)) { // 設(shè)置了激進懶加載或者被調(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);
? ? ? ? ? ? ? ? // 如果該屬性是尚未加載的懶加載屬性,則進行懶加載
? ? ? ? ? ? ? ? if (lazyLoader.hasLoader(property)) {
? ? ? ? ? ? ? ? ? lazyLoader.load(property);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? }
? ? ? ? // 觸發(fā)被代理類的相應(yīng)方法。能夠進行到這里的是除去writeReplace方法外的方法,例如讀寫方法、toString方法等
? ? ? ? return methodProxy.invokeSuper(enhanced, args);
? ? ? } catch (Throwable t) {
? ? ? ? throw ExceptionUtil.unwrapThrowable(t);
? ? ? }
? ? }
? }
? }

代理類最核心的方法是intercept方法,當(dāng)被代理對象的其他方法被調(diào)用時,intercept方法的處理方式是:

如果設(shè)置了激進懶加載或者被調(diào)用的是觸發(fā)全局加載的方法,則直接加載所有未加載的屬性。

如果被調(diào)用的是屬性寫方法,則將該方法從懶加載列表中刪除,因為此時數(shù)據(jù)庫中的數(shù)據(jù)已經(jīng)不是最新的,沒有必要再去加載,然后進行屬性的寫入操作。

如果被調(diào)用的是讀方法,則該屬性尚未被懶加載的情況下,則加載該屬性,如果該屬性已經(jīng)被懶加載過,則直接讀取該屬性。

ResultLoaderMap類:

被代理對象可能會有多個屬性可以被懶加載,這些尚未完成加載的屬性是在ResultLoaderMap類的實例中存儲的。ResultLoaderMap類主要就是一個map類,該類key為屬性名的大寫,value為LoadPair對象。LoadPair類是ResultLoaderMap類的內(nèi)部類,它能實現(xiàn)對應(yīng)屬性的懶加載功能。

public static class LoadPair implements Serializable {
? ? private static final long serialVersionUID = 20130412;
??
? ? // 用來根據(jù)反射得到數(shù)據(jù)庫連接的方法名
? ? private static final String FACTORY_METHOD = "getConfiguration";
? ??
? ? // 判斷是否經(jīng)過了序列化的標(biāo)志位,因為該屬性被設(shè)置了transient,經(jīng)過一次序列化和反序列化后會變?yōu)閚ull
? ? private final transient Object serializationCheck = new Object();
? ?
? ? // 輸出結(jié)果對象的封裝
? ? private transient MetaObject metaResultObject;
? ?
? ? // 用以加載未加載屬性的加載器
? ? private transient ResultLoader resultLoader;
??
? ? // 日志記錄器
? ? private transient Log log;
? ??
? ? // 用來獲取數(shù)據(jù)庫連接的工廠
? ? private Class<?> configurationFactory;
? ??
? ? // 未加載的屬性的屬性名
? ? private String property;
? ?
? ? // 能夠加載未加載屬性的SQL的編號
? ? 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);
? ? }

? ? /**
? ? ?* 進行加載操作
? ? ?* @param userObject 需要被懶加載的對象(只有當(dāng)this.metaResultObject == null || this.resultLoader == null才生效,否則會采用屬性metaResultObject對應(yīng)的對象)
? ? ?* @throws SQLException
? ? ?*/
? ? public void load(final Object userObject) throws SQLException {
? ? ? if (this.metaResultObject == null || this.resultLoader == null) { // 輸出結(jié)果對象的封裝不存在或者輸出結(jié)果加載器不存在
? ? ? ? // 判斷用以加載屬性的對應(yīng)的SQL語句存在
? ? ? ? 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();
? ? ? ? // 取出用來加載結(jié)果的SQL語句
? ? ? ? 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é)果對象的包裝
? ? ? ? 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)歷過持久化,則可能在別的線程中了。為這次惰性加載創(chuàng)建的新線程ResultLoader
? ? ? if (this.serializationCheck == null) {
? ? ? ? // 取出原來的ResultLoader中的必要信息,然后創(chuàng)建一個新的
? ? ? ? // 這是因為load函數(shù)可能在不同的時間多次執(zhí)行(第一次加載屬性A,又過了好久加載屬性B)。
? ? ? ? // 而該對象的各種屬性是跟隨對象的,加載屬性B時還保留著加載屬性A時的狀態(tài),即ResultLoader是加載屬性A時設(shè)置的
? ? ? ? // 則此時ResultLoader中的Executor在ResultLoader中被替換成了一個能運行的Executor,而不是ClosedExecutor
? ? ? ? // 能運行的Executor的狀態(tài)可能不是close,這將導(dǎo)致它被復(fù)用,從而引發(fā)多線程問題
? ? ? ? // 是不是被兩次執(zhí)行的一個關(guān)鍵點就是有沒有經(jīng)過序列化,因為執(zhí)行完后會被序列化并持久化
? ? ? ? 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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入解析Java編程中final關(guān)鍵字的使用

    深入解析Java編程中final關(guān)鍵字的使用

    這篇文章主要介紹了Java編程中final關(guān)鍵字的使用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2016-01-01
  • Springboot MultipartFile文件上傳與下載的實現(xiàn)示例

    Springboot MultipartFile文件上傳與下載的實現(xiàn)示例

    在Spring Boot項目中,可以使用MultipartFile類來處理文件上傳和下載操作,本文就詳細(xì)介紹了如何使用,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • Java編程多線程之共享數(shù)據(jù)代碼詳解

    Java編程多線程之共享數(shù)據(jù)代碼詳解

    這篇文章主要介紹了Java編程多線程之共享數(shù)據(jù)代碼詳解,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • SpringBoot的服務(wù)注冊與發(fā)現(xiàn)示例

    SpringBoot的服務(wù)注冊與發(fā)現(xiàn)示例

    本篇文章主要介紹了SpringBoot的服務(wù)注冊與發(fā)現(xiàn)示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java之一文詳解String字符串的用法

    Java之一文詳解String字符串的用法

    本文將給大家重點講解一下String的用法,因為這個太常用,也太??剂恕tring字符串的內(nèi)容是比較多的,需要初學(xué)者進行專門的學(xué)習(xí),尤其是它的一些底層原理更需要我們來了解,需要的同學(xué)跟著小編一起學(xué)習(xí)吧
    2023-05-05
  • Eclipse如何導(dǎo)入Maven項目詳解(新手初學(xué))

    Eclipse如何導(dǎo)入Maven項目詳解(新手初學(xué))

    這篇文章主要介紹了Eclipse如何導(dǎo)入Maven項目詳解(新手初學(xué)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • 一篇文章帶你Java Spring開發(fā)入門

    一篇文章帶你Java Spring開發(fā)入門

    這篇文章主要為大家詳細(xì)介紹了Java Spring開發(fā)入門學(xué)習(xí)教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-09-09
  • SpringBoot動態(tài)定時任務(wù)實現(xiàn)完整版

    SpringBoot動態(tài)定時任務(wù)實現(xiàn)完整版

    最近有幸要開發(fā)個動態(tài)定時任務(wù),這里簡單再梳理一下,下面這篇文章主要給大家介紹了關(guān)于SpringBoot動態(tài)定時任務(wù)實現(xiàn)的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • java實現(xiàn)拼圖游戲

    java實現(xiàn)拼圖游戲

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)拼圖游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Java注解(annotation)簡述

    Java注解(annotation)簡述

    這篇文章主要介紹了使用java的注解(用在java類的方法上的注解)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08

最新評論