您的位置:首页 > 移动开发

Mybatis源码分析获取Mapper

2016-04-01 17:43 393 查看
这次分析的入口是

StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);


根据上篇分析我们这里获得的sqlSession是DefaultSqlSession,

public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
private Executor executor;
private boolean autoCommit;
private boolean dirty;

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
}


1.我们进入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);
}


利用我们开始解析xml获得的mapperRegistry获取,继续跟进

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();//这是我们mapperRegistry中保存的
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);//通过上面的HashMap获取mapperProxyFactory
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?

翻译成中文就是映射代理工厂。

private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}


上面构造函数的代码首先会把之前在mapper.xml中配置的那些mapper接口注入进去,这里我们也会有一个方法缓存,我们每个方法都会对应一个MapperMethod其中保存我们已经解析过的sql。接下来我们就会生成我们的代理映射类。

public T newInstance(SqlSession sqlSession) {
MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance((MapperProxy)mapperProxy);
}


mapperProxy就是我们的代理类,接下来进入我们的代理类之中。Mybatis实现的是Jdk动态代理,在代理之中最重要的当然是invoke,接下来我们分析。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
} else {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}

private MapperMethod cachedMapperMethod(Method method) {
MapperMethod 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;
}


1.上面的invoke之中我们首先判断method方法的拥有者类是不是和object.class相等。如果相等就直接执行Invoke。

2.如果不相等通过this.cachedMapperMethod(method);获取我们该方法的缓存映射。

3。调用mapperMethod.execute(this.sqlSession, args); 这是真正的执行过程。

这里MapperMethod非常重要我们这里详细分析:

public class MapperMethod {
private final MapperMethod.SqlCommand command;
private final MapperMethod.MethodSignature method;

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
this.method = new MapperMethod.MethodSignature(config, method);
}
}


在MapperMethod维护了两个变量SqlCommand 和MethodSignature ,SqlCommand类获取处理的唯一标识及SQL语句类型,MethodSignature类对业务接口方法的入参类型及出参类型进行处理。

在SqlCommand的构造函数中有

public static class SqlCommand {
private final String name;//保存我们唯一标识id
private final SqlCommandType type;//保存我们sql语句类型

public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
String statementName = mapperInterface.getName() + "." + method.getName();
MappedStatement ms = null;
if(configuration.hasStatement(statementName)) {
ms = configuration.getMappedStatement(statementName);
} else if(!mapperInterface.equals(method.getDeclaringClass())) {
String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
if(configuration.hasStatement(parentStatementName)) {
ms = configuration.getMappedStatement(parentStatementName);
}
}

if(ms == null) {
if(method.getAnnotation(Flush.class) == null) {
throw new BindingException("Invalid bound statement (not found): " + statementName);
}

this.name = null;
this.type = SqlCommandType.FLUSH;
} else {
this.name = ms.getId();
this.type = ms.getSqlCommandType();
if(this.type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + this.name);
}
}

}
}


当我们代理实例生成之后,我们利用jdk反射Proxy.newProxyInstance()方法生成我们的代理类。

protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}


至此我们获取Mapper过程全部分析完毕。简而言之就是生成了利用Proxy动态代理反射生成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: