- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
9.3.1 sqlSessionFactory 创建
通过配置文件我们分析,对于配置文件的读取解析,Spring 应该通过 org.mybatis.Spring. SqlSessionFactoryBean 封装了 MyBatis 中的实现。我们进入这个类,首先查看这个类的层次结构,如图 9-2 所示。根据这个类的层次结构找出我们感兴趣的两个接口, FactoryBean 和 InitializingBean。

图 9-2 SqlSessionFactoryBean 类的层次结构图
InitializingBean:实现此接口的 bean 会在初始化时调用其 afterPropertiesSet 方法来进行 bean 的逻辑初始化。
FactoryBean:一旦某个 bean 实现次接口,那么通过 getBean 方法获取 bean 时其实是获取此类的 getObject() 返回的实例。
我们首先以 InitializingBean 接口的 afterPropertiesSet() 方法作为突破点。
1.SqlSessionFactoryBean 的初始化
查看 org.mybatis.Spring.SqlSessionFactoryBean 类型的 bean 在初始化时做了哪些逻辑实现。
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
this.sqlSessionFactory = buildSqlSessionFactory();
}
很显然,此函数主要目的就是对于 sqlSessionFactory 的初始化,通过之前展示的独立使用 MyBatis 的示例,我们了解到 SqlSessionFactory 是所有 MyBatis 功能的基础。
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
Configuration configuration;
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null,
this.configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Property '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 (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);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Scanned package: '" + packageToScan + "' for aliases");
}
}
}
if (!isEmpty(this.typeAliases)) {
for (Class<?> typeAlias : this.typeAliases) {
configuration.getTypeAliasRegistry().registerAlias(typeAlias);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Registered type alias: '" + typeAlias + "'");
}
}
}
if (!isEmpty(this.plugins)) {
for (Interceptor plugin : this.plugins) {
configuration.addInterceptor(plugin);
if (this.logger.isDebugEnabled()) {
this.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 (this.logger.isDebugEnabled()) {
this.logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
}
}
}
if (!isEmpty(this.typeHandlers)) {
for (TypeHandler<?> typeHandler : this.typeHandlers) {
configuration.getTypeHandlerRegistry().register(typeHandler);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Registered type handler: '" + typeHandler + "'");
}
}
}
if (xmlConfigBuilder != null) {
try {
xmlConfigBuilder.parse();
if (this.logger.isDebugEnabled()) {
this.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();
}
Environment environment = new Environment(this.environment, this.transactionFactory,
this.dataSource);
configuration.setEnvironment(environment);
if (this.databaseIdProvider != null) {
try {
configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId (this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}
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) {
+ "'", e);
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation
} finally {
ErrorContext.instance().reset();
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Parsed mapper file: '" + mapperLocation + "'");
}
}
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Property 'mapperLocations' was not specified or no matching
resources found");
}
}
return this.sqlSessionFactoryBuilder.build(configuration);
}
从函数中可以看到,尽管我们还是习惯于将 MyBatis 的配置与 Spring 的配置独立出来,但是,这并不代表 Spring 中的配置不支持直接配置。也就是说,在上面提供的示例中,你完全可以取消配置中的 configLocation 属性,而把其中的属性直接写在 SqlSessionFactoryBean 中。
<bean id="sqlSessionFactory" class="org.mybatis.Spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:test/mybatis/MyBatis- Configuration.
xml"></property>
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="aaaaa"/>
... ...
</bean>
从这个函数中可以得知,配置文件还可以支持其他多种属性的配置,如 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 实例。
2.获取 SqlSessionFactoryBean 实例
由于 SqlSessionFactoryBean 实现了 FactoryBean 接口,所以当通过 getBean 方法获取对应实例时,其实是获取该类的 getObject() 函数返回的实例,也就是获取初始化后的 sqlSession Factory 属性。
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论