mybatis中mapper都是接口捕仔,我們在使用的時候都是可以通過@Autowired依賴注入進(jìn)mapper實例徒仓。這些mapper實例都是由MapperProxyFactory工廠生成的MapperProxy代理對象虏缸,這里主要涉及到了Mapper、MapperProxy和MapperProxyFactory三個對象,以下是對這些對象的簡要描述:
- Mapper:這個是我們定義的Mapper接口约郁,在應(yīng)用中使用战惊。
- MapperProxy:這個是使用JDK動態(tài)代理對Mapper接口生成的代理實例流昏,也就是我們實際使用引入的實例對象
- MapperProxyFactory:這個是使用了工廠模式,用來對某一mapper接口來生成MapperProxy實例的吞获。
以下來對上述接口和類來進(jìn)行源碼分析:
MapperProxyFactory源碼:
public class MapperProxyFactory<T> {
//mapper接口况凉,就是實際我們定義的接口,也是需要代理的target
private final Class<T> mapperInterface;
//Method的緩存各拷,應(yīng)該是當(dāng)前Mapper里面的所有method刁绒,這里有點疑問
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
//給對應(yīng)的mapper接口生成MapperProxy代理對象
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
MapperProxy源碼:
public class MapperProxy<T> implements InvocationHandler, Serializable {
//當(dāng)前會話
private final SqlSession sqlSession;
//target對象,mapper接口
private final Class<T> mapperInterface;
//方法緩存烤黍,key是Mapper接口里面的Method對象
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 {
try {
//判斷方法是否為Obect里面聲明的對象
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//創(chuàng)建并緩存MapperMethod
final MapperMethod mapperMethod = cachedMapperMethod(method);
//執(zhí)行method方法
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
//如果緩存里面沒有的話就創(chuàng)建并且放入緩存中知市,這里緩存是一個ConcurrentHashMap
return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
}
這里的MapperProxy是對Mapper接口的代理對象,當(dāng)調(diào)用mapper接口的方法時會進(jìn)行攔截速蕊,生成MapperMethod對象并放入緩存中嫂丙,這里的緩存存在的意義就是不用下次再來生成該接口方法的MapperMethod對象,然后執(zhí)行對應(yīng)的方法规哲。這里根據(jù)方法類型(insert | update)來路由執(zhí)行對應(yīng)的方法跟啤。
Mapper接口內(nèi)的方法不能重載
原因:在Mapper接口生成的代理MapperProxy中,可以看到在方法被攔截的處理動作中唉锌,是把方法對應(yīng)的MapperMethod放到了緩存中隅肥,緩存是以Method對象作為key,所以是不允許重載這種情況的袄简。
final MapperMethod mapperMethod = cachedMapperMethod(method);