ORM框架之Mybatis(七):configuration配置源碼除探

建造者模式是Java基本設(shè)計模式的一種,是經(jīng)常被使用到的老翘。比如在開發(fā)過程中經(jīng)常使用的lambok插件芹啥,在實體類上加上@Builder就可以使用建造者模式方式構(gòu)建實體對象。這mybatis中同樣也使用到了這種設(shè)計模式铺峭,但是不是使用的lambok插件墓怀。在讀取配置文件的時候,需要讀取各種類型的標簽卫键,讓構(gòu)造器和標簽對應(yīng)傀履,可以將標簽的屬性及相關(guān)的值放到構(gòu)建器中,然后由構(gòu)建器構(gòu)建一個對象莉炉,這個對象中封裝了標簽的信息钓账,提供后續(xù)使用。

其實里面還使用到裝飾者模式絮宁,這篇文章先不說梆暮,后續(xù)出文再具體說裝飾者模式∩馨海可以劇透一下啦粹,在二級緩存中,使用裝飾器模式給二級緩存加各種功能窘游。

mybatis讀取配置

涉及到mybatis的配置文件不多唠椭,主要就是mybatis-config.xml核心配置文件,然后就是mapper.xml映射文件忍饰。mybatis在讀取配置文件的時候也是按照這個順序贪嫂,先讀核心配置文件,將核心配置文件中的信息封裝到核心配置類Configuration中喘批。核心配置文件中配置了mapper.xml的位置撩荣,然后根據(jù)配置的路徑讀取mapper.xml铣揉。整個過程思路很清晰,其中涉及到三個核心的類XMLConfigBuilder餐曹、XMLMapperBuilder逛拱、XMLStatementBuilder。來看下面的圖台猴。

image

從圖里面可以看的出來朽合,就是將相關(guān)配置文件的信息經(jīng)過封裝,然后統(tǒng)一放到Configuration配置類中饱狂。

XMLConfigBuilder源碼

接下來看XMLConfigBuilder加載核心配置文件的代碼曹步,這個過程其實不難,流程也很清晰休讳。

parse

parse方法是入口讲婚,在配置文件被讀入到parser解析器后,會調(diào)用這個方法開始解析工作俊柔。

//配置類開始解析的方法
public Configuration parse() {
    if (parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    //設(shè)置開始解析的標識筹麸,防止重復(fù)解析
    parsed = true;
    //調(diào)用解析核心配置文件的方法
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}

上面這個方法首先是判斷當前配置文件是否已經(jīng)在解析了,保證同一個文件不會被重復(fù)的解析雏婶。

parseConfiguration

這里就是開始真正的解析配置文件中的內(nèi)容啦物赶。

//解析mybatis核心配置文件mybatis-config.xml,configuration是此文件的根目錄
private void parseConfiguration(XNode root) {
    try {
        //issue #117 read properties first
        //獲取properties標簽信息
        propertiesElement(root.evalNode("properties"));
        //獲取settings標簽設(shè)置信息
        Properties settings = settingsAsProperties(root.evalNode("settings"));
        loadCustomVfs(settings);
        //獲取別名信息
        typeAliasesElement(root.evalNode("typeAliases"));
        //獲取插件信息
        pluginElement(root.evalNode("plugins"));
        //objectFactory留晚、objectWrapperFactory酵紫、reflectorFactory信息(一般項目上用不上這些信息)
        objectFactoryElement(root.evalNode("objectFactory"));
        objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        reflectorFactoryElement(root.evalNode("reflectorFactory"));
        //設(shè)置配置信息
        settingsElement(settings);
        // read it after objectFactory and objectWrapperFactory issue #631
        //解析環(huán)境信息(數(shù)據(jù)庫信息+事務(wù)信息)
        environmentsElement(root.evalNode("environments"));
        databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        //類型處理器
        typeHandlerElement(root.evalNode("typeHandlers"));
        //mapper.xml文件
        mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

流程很清晰,在之前的基礎(chǔ)文章中也寫過在核心配置文件中的主要標簽错维,這里基本都體現(xiàn)到了奖地,就是對這些主要的標簽進行依次的解析。(核心標簽的的文章可以參考這篇文章:ORM框架之Mybatis:基礎(chǔ)配置

這個方法的流程就不介紹了赋焕,上面的源碼中也有注釋鹉动。

settingsAsProperties

這里是mybatis-config.xml核心配置文件中<settings>標簽的解析。

private Properties settingsAsProperties(XNode context) {
    if (context == null) {
        return new Properties();
    }
    Properties props = context.getChildrenAsProperties();//獲取所有子標簽信息
    // Check that all settings are known to the configuration class
    //檢查settings里面加的配置信息是否是可配置項
    MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
    for (Object key : props.keySet()) {
        if (!metaConfig.hasSetter(String.valueOf(key))) {
            throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
        }
    }
    return props;
}

這里就是讀取<settings>標簽下的所有子標簽宏邮,并將子標簽信息封裝到pros中返回。讀取的過程是在第五行代碼缸血。

public Properties getChildrenAsProperties() {
  Properties properties = new Properties();
  for (XNode child : getChildren()) {
    String name = child.getStringAttribute("name");
    String value = child.getStringAttribute("value");
    if (name != null && value != null) {
      properties.setProperty(name, value);
    }
  }
  return properties;
}

遍歷子標簽蜜氨,讀取子標簽的namevalue屬性,然后封裝捎泻。沒有復(fù)雜的邏輯飒炎。

到這里這個<settings>標簽下的所有內(nèi)容就都讀取成功啦。

settingsElement

這個方法很實用的笆豁,平時在開發(fā)過程中都會設(shè)置各種配置參數(shù)郎汪,配置參數(shù)也有對應(yīng)的默認值赤赊,什么時候需要配置,什么時候不需要配置使用默認就好煞赢。都是在這里面啦抛计。

//將settings標簽的子標簽配置信息設(shè)置到Configuration內(nèi),部分配置信息有對應(yīng)的默認值
private void settingsElement(Properties props) throws Exception {
    //autoMappingBehavior,默認值PARTIAL
    configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    //autoMappingUnknownColumnBehavior,默認值NONE
    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    //cacheEnabled,二級緩存全局開關(guān)照筑,默認值true
    configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
    //proxyFactory吹截,代理工廠,無默認值
    configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
    //lazyLoadingEnabled凝危,是否可以延遲加載波俄,默認值false
    configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
    //aggressiveLazyLoading,侵略性懶加載屬性蛾默,也就是按需加載的意思懦铺,默認值false
    configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
    //multipleResultSetsEnabled,默認值true
    configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    //useColumnLabel支鸡,默認值true
    configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
    //useGeneratedKeys冬念,使用生成鍵,默認值false
    configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    //defaultExecutorType苍匆,默認執(zhí)行器類型刘急,默認值是SIMPLE,可選值SIMPLE, REUSE, BATCH
    configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    //defaultStatementTimeout浸踩,默認值null
    configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
    //defaultFetchSize叔汁,默認值null
    configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
    //mapUnderscoreToCamelCase,駝峰規(guī)則自動映射检碗,默認是false
    configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    //safeRowBoundsEnabled据块,默認值false
    configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    //localCacheScope,緩存返回折剃,默認是SESSION另假,可選值SESSION,STATEMENT
    configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    //jdbcTypeForNull,默認值OTHER怕犁,可選值很多边篮,參考JdbcType類
    configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    //lazyLoadTriggerMethods,懶加載觸發(fā)的方法奏甫,equals,clone,hashCode,toString
    //如果重寫了這些方法戈轿,不涉及關(guān)聯(lián)對象,懶加載也不會被觸發(fā)
    configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    //safeResultHandlerEnabled阵子,默認值true
    configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    //defaultScriptingLanguage思杯,默認腳本語言,無默認值
    configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
    //defaultEnumTypeHandler挠进,枚舉類型處理器色乾,無默認值
    @SuppressWarnings("unchecked")
    Class<? extends TypeHandler> typeHandler = (Class<? extends TypeHandler>) resolveClass(props.getProperty("defaultEnumTypeHandler"));
    configuration.setDefaultEnumTypeHandler(typeHandler);
    //callSettersOnNulls誊册,默認值false
    configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    //useActualParamName,默認值true
    configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
    //returnInstanceForEmptyRow暖璧,默認值false
    configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
    //logPrefix案怯,日志前綴,無默認值
    configuration.setLogPrefix(props.getProperty("logPrefix"));
    //logImpl漆撞,日志實現(xiàn)類殴泰,無默認值
    @SuppressWarnings("unchecked")
    Class<? extends Log> logImpl = (Class<? extends Log>) resolveClass(props.getProperty("logImpl"));
    configuration.setLogImpl(logImpl);
    //configurationFactory,無默認值
    configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}

里面都是將剛才讀取的配置信息放到configuration中浮驳,沒有對應(yīng)值的賦予默認值(缺省值)悍汛。

其他標簽的解析就不具體去說了,基本都是差不多的套路至会。

本文作者:程序猿楊鮑
版權(quán)歸作者所有离咐,轉(zhuǎn)載請注明出處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奉件,隨后出現(xiàn)的幾起案子宵蛀,更是在濱河造成了極大的恐慌,老刑警劉巖县貌,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件术陶,死亡現(xiàn)場離奇詭異,居然都是意外死亡煤痕,警方通過查閱死者的電腦和手機梧宫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摆碉,“玉大人塘匣,你說我怎么就攤上這事∠锏郏” “怎么了忌卤?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長楞泼。 經(jīng)常有香客問我驰徊,道長,這世上最難降的妖魔是什么堕阔? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任辣垒,我火速辦了婚禮,結(jié)果婚禮上印蔬,老公的妹妹穿的比我還像新娘。我一直安慰自己脱衙,他們只是感情好侥猬,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布例驹。 她就那樣靜靜地躺著,像睡著了一般退唠。 火紅的嫁衣襯著肌膚如雪鹃锈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天瞧预,我揣著相機與錄音屎债,去河邊找鬼。 笑死垢油,一個胖子當著我的面吹牛盆驹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滩愁,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼躯喇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了硝枉?” 一聲冷哼從身側(cè)響起廉丽,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妻味,沒想到半個月后正压,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡责球,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年焦履,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棕诵。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡裁良,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出校套,到底是詐尸還是另有隱情价脾,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布笛匙,位于F島的核電站侨把,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妹孙。R本人自食惡果不足惜秋柄,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蠢正。 院中可真熱鬧骇笔,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芦劣,卻和暖如春粗俱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背虚吟。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工寸认, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人串慰。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓偏塞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親模庐。 傳聞我的和親對象是個殘疾皇子烛愧,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容