Springboot Mybatis 打包jar掃描bean與mapper問題研究與解決

SpringBootLean 是對springboot學(xué)習(xí)與研究項(xiàng)目竹捉,是根據(jù)實(shí)際項(xiàng)目的形式對進(jìn)行配置與處理,歡迎star與fork。
[oschina 地址]
http://git.oschina.net/cmlbeliever/SpringBootLearning
[github 地址]
https://github.com/cmlbeliever/SpringBootLearning

最近在項(xiàng)目中集成以全注解的方式Mybatis簸喂,配置了自動(dòng)bean包與mapper所在包

db.mybatis.mapperLocations=classpath*:com/cml/springboot/sample/db/resource/*
db.mybatis.typeAliasesPackage=com.cml.springboot.sample.bean
db.mybatis.typeHandlerPackage=com.cml.springboot.framework.mybatis.typehandler

這些配置直接在ide上運(yùn)行都是ok的毙死,但是經(jīng)過打包成jar包后,就一直報(bào)錯(cuò)提示找打不到對應(yīng)的bean或者對應(yīng)的mapper喻鳄。主要錯(cuò)誤如下:

 Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'logbean'.  Cause: java.lang.ClassNotFoundException: Cannot find class: logbean
 
***************************
APPLICATION FAILED TO START
***************************

Description:

Field logMapper in com.cml.springboot.sample.service.impl.LogServiceImpl required a bean of type 'com.cml.springboot.sample.db.LogMapper' that could not be found.


Action:

Consider defining a bean of type 'com.cml.springboot.sample.db.LogMapper' in your configuration.

針對以上問題扼倘,在新開的分支deploy_jar_bugfind上進(jìn)行研究,找到了一個(gè)臨時(shí)解決辦法除呵,就是配置mybat-configuration.xml將對應(yīng)的bean都配置到xml上再菊。

<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
    <typeAliases>
        <typeAlias type="com.cml.springboot.sample.bean.LogBean" alias="logbean"/>
        <typeAlias type="com.cml.springboot.sample.bean.User" alias="user"/>
    </typeAliases>
    <typeHandlers>
        <typeHandler javaType="org.joda.time.DateTime"
            handler="com.cml.springboot.framework.mybatis.typehandler.JodaDateTimeTypeHandler" />
        <typeHandler javaType="org.joda.time.LocalTime"
            handler="com.cml.springboot.framework.mybatis.typehandler.JodaLocalTimeTypeHandler" />
    </typeHandlers>
</configuration>

但是這個(gè)僅僅適合小項(xiàng)目并且bean少的情況,假如在打項(xiàng)目上颜曾,可能有幾十上百的bean纠拔,都要一一配置豈不是累死人了,而且容易出bug泛豪。

于是繼續(xù)研究稠诲,首先自定義DefaultSqlSessionFactoryBean取代默認(rèn)的SqlSessionFactoryBean,并且在buildSqlSessionFactory()方法上對bean掃描的配置進(jìn)行一步步log拆分,主要代碼如下:

if (hasLength(this.typeAliasesPackage)) {
            String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            for (String packageToScan : typeAliasPackageArray) {

                logger.debug("##################################################################################");
                List<String> children = VFS.getInstance().list(packageToScan.replace(".", "/"));
                logger.debug("findclass:" + children);
                logger.debug("##################################################################################");

                logger.debug("DefaultSqlSessionFactoryBean.buildSqlSessionFactory.registerAliases:" + packageToScan);

                ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
                resolverUtil.find(new ResolverUtil.IsA(Object.class), packageToScan);
                Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();

                logger.debug(
                        "DefaultSqlSessionFactoryBean.buildSqlSessionFactory.typeAliasesPackage.scanClass:" + typeSet);

                for (Class<?> type : typeSet) {
                    if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
                        String alias = type.getSimpleName();
                        String key = alias.toLowerCase(Locale.ENGLISH);
                        logger.debug(
                                "DefaultSqlSessionFactoryBean.buildSqlSessionFactory.typeAliasesPackage.scan:" + key);

                    }
                }

                configuration.getTypeAliasRegistry().registerAliases(packageToScan,
                        typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Scanned package: '" + packageToScan + "' for aliases");
                }
            }
        }

發(fā)現(xiàn)在ide上運(yùn)行的時(shí)候是可以掃描到指定的bean诡曙,但是在jar上就掃描不到了臀叙。主要問題找到了,就是對代碼的掃描問題,原本想自定義configuration的价卤,但是發(fā)現(xiàn)好多類都是依賴configuration這個(gè)類匹耕,于是便放棄這個(gè)想法,轉(zhuǎn)而研究掃描不到bean的問題荠雕。

繼續(xù)研究源碼稳其,得知bean的掃描是通過ResolverUtil這個(gè)類進(jìn)行的,并且ResolverUtil掃描是通過VFS進(jìn)行掃描的炸卑,主要代碼:

public ResolverUtil<T> find(Test test, String packageName) {
    String path = getPackagePath(packageName);

    try {
      List<String> children = VFS.getInstance().list(path);
      for (String child : children) {
        if (child.endsWith(".class"))
          addIfMatching(test, child);
      }
    } catch (IOException ioe) {
      log.error("Could not read package: " + packageName, ioe);
    }

    return this;
  }

結(jié)合log上的信息既鞠,工程上默認(rèn)使用的是Mybatis的DefaultVFS進(jìn)行掃描。查看這個(gè)類代碼后也沒發(fā)現(xiàn)什么問題盖文,轉(zhuǎn)而求救于百度與谷歌嘱蛋,經(jīng)過多方搜索,找到了Mybatis官網(wǎng)issue (地址:https://github.com/mybatis/mybatis-3/issues/325)這里有對這些問題進(jìn)行說明五续。根據(jù)issue的描述與各大神的回答洒敏,定位到了問題是DefaultVFS在獲取jar上的class問題。

在mybat/spring-boot-starter工程上找到了SpringBootVFS疙驾,這個(gè)類重寫了class掃描功能凶伙,通過spring進(jìn)行掃描。

于是將SpringBootVFS拷貝到工程上它碎,并且添加到VFS實(shí)現(xiàn)上去函荣,代碼如下:

@Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(DataSource datasource, MybatisConfigurationProperties properties)
            throws Exception {

        log.info("*************************sqlSessionFactory:begin***********************" + properties);

        VFS.addImplClass(SpringBootVFS.class);

        DefaultSqlSessionFactoryBean sessionFactory = new DefaultSqlSessionFactoryBean();
        sessionFactory.setDataSource(datasource);
        sessionFactory.setTypeAliasesPackage(properties.typeAliasesPackage);
        sessionFactory.setTypeHandlersPackage(properties.typeHandlerPackage);

        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactory.setMapperLocations(resolver.getResources(properties.mapperLocations));

//      sessionFactory
//              .setConfigLocation(new PathMatchingResourcePatternResolver().getResource(properties.configLocation));

        SqlSessionFactory resultSessionFactory = sessionFactory.getObject();

        log.info("===typealias==>" + resultSessionFactory.getConfiguration().getTypeAliasRegistry().getTypeAliases());

        log.info("*************************sqlSessionFactory:successs:" + resultSessionFactory
                + "***********************" + properties);

        return resultSessionFactory;

    }

這樣mybaits打包jar后掃描問題完美解決显押。


綜上,解決SpringBoot Mybatis打包jar后問題處理完畢傻挂,已提交到git項(xiàng)目master分支和deploy_jar_bugfind
http://git.oschina.net/cmlbeliever/SpringBootLearning

解決辦法:

  1. 通過mybatis-configuration.xml進(jìn)行配置
  2. 通過SpringBootVFS進(jìn)行自動(dòng)掃描配置(推薦)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乘碑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子金拒,更是在濱河造成了極大的恐慌兽肤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绪抛,死亡現(xiàn)場離奇詭異轿衔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)睦疫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門害驹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蛤育,你說我怎么就攤上這事宛官。” “怎么了瓦糕?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵底洗,是天一觀的道長。 經(jīng)常有香客問我咕娄,道長亥揖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任圣勒,我火速辦了婚禮费变,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘圣贸。我一直安慰自己挚歧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布吁峻。 她就那樣靜靜地躺著滑负,像睡著了一般。 火紅的嫁衣襯著肌膚如雪用含。 梳的紋絲不亂的頭發(fā)上矮慕,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機(jī)與錄音啄骇,去河邊找鬼痴鳄。 笑死鞋诗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的推励。 我是一名探鬼主播点额,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涎劈,長吁一口氣:“原來是場噩夢啊……” “哼疚脐!你這毒婦竟也來了忙灼?” 一聲冷哼從身側(cè)響起杭攻,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤趟妥,失蹤者是張志新(化名)和其女友劉穎猫态,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體披摄,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亲雪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疚膊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片义辕。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寓盗,靈堂內(nèi)的尸體忽然破棺而出灌砖,到底是詐尸還是另有隱情,我是刑警寧澤傀蚌,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布基显,位于F島的核電站,受9級特大地震影響善炫,放射性物質(zhì)發(fā)生泄漏撩幽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一箩艺、第九天 我趴在偏房一處隱蔽的房頂上張望窜醉。 院中可真熱鬧,春花似錦艺谆、人聲如沸酱虎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽读串。三九已至,卻和暖如春撒妈,著一層夾襖步出監(jiān)牢的瞬間恢暖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工狰右, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杰捂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓棋蚌,卻偏偏與公主長得像嫁佳,于是被迫代替她去往敵國和親挨队。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蒿往,服務(wù)發(fā)現(xiàn)盛垦,斷路器,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,806評論 6 342
  • 1. 簡介 1.1 什么是 MyBatis 瓤漏? MyBatis 是支持定制化 SQL腾夯、存儲(chǔ)過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,517評論 0 4
  • 時(shí)刻保持自己的獨(dú)立與清醒蝶俱,不要總是低頭跟著別人前行,當(dāng)別人到站的時(shí)候你才會(huì)發(fā)現(xiàn)自己忽然之間就失去了方向——你與別人...
    高手如林閱讀 837評論 0 3
  • 無論世界多么嫌棄你饥漫,你都不能嫌棄你自己榨呆。 寫下這段話的我,此時(shí)應(yīng)該是經(jīng)過陣陣焦慮庸队,艱難思索后的結(jié)果积蜻。 ...
    獨(dú)聲閱讀 179評論 0 0