为什么 Mapper 接口不需要实现类?
四个字回答:动态代理,我们来看一下获取 Mapper 的过程:

- 获取 Mapper
我们都知道定义的 Mapper 接口是没有实现类的,Mapper 映射其实是通过动态代理实现的。
BlogMapper mapper = session.getMapper(BlogMapper.class);
七拐八绕地进去看一下,发现获取 Mapper 的过程,需要先获取 MapperProxyFactory——Mapper 代理工厂。
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
MapperProxyFactory 的作用是生成 MapperProxy(Mapper 代理对象)。
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
……
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);
}
}
这里可以看到动态代理对接口的绑定,它的作用就是生成动态代理对象(占位),而代理的方法被放到了 MapperProxy 中。
- MapperProxy
MapperProxy 里,通常会生成一个 MapperMethod 对象,它是通过 cachedMapperMethod 方法对其进行初始化的,然后执行 excute 方法。
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);
}
}
- MapperMethod
MapperMethod 里的 excute 方法,会真正去执行 sql。这里用到了命令模式,其实绕一圈,最终它还是通过 SqlSession 的实例去运行对象的 sql。
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
……
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;
……
}
THE END
暂无评论内容