核心对象
- SqlSessionFactoryBean: 实现InitializingBean接口,在初始化过程中读取配置文件mybatis-config.xml并创建SqlSessionFactory
- MapperScannerConfigurer: 实现BeanDefinitionRegistryPostProcessor接口,实现自定义的Bean对象注册 - MapperFactoryBean<*Mapper>对象
- SqlSessionTemplate: 持有SqlSessionProxy对象,对SqlSessionProxy对象的操作都会经过SqlSessionInterceptor.invoke()方法,在invoke()内部获取sqlSession进行SQL语句执行
- MapperFactoryBean
对象 : getObject()方法返回Mapper的代理对象,底层实现依赖MapperProxyFactory对象:MapperProxyFactory.newInstance(SqlSessionTemplate);
Spring配置文件
<beans>
<!-- Spring包扫描路径 -->
<context:component-scan base-package="top.kiqi.spring"/>
<bean id="jdbc" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath*:db.properties"/>
</bean>
<!-- c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${dataSource.driver}" />
<property name="jdbcUrl" value="${dataSource.url}" />
<property name="user" value="${dataSource.username}" />
<property name="password" value="${dataSource.password}" />
</bean>
<!-- 在Spring启动时创建 sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:spring-mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:mapping/*iMapper.xml"></property>
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置扫描器,将mybatis的接口实现加入到 IOC容器中 -->
<mybatis-spring:scan base-package="top.kiqi.mybatis.dao" />
<!--开启事务控制-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
SqlSessionFactoryBean
// 注册到IOC容器中,用于获取SqlSessionFactory对象
public class SqlSessionFactoryBean
implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
// (init)生命周期切入点
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
// MS1 : 通过SqlSessionFactoryBean对象的生命周期切入点,实现配置读取和SqlSessionFactory对象创建
this.sqlSessionFactory = buildSqlSessionFactory();
}
// MS : 实现配置文件解析,并返回sqlSessionFactory对象。
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
Configuration targetConfiguration = xmlConfigBuilder.getConfiguration();
xmlConfigBuilder.parse();
xmlMapperBuilder.parse();
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
// IOC容器调用FactoryBean<T>对象的getObject()方法获取真实bean
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
MapperScannerConfigurer
// 用于扫描mybatis mapper接口,并注册到IOC容器中,其BeanDefinition中的class为MapperFactoryBeanClass,通过getObject()获取Mapper代理对象
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
// 通过该后置处理器,可以实现对未实例化的BeanDefinition进行修改
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
// 配置扫描参数
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
scanner.registerFilters();
// MS : 快进到 ClassPathMapperScanner.scan方法,读取到beanDefinitions定义后将class替换为MapperFactoryBean<T>对象
// 最后注册到容器中的为MapperFactoryBean<T>对象,通过getObject方法获得mapper
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
}
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
// 修改BeanDefinition的定义,将class对象替换为mapperFactoryBeanClass。
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
// MapperScannerConfigurer#postProcessBeanDefinitionRegistry()
// definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
// definition.setBeanClass(this.mapperFactoryBeanClass);
}
getMapper()
// IOC容器调用 MapperFactoryBean.getObject() 获取beanname为*Mapper的对象
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
// 实际调用sqlSessionTemplate.sqlSessionFactory.configuration.mapperRegistry.getMapper(type, sqlSession);
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
public SqlSession getSqlSession() {
return this.sqlSessionTemplate;
}
}
// MapperRegistry 中存放了`Type-MapperProxyFactory`的映射,由MapperProxyFactory创建代理对象和invocationHandler对象(MapperProxy)
// 由于传入参数为sqlSessionTemplate,因此由sqlSessionTemplate实现线程安全控制
public class MapperRegistry {
private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
public MapperRegistry(Configuration config) {
this.config = config;
}
public <T> T getMapper(Class<T> type, SqlSession sqlSessionTemplate) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSessionTemplate);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
SqlSessionTemplate
-> mapper代理对象方法 -> SqlSessionTemplate方法 -> sqlSessionProxy方法 -> SqlSessionInterceptor.invoke()
-> SqlSessionUtils.getSqlSession() -> TransactionSynchronizationManager事务资源管理
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
// SqlSessionTemplate持有一个SqlSessionProxy对象,对sqlSessionProxy的操作都会经过SqlSessionInterceptor.invoke()方法
this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class }, new SqlSessionInterceptor());
}
// SqlSessionProxy - InvocationHandler对象
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// MS : 此处获取SqlSession(--- 具体逻辑与Spring的TransactionSynchronizationManager有关,通过ThreadLocal获取当前线程已有sqlSession)
SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator
.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
}
由Spring TransactionSynchronizationManager对象 - 实现SqlSession线程相关
- 从TransactionSynchronizationManager中获取SqlSessionHolder对象(底层为ThreadLocal数据结构,线程相关)
- 如果存在,则返回SqlSessionHolder对象持有的SqlSession
- 如果不存在,则session = sessionFactory.openSession(executorType),包装成SqlSessionHolder并注册
SqlSessionUtils#registerSessionHolder()
// 将session包装成SqlSessionHolder对象
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
// 将SqlSessionHolder对象注册到TransactionSynchronizationManager的ThreadLocal中
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
// 将SqlSessionSynchronization对象注册到TransactionSynchronizationManager的ThreadLocal中,该对象可以实现Spring事务管理前后置代码切入
TransactionSynchronizationManager
.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
- TransactionSynchronizationAdapter对象 - Spring提供的事务管理前后置代码切入点
private static final class SqlSessionSynchronization extends TransactionSynchronizationAdapter{}
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
public TransactionSynchronizationAdapter() {}
public int getOrder() {
return 2147483647;}
public void suspend() {}
public void resume() {}
public void flush() {}
public void beforeCommit(boolean readOnly) {}
public void beforeCompletion() {}
public void afterCommit() {}
public void afterCompletion(int status) {}
}
Spring实现MyBatis事务管理
- SqlSessionFactoryBean在解析配置文件时,会将SpringManagedTransactionFactory配置为Mybatis的事务管理工厂
- sqlSessionFactory.openSession()获取链接时,会与SpringManagedTransactionFactory中创建的SpringManagedTransaction绑定
- Connection conn = springManagedTransaction.getConnection()
- 实际上,Spring通过
DataSourceUtils.getConnection(this.dataSource);
获得链接,如此,链接由Spring进行控制
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
if (conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = fetchConnection(dataSource);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
try {
ConnectionHolder holderToUse = conHolder;
if (conHolder == null) {
holderToUse = new ConnectionHolder(con);
} else {
conHolder.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
} catch (RuntimeException var4) {
releaseConnection(con, dataSource);
throw var4;
}
}
return con;
} else {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection();
}
}