要了解MyBatis的的源碼,咱們能夠看看咱們平時在Spring容器中使用MyBatis的配置文件,找到最基本的入口.java
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:configuration.xml"></property> <property name="mapperLocations" value="classpath:com/sage/mybatis/mapper/*.xml"/> <property name="typeAliasesPackage" value="com.sage.entity" /> </bean>
Spring會調用SqlSessionFactoryBean這個工廠bean的無參構造函數,同時注入dataSource,Mapper文件的路徑,進行sqlSessionFactory的初始化.這裏面的SqlSessionFactoryBean,使用的是mybatis-spring包.spring
咱們來看一下,MyBatis是如何經過XML配置來建立SqlSessionFactory.sql
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) { // 若是傳入了MyBatis Config文件的路徑,初始化xmlConfigBuilder 並得到裏面的配置信息 xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); configuration = xmlConfigBuilder.getConfiguration(); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Property `configuration` or 'configLocation' not specified, using default MyBatis Configuration"); } configuration = new Configuration(); 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); } // 若是在Spring的配置文件中,配置類實體類包的別名typeAliasesPackage if (hasLength(this.typeAliasesPackage)) { String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan : typeAliasPackageArray) { // 不使用MyBatis Config文件裏的實體類包別名配置 configuration.getTypeAliasRegistry().registerAliases(packageToScan, typeAliasesSuperType == null ? Object.class : typeAliasesSuperType); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases"); } } } if (!isEmpty(this.typeAliases)) { for (Class<?> typeAlias : this.typeAliases) { configuration.getTypeAliasRegistry().registerAlias(typeAlias); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Registered type alias: '" + typeAlias + "'"); } } } //若是配置類插件,註冊插件,從這咱們能夠看到,插件類是實現Interceptor, 配置文件裏能夠傳入數組 if (!isEmpty(this.plugins)) { for (Interceptor plugin : this.plugins) { configuration.addInterceptor(plugin); if (LOGGER.isDebugEnabled()) { 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); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers"); } } } if (!isEmpty(this.typeHandlers)) { for (TypeHandler<?> typeHandler : this.typeHandlers) { configuration.getTypeHandlerRegistry().register(typeHandler); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Registered type handler: '" + typeHandler + "'"); } } } //databaseIdProvider 多數據庫支持 在編寫Mapper的時候 指定databaseId //用於多數據源的狀況,我會放到以後的文章來說解如何使用 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); } //若是xmlConfigBuilder存在則開始分析建立Configuration對象 if (xmlConfigBuilder != null) { try { xmlConfigBuilder.parse(); if (LOGGER.isDebugEnabled()) { 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的環境變量信息 configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource)); //若是指定了mapper文件的路徑 if (!isEmpty(this.mapperLocations)) { for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; } try { //將xml的mapper文件進行解析轉換 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(); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'"); } } } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found"); } } //建立SqlSessionFactory return this.sqlSessionFactoryBuilder.build(configuration); }
從上面的代碼咱們能夠簡單的看出,在初始化SqlSessionFactory的時候,會經過工廠Bean對象,並傳入配置參數進行建立的.咱們能夠看到,MyBatis自己並不提供事務的支持,使用的是Spring的事務.同時也和大部分框架,將XML解析爲配置對象,方便使用.數據庫