1 概述
针对这里的源码分析,我们首先要搞清楚java动态代理,因为就因为这里使用了java动态代理,才能够让我们在并没有mapper接口实现类对应的bean的情况下也能够进行依赖注入。
2 MapperProxyFactory
这个类的主要作用是用于生成mapper接口的Proxy代理。
我们直接来看一下源码。
import org.apache.ibatis.session.SqlSession;
/**
* @author Lasse Voss
*/
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface; //mapper接口
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>(); //mapper接口中对应的method与xml节点封装MapperMethod的map
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//生成接口的代理类
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//初始化MapperProxy,这个MapperProxy其实是InvokeHandler类的实现类
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
从上面的源码我们得知,MapperProxyFactory的作用其实就是生成Mapper接口的动态代理对象。其实在我们添加依赖注入的时候注入到Spring容器中的也就是这个动态代理对象。
3 MapperProxy
由上面的分析可以猜想MapperProxy实现了主要的动态代理逻辑,我们直接看一看源码。
/**
* @author Clinton Begin
* @author Eduardo Macarron
*/
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;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断method是否是属于Object类,如果是则直接执行
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//获取method对应的MapperMethod封装,直接执行execute。
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
从上面我们知晓MapperProxy的invoke方法实际上是把Mapper接口方法包装为了MapperMethod,并执行的MapperMethod的execute方法。
上面我们完成了MapperProxyFactory&MapperProxy源码分析,我们将继续进行Mybatis的其余内容进行分析,欢迎交流。