引子
如果你是一个服务端开发者,而你的主要语言又是Java的话,如果还不知道MyBatis和Spring这二大利器,那我只能对你说:出门右转找百度,左转找谷歌!
- MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
- Spring 是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式)轻量级开源框架。
- MyBatis-Spring 帮助你将 MyBatis 代码无缝地整合到 Spring 中。 使用这个类库中的类, Spring 将会加载必要的 MyBatis 工厂类和 session 类。 这个类库也提供一个简单的方式来注入 MyBatis 数据映射器和 SqlSession 到业务层的 bean 中。 而且它也会处理事务, 翻译 MyBatis 的异常到 Spring 的 DataAccessException 异常中。最终,它并 不会依赖于 MyBatis,Spring 或 MyBatis-Spring 来构建应用程序代码。
通过上面各组件官网上的解释我们已经知道各个是干什么用的吧!
SqlSessionFactoryBean
在基本的MyBatis中,SqlSessionFactory
可以使用SqlSessionFactoryBuilder
来创建,而在mybatis-spring中,则使用SqlSessionFactoryBean
来创建。
XML配置方式:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath*:mappers/**/*.xml" />
</bean>
Java代写方式:
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath*:mappers/**/*.xml"));
SqlSessionFactory sessionFactory = factoryBean.getObject();
SqlSessionFactoryBean的类设计如下图:
SqlSessionFactoryBean设计图
注意: SqlSessionFactoryBean实现了Spring的FactoryBean
接口这就说明了由 Spring 最终创建的 bean 不是SqlSessionFactoryBean 本身, 而是工厂类的 getObject()返回的方法的结果 ,即SqlSessionFactory对象。
具体的实现源代码如下:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private Resource configLocation;
private Configuration configuration;
private Resource[] mapperLocations;
private DataSource dataSource;
private TransactionFactory transactionFactory;
private Properties configurationProperties;
private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
private SqlSessionFactory sqlSessionFactory;
//EnvironmentAware requires spring 3.1
private String environment = SqlSessionFactoryBean.class.getSimpleName();
private boolean failFast;
private Interceptor[] plugins;
private TypeHandler<?>[] typeHandlers;
private String typeHandlersPackage;
private Class<?>[] typeAliases;
private String typeAliasesPackage;
private Class<?> typeAliasesSuperType;
//issue #19. No default provider.
private DatabaseIdProvider databaseIdProvider;
private Class<? extends VFS> vfs;
private Cache cache;
private ObjectFactory objectFactory;
private ObjectWrapperFactory objectWrapperFactory;
// 省略getter和setter
// ...
@Override
public void afterPropertiesSet() throws Exception {
// 省略属性的断言判断
// ...
this.sqlSessionFactory = buildSqlSessionFactory();
}
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
Configuration configuration;
// Configuration的构建优先级为:
// 1. configuration属性,
// 2. configLocation,MyBatis的配置文件,通常在为“WEB-INF/mybatis-configuration.xml”
// 3. 如果上面二个属性都没有设置,则使用默认的配置信息
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);
}
}
// 省略部分设置configuration属性代码
// ...
// 这里,如果配置的xxxMapper.xml文件的路径,会循环解析xml文件
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();
}
}
}
}
// 这里根据configuration构建出SqlSessionFactory
return this.sqlSessionFactoryBuilder.build(configuration);
}
// ...
}
从这个类中我们可以看到,buildSqlSessionFactory
干了主要的工作,从Configuration的初始化,到Configuration中各个属性值的设置,以及Mapper的xml文件解析。
属性
- DataSource - SqlSessionFactory有一个单独的必须属性就是JDBC的DataSource.
- mapperLocations - 如果MyBatis映射器XML文件在和映射器类相同的路径下不存在,那么就需要配置这个属性;使用这个配置有两种选择:
- 手动在MyBatis的XML配置文件中使用<mappers>部分来指定类路径;
- 使用SqlSessionFactoryBean的mapperLocations属性;
至此,SqlSessionFactoryBean类的功能基本讲完了,如果你有其他想法和意见可以下在方留言~~
网友评论