Mybatis-Spring:SqlSessionFactoryBean

環(huán)境:mybatis-spring 2.0.3

可以通過如下方式向在Spring中集成Mybatis,通過向Spring注冊SqlSessionFactoryBean@MapperScan啟用Mybatis的功能

@Configuration
@MapperScan("com.holybell.mybatis.mapper") // Mapper接口掃描路徑
public class Config {
    /**
     * 通過SqlSessionFactoryBean獲得SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());
        return factoryBean.getObject();
    }

    @Bean
    public DataSource dataSource() {
        // ... 省略創(chuàng)建一個DataSource
    }
}

Mybatis利用Spring提供的BeanFactory接口球恤,實現(xiàn)了SqlSessionFactoryBean辜昵,簡單來說它就是一個構(gòu)建SqlSessionFactory的工廠類,雖然注冊的是SqlSessionFactoryBean咽斧,但是它生產(chǎn)的對象也會注冊到Spring容器中

public class SqlSessionFactoryBean 
        implements FactoryBean<SqlSessionFactory>, InitializingBean, 
                   ApplicationListener<ApplicationEvent> {

    // spring的資源加載器
    private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER 
                                                    = new PathMatchingResourcePatternResolver();
    // spring的類注解解析器
    private static final MetadataReaderFactory METADATA_READER_FACTORY 
                                                    = new CachingMetadataReaderFactory();

    private SqlSessionFactory sqlSessionFactory;

    /**
     * FactoryBean向Spring容器注冊之后堪置,
     * Spring會回調(diào)這個方法獲得它生產(chǎn)的bean
     */
    public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            afterPropertiesSet();    
        }
        return this.sqlSessionFactory;
    }
    /**
     * Spring會在bean初始化完成之后回調(diào)這個方法
     */
    public void afterPropertiesSet() throws Exception {
        // 省略Assert校驗...
        this.sqlSessionFactory = buildSqlSessionFactory();
    }
    /**
     * 構(gòu)造Mybatis的SqlSessionFactory
     */
    protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
    
       final Configuration targetConfiguration;

        // 省略其他屬性的裝配

        // 掃描路徑躬存,向mybatis注冊TypeHandler
        if (hasLength(this.typeHandlersPackage)) {
            scanClasses(this.typeHandlersPackage, 
                    TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
                    .filter(clazz -> !clazz.isInterface())
                    .filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
                    .forEach(targetConfiguration.getTypeHandlerRegistry()::register);
        }

        // 如果注冊SqlSessionFactoryBean的時候配置了Mapper文件地址
        // 那么就會去解析Mapper文件,生成Configruation中的各種配置信息舀锨,如MapperStatement
        for (Resource mapperLocation : this.mapperLocations) {
            if (mapperLocation == null) {
                continue;
            }

            try {
                // 這里就和不集成Spring的Mybatis操作一樣
                // 解析Mapper文件的配置岭洲,生產(chǎn)MappedStatement等信息
                XMLMapperBuilder xmlMapperBuilder 
                        = new XMLMapperBuilder(mapperLocation.getInputStream(),
                                configuration, mapperLocation.toString(), 
                                configuration.getSqlFragments());
                xmlMapperBuilder.parse();
            } catch (Exception e) {
                // ...省略異常
            } finally {
              ErrorContext.instance().reset();
            }
        }
        // ...
        return this.sqlSessionFactoryBuilder.build(configuration);
    }
    /**
     * 從指定的路徑packagePatterns加載指定assignableType注解的類
     */
    private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType)
          throws IOException {

        Set<Class<?>> classes = new HashSet<>();
        String[] packagePatternArray = tokenizeToStringArray(packagePatterns,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        for (String packagePattern : packagePatternArray) {
            // 加載類資源,每個Resource對象表示一個被加載的文件資源坎匿,此處為class文件
            Resource[] resources = RESOURCE_PATTERN_RESOLVER
                    .getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                            + ClassUtils.convertClassNameToResourcePath(packagePattern) 
                            + "/**/*.class");
            // 遍歷每個加載到的Class文件盾剩,解析注解信息
            for (Resource resource : resources) {
                try {
                    // 解析類的注解信息
                    ClassMetadata classMetadata = METADATA_READER_FACTORY
                            .getMetadataReader(resource).getClassMetadata();
                    Class<?> clazz = Resources.classForName(classMetadata.getClassName());
                    if (assignableType == null || assignableType.isAssignableFrom(clazz)) {
                        // 符合條件的類加入集合返回
                        classes.add(clazz);
                    }
                } catch (Throwable e) {
                    // ... 省略異常日志
                }
            }
        }
        return classes;
    }
}

簡而言之,Mybatis借助SqlSessionFactoryBean完成了在不集成Spring的情況下SqlSessionFactory的創(chuàng)建替蔬,同時可以借助這個類裝配Interceptor告私、TypeHandler等組件

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市承桥,隨后出現(xiàn)的幾起案子驻粟,更是在濱河造成了極大的恐慌,老刑警劉巖凶异,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜀撑,死亡現(xiàn)場離奇詭異,居然都是意外死亡剩彬,警方通過查閱死者的電腦和手機酷麦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來襟衰,“玉大人贴铜,你說我怎么就攤上這事∑偕梗” “怎么了绍坝?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長苔悦。 經(jīng)常有香客問我轩褐,道長,這世上最難降的妖魔是什么玖详? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任把介,我火速辦了婚禮,結(jié)果婚禮上蟋座,老公的妹妹穿的比我還像新娘拗踢。我一直安慰自己,他們只是感情好向臀,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布巢墅。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪君纫。 梳的紋絲不亂的頭發(fā)上驯遇,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音蓄髓,去河邊找鬼叉庐。 笑死,一個胖子當(dāng)著我的面吹牛会喝,可吹牛的內(nèi)容都是我干的陡叠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼好乐,長吁一口氣:“原來是場噩夢啊……” “哼匾竿!你這毒婦竟也來了瓦宜?” 一聲冷哼從身側(cè)響起蔚万,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎临庇,沒想到半個月后反璃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡假夺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年淮蜈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片已卷。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡梧田,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侧蘸,到底是詐尸還是另有隱情裁眯,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布讳癌,位于F島的核電站穿稳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏晌坤。R本人自食惡果不足惜逢艘,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骤菠。 院中可真熱鬧它改,春花似錦、人聲如沸商乎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爬泥,卻和暖如春柬讨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袍啡。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工踩官, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人境输。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓蔗牡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嗅剖。 傳聞我的和親對象是個殘疾皇子辩越,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353