构造方法
SqlSessionTemplate
的构造方法源代码如下,其他构造方法,都是在此构造方法上进行的重载。
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
Assert.notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
}
sqlSessionProxy
从构造方法中能够看出sqlSessionProxy
是SqlSessionTemplate
执行CRUD操作时的实际执行者。所以重点解析下sqlSessionProxy
的实例化过程。不难看出,sqlSessionProxy
实例化使用了java的动态代理设计模式。传入的参数如下:
-
ClassLoader
是SqlSessionFactory
; - 接口是
SqlSession
; - 调用处理程序是
SqlSessionTemplate
的内部类SqlSessionInterceptor
。
接下来看看SqlSessionInterceptor都做了什么。
SqlSessionInterceptor
private class SqlSessionInterceptor implements InvocationHandler {
private SqlSessionInterceptor() {
}
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) {
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw (Throwable)unwrapped;
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
return unwrapped;
}
}
SqlSessionInterceptor
的构造方法并没有任何参数,即没有指明SqlSession
的实际实现类。这是因为SqlSession
的实际实现类在invoke()
中进行了实例化。即SqlSessionUtils
的getSqlSession()
方法参与生成SqlSession
的实际实现类。
SqlSessionUtils getSqlSession
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);
if (holder != null && holder.isSynchronizedWithTransaction()) {
if (holder.getExecutorType() != executorType) {
throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
} else {
...
return holder.getSqlSession();
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Creating a new SqlSession");
}
SqlSession session = sessionFactory.openSession(executorType);
...
return session;
}
}
getSqlSession
方法分为两部分。
- 判断
SqlSessionHolder
在内存中是否存在,如果存在则直接从内存中取出,通过sqlSessionholder.getSqlSession()
获取SqlSession
的实际实现类。 - 如果不存在,则先创建
SqlSession
,然后再创建SqlSessionHolder
,最后放入内存方便下次直接使用。
下面我们看看是如何生成SqlSession
的。
SqlSession session = sessionFactory.openSession(executorType);
在通过sessionFactory
创建SqlSession
时。要搞清楚sessionFactory
是在application.xml
配置Mybatis
时传入的。即:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
需要注意的是SqlSessionFactoryBean
实现了Spring
的FactoryBean
接口。这意味着由Spring
最终创建的 bean并不是SqlSessionFactoryBean
本身,而是工厂类(SqlSessionFactoryBean
)的getObject()
方法的返回结果。这种情况下,Spring 将会在应用启动时为你创建SqlSessionFactory
并使用sqlSessionFactory
这个名字存储起来。关于FactoryBean
这里不再详细解释。
查看SqlSessionFactoryBean
的getObject()
方法,然后顺着内部方法一层一层查看。最终发现发现返回的SqlSessionFactory
其实是DefaultSqlSessionFactory
类。路径:afterPropertiesSet
方法 -->buildSqlSessionFactory
方法 --> build()
方法。代码路径如下:
SqlSessionFactoryBean
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
this.afterPropertiesSet();
}
return this.sqlSessionFactory;
}
afterPropertiesSet
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
this.sqlSessionFactory = this.buildSqlSessionFactory();
}
buildSqlSessionFactory
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
XMLConfigBuilder xmlConfigBuilder = null;
Configuration configuration;
...
...
return this.sqlSessionFactoryBuilder.build(configuration);
}
SqlSessionFactoryBuilder
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
既然传入的sessionFactory
参数是DefaultSqlSessionFactory
,那我们就可以查看DefaultSqlSessionFactory
的openSession
方法了。即sqlSessionProxy
是DefaultSqlSession
实例。
DefaultSqlSessionFactory
public SqlSession openSession(ExecutorType execType) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, false);
}
...
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
...
var8 = new DefaultSqlSession(this.configuration, executor);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
总结
SqlSessionTemplate
的实例化过程主要利用了java的动态代理设计模式和FactoryBean<T>自定义工厂这两个知识点。
-
SqlSessionTemplate
是代理类; -
SqlSession
是接口; -
DefaultSqlSession
是实际实现类;
网友评论