引子
如果你是一個服務(wù)端開發(fā)者襟诸,而你的主要語言又是Java的話瓦堵,如果還不知道MyBatis和Spring這二大利器,那我只能對你說:出門右轉(zhuǎn)找百度歌亲,左轉(zhuǎn)找谷歌菇用!
- MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL应结、存儲過程以及高級映射刨疼。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息鹅龄,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數(shù)據(jù)庫中的記錄揩慕。
- Spring 是一個開放源代碼的設(shè)計層面框架,它解決的是業(yè)務(wù)邏輯層和其他各層的松耦合問題扮休,因此它將面向接口的編程思想貫穿整個系統(tǒng)應(yīng)用迎卤。Spring是于2003 年興起的一個輕量級的Java 開發(fā)框架,由Rod Johnson創(chuàng)建玷坠。簡單來說蜗搔,Spring是一個分層的JavaSE/EE full-stack(一站式)輕量級開源框架劲藐。
- MyBatis-Spring 幫助你將 MyBatis 代碼無縫地整合到 Spring 中。 使用這個類庫中的類, Spring 將會加載必要的 MyBatis 工廠類和 session 類樟凄。 這個類庫也提供一個簡單的方式來注入 MyBatis 數(shù)據(jù)映射器和 SqlSession 到業(yè)務(wù)層的 bean 中聘芜。 而且它也會處理事務(wù), 翻譯 MyBatis 的異常到 Spring 的 DataAccessException 異常中。最終,它并 不會依賴于 MyBatis,Spring 或 MyBatis-Spring 來構(gòu)建應(yīng)用程序代碼缝龄。
通過上面各組件官網(wǎng)上的解釋我們已經(jīng)知道各個是干什么用的吧汰现!
SqlSessionFactoryBean
在基本的MyBatis中,SqlSessionFactory
可以使用SqlSessionFactoryBuilder
來創(chuàng)建叔壤,而在mybatis-spring中瞎饲,則使用SqlSessionFactoryBean
來創(chuàng)建。
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的類設(shè)計如下圖:
SqlSessionFactoryBean設(shè)計圖
注意: SqlSessionFactoryBean實現(xiàn)了Spring的FactoryBean
接口這就說明了由 Spring 最終創(chuàng)建的 bean 不是SqlSessionFactoryBean 本身, 而是工廠類的 getObject()返回的方法的結(jié)果 炼绘,即SqlSessionFactory對象嗅战。
具體的實現(xiàn)源代碼如下:
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的構(gòu)建優(yōu)先級為:
// 1. configuration屬性,
// 2. configLocation俺亮,MyBatis的配置文件驮捍,通常在為“WEB-INF/mybatis-configuration.xml”
// 3. 如果上面二個屬性都沒有設(shè)置,則使用默認(rèn)的配置信息
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);
}
}
// 省略部分設(shè)置configuration屬性代碼
// ...
// 這里脚曾,如果配置的xxxMapper.xml文件的路徑厌漂,會循環(huán)解析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();
}
}
}
}
// 這里根據(jù)configuration構(gòu)建出SqlSessionFactory
return this.sqlSessionFactoryBuilder.build(configuration);
}
// ...
}
從這個類中我們可以看到,buildSqlSessionFactory
干了主要的工作斟珊,從Configuration的初始化苇倡,到Configuration中各個屬性值的設(shè)置,以及Mapper的xml文件解析囤踩。
屬性
- DataSource - SqlSessionFactory有一個單獨(dú)的必須屬性就是JDBC的DataSource.
- mapperLocations - 如果MyBatis映射器XML文件在和映射器類相同的路徑下不存在旨椒,那么就需要配置這個屬性;使用這個配置有兩種選擇:
- 手動在MyBatis的XML配置文件中使用<mappers>部分來指定類路徑堵漱;
- 使用SqlSessionFactoryBean的mapperLocations屬性综慎;
至此,SqlSessionFactoryBean類的功能基本講完了勤庐,如果你有其他想法和意見可以下在方留言~~