Spring整合MyBatis(三)sqlSessionFactory建立

來源:互聯網
上載者:User

標籤:ini   樹狀   ali   iter   源碼   array   .config   應該   nes   

摘要: 本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的原始碼。若有描述錯誤之處,歡迎指正。

 

目錄

一、SqlSessionFactoryBean的初始化

二、擷取 SqlSessionFactoryBean 執行個體

 

通過Spring整合MyBatis的樣本,我們感受到了Spring為使用者更加快捷地進行開發所做的努力,開發人員的工作效率由此得到了顯著的提升。但是,相對於使用來說,我們更想知道其背後所隱藏的秘密,Spring整合MyBatis是如何?的呢?通過分析整合樣本中的設定檔,我們可以知道配置的bean其實是成樹狀結構的,而在樹的最頂層是類型為org.mybatis.spring.SqlSessionFactoryBean的bean,它將其他相關bean組裝在了一起,那麼,我們的分析就從此類開始。

通過設定檔我們分析,對於設定檔的讀取解析,Spring應該通過org.mybatis.spring.SqlSessionFactoryBean封裝了MyBatis中的實現。我們進入這個類,首先査看這個類的階層,如所示。

 

根據這個類的階層找出我們感興趣的兩個介面,FactoryBean和InitializingBean:

  • InitializingBean:實現此介面的bean會在初始化時調用其afterPropertiesSet方法來進行bean的邏輯初始化。
  • FactoryBean:一旦某個bean實現此介面,那麼通過getBean方法擷取bean時其實是擷取此類的getObject()返回的執行個體。

我們首先以InitializingBean介面的afterPropertiesSet()方法作為突破點。

一、SqlSessionFactoryBean的初始化

査看org.mybatis.spring.SqlSessionFactoryBean類型的bean在初始化時做了哪些邏輯實現。

@Overridepublic void afterPropertiesSet() throws Exception {    notNull(dataSource, "Property ‘dataSource‘ is required");    notNull(sqlSessionFactoryBuilder, "Property ‘sqlSessionFactoryBuilder‘ is required");    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),            "Property ‘configuration‘ and ‘configLocation‘ can not specified with together");    this.sqlSessionFactory = buildSqlSessionFactory();}

很顯然,此函數主要目的就是對於sqlSessionFactory的初始化,通過之前展示的獨立使用MyBatis的樣本,我們瞭解到SqlSessionFactory是所有MyBatis功能的基礎。

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {    Configuration configuration;    XMLConfigBuilder xmlConfigBuilder = null;    if (this.configuration != null) {        configuration = this.configuration;        if (configuration.getVariables() == null) {            configuration.setVariables(this.configurationProperties);        } else if (this.configurationProperties != null) {            configuration.getVariables().putAll(this.configurationProperties);        }    } else if (this.configLocation != null) {        xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);        configuration = xmlConfigBuilder.getConfiguration();    } else {        LOGGER.debug(() -> "Property ‘configuration‘ or ‘configLocation‘ not specified, using default MyBatis Configuration");        configuration = new Configuration();        if (this.configurationProperties != null) {            configuration.setVariables(this.configurationProperties);        }    }    if (this.objectFactory != null) {        configuration.setObjectFactory(this.objectFactory);    }    if (this.objectWrapperFactory != null) {        configuration.setObjectWrapperFactory(this.objectWrapperFactory);    }    if (this.vfs != null) {        configuration.setVfsImpl(this.vfs);    }    if (hasLength(this.typeAliasesPackage)) {        String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);        for (String packageToScan : typeAliasPackageArray) {            configuration.getTypeAliasRegistry().registerAliases(packageToScan,                    typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);            LOGGER.debug(() -> "Scanned package: ‘" + packageToScan + "‘ for aliases");        }    }    if (!isEmpty(this.typeAliases)) {        for (Class<?> typeAlias : this.typeAliases) {            configuration.getTypeAliasRegistry().registerAlias(typeAlias);            LOGGER.debug(() -> "Registered type alias: ‘" + typeAlias + "‘");        }    }    if (!isEmpty(this.plugins)) {        for (Interceptor plugin : this.plugins) {            configuration.addInterceptor(plugin);            LOGGER.debug(() -> "Registered plugin: ‘" + plugin + "‘");        }    }    if (hasLength(this.typeHandlersPackage)) {        String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);        for (String packageToScan : typeHandlersPackageArray) {            configuration.getTypeHandlerRegistry().register(packageToScan);            LOGGER.debug(() -> "Scanned package: ‘" + packageToScan + "‘ for type handlers");        }    }    if (!isEmpty(this.typeHandlers)) {        for (TypeHandler<?> typeHandler : this.typeHandlers) {            configuration.getTypeHandlerRegistry().register(typeHandler);            LOGGER.debug(() -> "Registered type handler: ‘" + typeHandler + "‘");        }    }    if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls        try {            configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));        } catch (SQLException e) {            throw new NestedIOException("Failed getting a databaseId", e);        }    }    if (this.cache != null) {        configuration.addCache(this.cache);    }    if (xmlConfigBuilder != null) {        try {            xmlConfigBuilder.parse();            LOGGER.debug(() -> "Parsed configuration file: ‘" + this.configLocation + "‘");        } catch (Exception ex) {            throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);        } finally {            ErrorContext.instance().reset();        }    }    if (this.transactionFactory == null) {        this.transactionFactory = new SpringManagedTransactionFactory();    }    configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));    if (!isEmpty(this.mapperLocations)) {        for (Resource mapperLocation : this.mapperLocations) {            if (mapperLocation == null) {                continue;            }            try {                XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),                        configuration, mapperLocation.toString(), configuration.getSqlFragments());                xmlMapperBuilder.parse();            } catch (Exception e) {                throw new NestedIOException("Failed to parse mapping resource: ‘" + mapperLocation + "‘", e);            } finally {                ErrorContext.instance().reset();            }            LOGGER.debug(() -> "Parsed mapper file: ‘" + mapperLocation + "‘");        }    } else {        LOGGER.debug(() -> "Property ‘mapperLocations‘ was not specified or no matching resources found");    }    return this.sqlSessionFactoryBuilder.build(configuration);}

從函數中可以看到,儘管我們還是習慣於將MyBatis的配置與Spring的配置獨立開來,但是,這並不代表Spring中的配置不支援直接配置。也就是說,在上面提供的樣本中,你完全可以取消配置中的configLocation,而把其中的屬性直接寫在SqlSessionFactoryBean中。

從這個函數中可以得知,設定檔還可以支援其他多種屬性的配置,如configLocation、objectFactory、objectWrapperFactory、typeAliasesPackage、typeAliases、typeHandlersPackage、plugins、typeHandlers、transactionFactory、databaseIdProvider、mapperLocations。

其實,如果只按照常用的配置,那麼我們只需要在函數最開始按照如下方式處理configuration:

xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);configuration = xmlConfigBuilder.getConfiguration();

根據configLocation構造XMLConfigBuilder並進行解析,但是,為了體現Spring更強大的相容性,Spring還整合了MyBatis中其他屬性的注入,並通過執行個體configuration來承載每一步所擷取的資訊並最終使用sqlSessionFactoryBuilder執行個體根據解析到的configuration建立SqlSessionFactory執行個體。

二、擷取 SqlSessionFactoryBean 執行個體

由於SqlSessionFactoryBean實現了FactoryBean介面,所以當通過getBean方法擷取對應執行個體時,其實是擷取該類的getObject()函數返回的執行個體,也就是擷取初始化後的sqlSessionFactory屬性。

@Overridepublic SqlSessionFactory getObject() throws Exception {    if (this.sqlSessionFactory == null) {        afterPropertiesSet();    }    return this.sqlSessionFactory;}

 

Spring整合MyBatis(三)sqlSessionFactory建立

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.