mybatis-spring-1.3.2.jar 中有5个类
org.mybatis.spring.mapper.MapperScannerConfigurer
org.mybatis.spring.mapper.ClassPathMapperScanner
org.mybatis.spring.mapper.MapperFactoryBean
org.mybatis.spring.SqlSessionTemplate
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor
我们看下MapperScannerConfigurer的定义
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
private String basePackage;
private boolean addToConfig = true;
private SqlSessionFactory sqlSessionFactory;
private SqlSessionTemplate sqlSessionTemplate;
private String sqlSessionFactoryBeanName;
private String sqlSessionTemplateBeanName;
private Class<? extends Annotation> annotationClass;
private Class<?> markerInterface;
private ApplicationContext applicationContext;
private String beanName;
private boolean processPropertyPlaceHolders;
private BeanNameGenerator nameGenerator;
// ...省略了若干方法的定义
//...
@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.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
}
实现了BeanDefinitionRegistryPostProcessor接口,说明这个类在Spring容器初始化的过程中会被执行,在bean的定义被注册后,会进入这个执行过程。
在方法postProcessBeanDefinitionRegistry
创建了一个ClassPathMapperScanner 。 而ClassPathMapperScanner会为每个用户定义的Mapper interface注册一个Bean,而且这个Bean是从MapperFactoryBean#getObject来的。
虽然MapperFactoryBean本身是单例模式的(inSingleton() return true). 假设用户定义来两个Mapper interface。 比如StudentMapper和SecondStudentMapper两个interface。
则MapperScannerConfigurer会添加两个BeanDefinition,每个对应一个MapperFactoryBean.
而MapperFactoryBean实现了FactoryBean接口,所以会分别new一个MapperFactoryBean,
并通过MapperFactoryBean.geObject() 返回一个对象。比如StudentMapper对象和SecondStudentMapper对象。
MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean
创建的过程中,会设置SqlSessionDaoSupport中的一些字段。比如(SqlSessionTemplate等)
MapperFactoryBean.getObject()
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
// --> SqlSessionTemplate.java
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
//调用链
SqlSessionTemplate#getMapper(Class<T> type))
Configuration#mapperRegistry.getMapper(type, sqlSession);
MapperRegistry#getMapper(Class<T> type, SqlSession sqlSession)
MapperProxyFactory#newInstance()
产生一些代理类的对象。 类型为StudentMapper。
对应的InvocationHandler是MapperProxy.java
Proxy.
至此StudentMapper的代理对象就已经生成了。并以单例到模式注册到spirng容器
这个实现由下面两个类来完成
org.mybatis.spring.SqlSessionTemplate
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor
还是使用的JDK动态代理,这个就很简单。直接贴关键代码
public class SqlSessionTemplate implements SqlSession, DisposableBean {
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;
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
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);
}
}
}
}
sqlSessionProxy是 SqlSessionInterceptor关联的一个动态代理对象.
sqlSessionProxy的增删改查,都会通过代理对象,这样都会进入SqlSessionInterceptor#invoke
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.sqlSessionProxy.<E> selectList(statement, parameter);
}
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
...
}
sqlSession会真正根据sql语句去操作数据库并返回结果。
SqlSession.java
package org.apache.ibatis.session;
import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.BatchResult;
public interface SqlSession extends Closeable {
<T> T selectOne(String var1);
<T> T selectOne(String var1, Object var2);
<E> List<E> selectList(String var1);
<E> List<E> selectList(String var1, Object var2);
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<K, V> Map<K, V> selectMap(String var1, String var2);
...
}