0.从配置文件开始
要了解MyBatis的的源码,我们可以看看我们平时在Spring容器中使用MyBatis的配置文件,找到最基本的入口.
<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包.
1.创建SqlSessionFactory
我们来看一下,MyBatis是如何通过XML配置来创建SqlSessionFactory.
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解析为配置对象,方便使用.
来源:oschina
链接:https://my.oschina.net/u/267473/blog/734336