是Mybatis的使用过程中,我们只要配置成功,我们就可以使用定义好的接口类,直接使用他的方法,不用去实现他,这其中的原理是什么呢?下面开始探究其原理
一 代理对象是如何产生的
PersonMapper personMapper = session.getMapper(PersonMapper.class);
personMapper.getOne();
相信大家对上面的代码很熟悉,本文就从session.getMapper开始探究,其底层方法是MapperRegistry的getMapper方法
public class MapperRegistry {
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//进入MapperProxyFactory的newInstance方法
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
/**************************************分界线********************************************************/
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;//原接口class对象
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
public T newInstance(SqlSession sqlSession) {
//MapperProxy是一个InvocationHandler,
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
//利用jdk动态代理生产代理类
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
}
二 代理对象是如何执行方法
通过上面的分析我们知道,mybatis代理对象是通过jdk动态代理生产,其动态代理类调用处理程序类是MapperProxy,所以执行代理类的方法会被转发到实现InvocationHandler接口类MapperProxy的invoke方法中类,
2.1 方法类别判断
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
//如果调用的是Object的方法,就直接调用他,不用太关注
return method.invoke(this, args);
} else if (method.isDefault()) {
//对默认方法的处理,不用太关注
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//如果缓存中存在这个方法,从缓存中取,
//如果没有,就从Configuration中获取相关信息,查询其方法和对应的sql语句建立,封装成MapperMethod类
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行方法,重点
return mapperMethod.execute(sqlSession, args);
}
/**************************************分界线********************************************************/
public class MapperMethod {
private final SqlCommand command;//接口方法和对应的sql语句
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
//args是传入的参数
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//command.getType()是sql语句的类型,如select,insert等
switch (command.getType()) {
case INSERT: { //insert语句,进入这个
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: { //update语句,进入这个
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: { //delete 语句,进入这个
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT: //select 语句,进入这个
if (method.returnsVoid() && method.hasResultHandler()) {
// 如果返回void 并且方法参数有ResultHandler
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//如果返回多行结果
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
//如果返回MAP
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
//如果返回Cursor
result = executeForCursor(sqlSession, args);
} else {
//否则就是查询单个对象
//返回方法对应参数信息和其值
Object param = method.convertArgsToSqlCommandParam(args);
//执行方法,本文重点研究这个方法
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
2.2 方法参数解析过程
Mybatis是通过
method.convertArgsToSqlCommandParam(args);
获取方法参数及其值,其底层是MethodSignature的convertArgsToSqlCommandParam方法
//MethodSignature是MapperMethod的静态内部类
public static class MethodSignature {
private final boolean returnsMany;
private final boolean returnsMap;
private final boolean returnsVoid;
private final boolean returnsCursor;
private final boolean returnsOptional;
private final Class<?> returnType;
private final String mapKey;
private final Integer resultHandlerIndex;
private final Integer rowBoundsIndex;
private final ParamNameResolver paramNameResolver;
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
.......
//解析@Param注解
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
}
/********************************分界线***************************************************/
public class ParamNameResolver {
private static final String GENERIC_NAME_PREFIX = "param";
private final SortedMap<Integer, String> names;
private boolean hasParamAnnotation;
// 解析@Param注解,把解析结果放到names中,key是位置从0开始,vaule是@Param值,
// 如果没有标注@Param注解,vaule就是arg+"key":如arg0
public ParamNameResolver(Configuration config, Method method) {
final Class<?>[] paramTypes = method.getParameterTypes();
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
int paramCount = paramAnnotations.length;
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue #71
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
//没有参数,直接返回
if (args == null || paramCount == 0) {
return null;
//没有标注@Param,且参数格式为1
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
//多个参数的情况
final Map<String, Object> param = new ParamMap<>();
int i = 0;
//循环遍历names
for (Map.Entry<Integer, String> entry : names.entrySet()) {
//如果标注@Param了,key就是@Param值,否则就是args0 args1 等
//值是入参值
param.put(entry.getValue(), args[entry.getKey()]);
//从新添加新的key值规则,如param1 param2...
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
}
结论:Mybatis在方法参数解析时,如果是一个参数且参数上标注@Param,那么读取的参数名就是@Param的值,否则就是如args0 args1等;如果是多个参数,那么每个参数都有2个名字一个就是
param+“i + 1”
,如param1 param2。另一个的话,如果标注@Param,那么参数名就是@Param的值,否则就是如args0 args1等
2.3 select类型方法执行过程
public class DefaultSqlSession implements SqlSession {
@Override
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("..忽略.“);
} else {
return null;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
//statement是调用的方法名,parameter是入参
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//从全局配置值获取对应sql映射的包装对象
MappedStatement ms = configuration.getMappedStatement(statement);
//调用执行器Executor进行处理
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
2.4 执行器Executor对方法的处理
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//二级缓存cache
Cache cache = ms.getCache();
if (cache != null) {
//判断要不要刷新缓存
flushCacheIfRequired(ms);
//是否使用二级缓存,默认true
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
//从事物管理器获取缓存
List<E> list = (List<E>) tcm.getObject(cache, key);
//如果没有缓存,就从数据库查
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
public abstract class BaseExecutor implements Executor {
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//${}是在这里解析的
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@SuppressWarnings("unchecked")
@Override
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 (closed) {throw new ExecutorException("Executor was closed."); }
if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache();}
List<E> list;
try {
queryStack++;
//一级缓存,通过key获取结果
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
//从缓存中取
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//查询数据库
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
//往缓存中储存一个一个临时 值,和对应的key
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
//
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
- 进入子类的SimpleExecutor的doQuery方法
public class SimpleExecutor extends BaseExecutor {
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//获取Statement对象,并为?占位符赋值
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
//参数类型解析
handler.parameterize(stmt);
return stmt;
}
}
2.5 StatementHandler与数据库建立链接,并执行sql
public class PreparedStatementHandler extends BaseStatementHandler {
@Override
public void parameterize(Statement statement) throws SQLException {
//底层是其子类DefaultParameterHandler的setParameters方法
parameterHandler.setParameters((PreparedStatement) statement);
}
}
/***********************分界线**************************************************/
public class DefaultParameterHandler implements ParameterHandler {
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
2.6 StatementHandler与数据库建立链接,并执行sql
public class PreparedStatementHandler extends BaseStatementHandler {
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//执行sql
ps.execute();
//利用ResultSetHandler处理结果
return resultSetHandler.handleResultSets(ps);
}