简述
1.在IOC容器的注册过程中,将mapper->MapperFactoryBean注册到容器的beanDefinitionMap中
2.配置SqlSessionFactoryBean,完成mybatis的Configuration的配置以及生成SqlSessionFactory
3.然后通过MapperFactoryBean(工厂bean)的getObject创建Mapper的代理对象MapperProxy
4.查询时openSession,执行查询
源码分析
SqlSessionFactory如何构建
SqlSessionFactoryBean实现InitializingBean,因此在bean初始化完成后会调用afterPropertiesSet方法
由以下代码可知,SqlSessionFactoryBean完成SqlSessionFactory的构建并且将它作为自己的成员变量
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = this.buildSqlSessionFactory();
}
buildSqlSessionFactory方法解析mybatis的configLocation 和mapperLocations文件
//以下代码为删减后的代码
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
XMLConfigBuilder xmlConfigBuilder = null;
Configuration targetConfiguration;
//配置解析
if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
}
//解析mapper.xml
if (!ObjectUtils.isEmpty(this.mapperLocations)) {
Resource[] var24 = this.mapperLocations;
int var4 = var24.length;
for(int var5 = 0; var5 < var4; ++var5) {
Resource mapperLocation = var24[var5];
if (mapperLocation != null) {
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception var19) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var19);
} finally {
ErrorContext.instance().reset();
}
LOGGER.debug(() -> {
return "Parsed mapper file: '" + mapperLocation + "'";
});
}
}
}
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
mapper的代理
mapper的代理由getBean方法作为入口,由于mapper对应的MapperFactoryBean为factoryBean,所有调用它的getObject方法
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);
}
追踪发现,最终还是调用了mybatis的MapperRegisty的getMapper方法,生成代理对象。最后执行this.factoryBeanObjectCache.put(beanName, object)将生成的代理对象放入容器。
sql执行
mapper被MapperProxy代理,调试发现,最终执行SqlSessionTemplate的selectOne方法
public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.selectOne(statement, parameter);
}
sqlSessionProxy是在SqlSessionTemplate构造时创建的一个动态代理对象,所以调用SqlSessionInterceptor的invoke方法
由代码可知,首先会获取一个sqlSession,然后执行mybatis的语句执行流程,紧接着进行sqlSession的提交或释放
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
Object unwrapped;
try {
Object result = method.invoke(sqlSession, args);
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
unwrapped = result;
} catch (Throwable var11) {
unwrapped = ExceptionUtil.unwrapThrowable(var11);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw (Throwable)unwrapped;
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
return unwrapped;
}
获取session的时候,如果没有开启事务,那么直接调用openSession开启一个新的session,如果是开启事务的情况,那么将当前事务存储在当前的线程变量中,以便事务中其他执行时获取
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
Assert.notNull(executorType, "No ExecutorType specified");
SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
} else {
LOGGER.debug(() -> {
return "Creating a new SqlSession";
});
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
}
对比mybatis
1.session的创建
mybatis中session的创建和sql的执行是分开的,但是spring-mybatis中是在sql的执行调用时,通过代理的方式在sql执行前获取session。因此在不存在事务的情况,spring-mybatis的一级缓存是没有作用的
2.mapper的作用域
mybatis每次获取mapper都会生成它的代理对象,因此mybatis的mapper是session级别的;spring-mybatis在第一次获取后放入factoryBeanObjectCache,以后都是从factoryBeanObjectCache中获取,因此它是全局单例的。