mybatis源码分析
首先简单回顾一下mybatis的用法。mybatis最主要的就是mybatis配置文件、SqlSessionFactory 和SqlSession 。
private void test(){
//mybatis配置文件
String resource = "mybatisConfig.xml";
InputStream inputStream;
SqlSessionFactory sqlSessionFactory;
SqlSession sqlSession = null;
try {
//根据配置文件获取输入流
inputStream = Resources.getResourceAsStream(resource);
//根据配置文件输入流创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//根据会话工厂得到sqlsession
sqlSession = sqlSessionFactory.openSession();
//通过id=1查询用户信息
//方式一:直接通过sqlsession的select方法查询
User user = sqlSession.selectOne("com.learn.mybatis.mapper.UserMapper.findUserById",1);
//方式二:通过mapper接口的方法查询(推荐使用第二种,该方式底层实际上依然是调用sqlsession的方法)
//UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//User user = userMapper.findUserById(1);
//提交事务,增删改需要commit,查询无需commit
//sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭会话
if (sqlSession != null){
sqlSession.close();
}
}
}
1、创建SqlSessionFactory
调用SqlSessionFactoryBuilder类的build方法:
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//通过XMLConfigBuilder解析配置文件,解析的配置信息都会封装为一个Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//创建SqlSessionFactory,实际是DefaultSqlSessionFactory。parser.parse()得到的是Configuration对象
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
2、获取SqlSession
调用SqlSessionFactory接口的openSession方法获取SqlSession,实际是调用具体实现类DefaultSqlSessionFactory的openSession方法。
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
//通过Confuguration对象获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//表面是通过SqlSession执行SQL语句,实际底层是通过Executor执行的
Executor executor = this.configuration.newExecutor(tx, execType);
//创建DefaultSqlSession,得到SqlSession
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
SqlSession接口中的方法:
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);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
<T> Cursor<T> selectCursor(String var1);
<T> Cursor<T> selectCursor(String var1, Object var2);
<T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
int insert(String var1);
int insert(String var1, Object var2);
int update(String var1);
int update(String var1, Object var2);
int delete(String var1);
int delete(String var1, Object var2);
void commit();
void commit(boolean var1);
void rollback();
void rollback(boolean var1);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
// 获取mapper接口代理对象
<T> T getMapper(Class<T> var1);
Connection getConnection();
}
3、获取Mapper接口
此处不使用SqlSession中的方法直接操作数据库,而是使用SqlSession获取Mapper接口,调用Mapper接口中的方法操作数据库。实际上是通过JDK动态代理获取Mapper接口的代理类,通过代理类调用方法来操作数据库。
在使用SqlSession获取Mapper接口的动态代理时,必须满足下面四个条件:
1. 映射文件的命名空间(namespace)必须是mapper接口的全路径;
2. 映射文件的statement的id必须和mapper接口的方法名保持一致;
3. statement的resultType必须和mapper接口方法的返回类型一致;
4. statement的parameterType与mapper接口方法的参数类型一致(不一定)。
SqlSession调用getMapper方法获取Mapper接口,实际是调用实现类DefaultSqlSession的getMapper方法。
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
调用Configuration类的getMapper方法:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
Configuration类中同时提供了新增Mapper的方法。可想而知,既然可以通过Configuration获取到Mapper,必然需要先新增Mapper。
public void addMappers(String packageName, Class<?> superType) {
this.mapperRegistry.addMappers(packageName, superType);
}
public void addMappers(String packageName) {
this.mapperRegistry.addMappers(packageName);
}
public <T> void addMapper(Class<T> type) {
// 调用MapperRegistry类的addMapper方法
this.mapperRegistry.addMapper(type);
}
此处先分析Configuration类的addMapper方法,然后再回过头来分析getMapper方法。
下面是MapperRegistry类的源码:
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 sqlSession) {
//根据接口的Class获取到MapperProxyFactory对象
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(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
public <T> boolean hasMapper(Class<T> type) {
return this.knownMappers.containsKey(type);
}
//调用MapperRegistry类的addMapper方法
public <T> void addMapper(Class<T> type) {
//只添加接口
if (type.isInterface()) {
//如果已经添加,不允许重复添加
if (this.hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//以接口的Class为键,以MapperProxyFactory对象为值保存到Map中。
//MapperProxyFactory对象又持有接口的引用
this.knownMappers.put(type, new MapperProxyFactory(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
this.knownMappers.remove(type);
}
}
}
}
public Collection<Class<?>> getMappers() {
return Collections.unmodifiableCollection(this.knownMappers.keySet());
}
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil();
resolverUtil.find(new IsA(superType), packageName);
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
Iterator var5 = mapperSet.iterator();
while(var5.hasNext()) {
Class<?> mapperClass = (Class)var5.next();
this.addMapper(mapperClass);
}
}
public void addMappers(String packageName) {
this.addMappers(packageName, Object.class);
}
}
下面看一下MapperProxyFactory类的源码:
public class MapperProxyFactory<T> {
//MapperProxyFactory类中持有Mapper接口的引用,封装了Mapper接口作为属性
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return this.mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return this.methodCache;
}
//通过JDK动态代理生成接口的代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
}
现在再回过头来分析Configuration类的getMapper方法:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 调用MapperRegistry类的getMapper方法
return this.mapperRegistry.getMapper(type, sqlSession);
}
调用MapperRegistry类的getMapper方法:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
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(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
调用MapperProxyFactory类的newInstance方法:
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
通过JDK动态代理生成接口的代理对象:
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
因此,通过SqlSession的getMapper方法最终得到的是Mapper接口的代理对象。并且根据JDK动态代理的原理可知,MapperProxy必然实现了InvocationHandler接口,重写了invoke方法。在代理对象重写的目标方法中会调用重写的invoke方法。
MapperProxy类的源码如下所示:
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method, Object[] args) throws Throwable {
try {
// 如果要调用的方法属于类,而不是属于接口,则直接通过反射调用(接口没有继承Object)
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 若是默认方法,则直接调用接口的默认方法
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
// 调用execute方法
MapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod = (MapperMethod)this.methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
this.methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
@UsesJava7
private Object invokeDefaultMethod(Object proxy, Method, Object[] args) throws Throwable {
Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
Class<?> declaringClass = method.getDeclaringClass();
return ((Lookup)constructor.newInstance(declaringClass, 15)).unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
private boolean isDefaultMethod(Method method) {
return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
}
}
4、调用接口方法操作数据库
本例中通过User user = userMapper.findUserById(1);调用UserMapper接口的findUserById方法查询用户信息。根据JDK动态代理的原理可知,实际是代理对象调用自己重写的目标方法,在重写的目标方法中调用了InvocationHandler的invoke方法。因此,userMapper.findUserById方法在底层调用了InvocationHandler的invoke方法。由上面可知,MapperProxy类实现了InvocationHandler接口,重写了invoke方法,根据多态性可知,实际调用了MapperProxy类的invoke方法。
调用MapperProxy类的invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//如果要调用的方法属于类,而不是属于接口,则直接通过反射调用(接口没有继承Object)
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//如果要调用Mapper接口中对数据库增删改查的方法,则调用execute方法
return mapperMethod.execute(this.sqlSession, args);
}
接口没有继承Object。如果一个接口定义是最顶级的(没有super interfaces),那么这个接口会自动声明一个abstract member method结构体来代表所有来自Object类(一切类的superclass)中的public方法(包括这些方法的签名、返回类型以及抛出的异常)。再换种说法——意思是接口隐含定义了一套与Object类中的方法签名完全相同的方法,所以,我们在程序中调用接口的那些与Object中具有相同签名的方法时,编译器不会报错!
由于Mapper接口没有实现类,所以在MapperProxy类的invoke方法中会调用MapperMethod的execute方法。
调用MapperMethod的execute方法:
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
switch(this.command.getType()) {
case INSERT:
// sqlSession.insert方法
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
// sqlSession.update方法
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
// sqlSession.delete方法
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
// sqlSession.selectOne方法
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
最终都会执行SqlSession对应的增删改查方法。因此,通过Mapper接口的代理对象调用Mapper接口的代理方法,与直接通过SqlSession调用方法是一样的。此处以SqlSession接口的selectOne方法为例分析,调用实现类DefaultSqlSession的selectOne方法:
public <T> T selectOne(String statement, Object parameter) {
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
// 调用抽象实现类BaseExecutor的query方法
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}
交给Executor接口去执行,调用Executor接口的query方法,实际是调用抽象实现类BaseExecutor的query方法:
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//通过MappedStatement还有查询参数来生成BoundSql。BoundSql就是对sql的包装,包含sql语句,参数,List(参数的mapping)。
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
try {
++this.queryStack;
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 调用抽象类BaseExecutor的queryFromDatabase方法
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
调用抽象类BaseExecutor的queryFromDatabase方法:
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
//调用抽象类BaseExecutor的doQuery方法,实际调用实现类的doQuery方法
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
this.localCache.removeObject(key);
}
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
继续看一下实现类SimpleExecutor的doQuery方法:
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = this.prepareStatement(handler, ms.getStatementLog());
// 调用实现类PreparedStatementHandler的query方法
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
调用StatementHandler接口的query方法,调用实现类PreparedStatementHandler的query方法:
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
//通过PreparedStatement执行SQL,将结果交给ResultSetHandler处理
ps.execute();
//调用接口ResultSetHandler的handleResultSets方法
return this.resultSetHandler.handleResultSets(ps);
}
调用实现类DefaultResultSetHandler的handleResultSets方法:
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
List<Object> multipleResults = new ArrayList();
int resultSetCount = 0;
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
this.validateResultMapsCount(rsw, resultMapCount);
while(rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
String[] resultSets = this.mappedStatement.getResultSets();
if (resultSets != null) {
while(rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
}
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
}
return this.collapseSingleResultList(multipleResults);
}
至此,mybatis源码分析完毕,由此可知,mybatis底层是对JDBC的封装,是通过JDK动态代理与JDBC实现的。mybatis通过sqlsession操作数据库,实际上是通过JDBC操作数据库。