SSM-Mybatis-运行原理和解析-Session运行过程
映射器的动态代理
通过代码分析:
RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
查看Mybatis如何实现getMapper,在IDEA中通过ctrl+H查看SqlSession实现类DefaultSqlSession
//DefaultSqlSession类中的getMapper实现方法
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
显然使用了Configuration对象的getMapper方法,获取对应的对象。继续跟踪这个方法
//Configuration对象中的getMapper方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
可以看到使用了mapperRegistry映射器的注册器来获取对应的接口对象
//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);
}
}
}
上面代码,首先判断是否注册一个Mapper,如果没有则会抛出异常,如果有,会启动MapperProxyFactory工厂来生成一个代理实例。继续往下看:
//MapperProxyFactory工厂类
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return this.mapperInterface;
}
public Map<Method, MapperMethodInvoker> getMethodCache() {
return this.methodCache;
}
//看此处
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);
}
}
注意注释的两个方法,Mapper映射通过动态代理实现,可以看到动态代理对接口的绑定,作用是生产动态对象(占位),代理的方法则放在MapperProxy类中。继续往下看:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return Object.class.equals(method.getDeclaringClass()) ?
method.invoke(this, args) :
this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
}
使用三元运算没判断Mapper是一个动态代理,如果是,则运行invoke方法。invoke首先判断是否是一个类,Mapper是一个接口不是类,判定失败,然后生成MapperMethod对象,通过cachedMapperMethod 方法对其进行初始化,最后执行execute方法,把SqlSession和当前运行参数传递进去
execute源码:
public class MapperMethod {
private final MapperMethod.SqlCommand command;
private final MapperMethod.MethodSignature method;
...
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
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);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
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;
}
}
...
//注释的方法
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
Object param = this.method.convertArgsToSqlCommandParam(args);
List result;
if (this.method.hasRowBounds()) {
RowBounds rowBounds = this.method.extractRowBounds(args);
result = sqlSession.selectList(this.command.getName(), param, rowBounds);
} else {
result = sqlSession.selectList(this.command.getName(), param);
}
if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
} else {
return result;
}
}
}
注释代码,MapperMethod类采用命令模式运行,根据上下文跳转到许多方法,不需要全部方法看明白,讨论executeForMany,源码中,实际上最后通过SqlSession对象去运行的SQL,其他的增删改查也是类似的处理