上一篇文章中講述了DefaultSqlSession的創(chuàng)建過程。它可以利用executor來完成crud操作悠夯、管理數據庫連接和事務,也可以根據mapper類型來獲取mapper代理對象。sql的執(zhí)行放到后面講,本文先記錄一下mapper代理對象是如何生成的
MemberDao mapper = sqlSession.getMapper(MemberDao.class);
當我們寫下getMapper(mapper.class)的時候尤筐,框架在后臺做了些什么事?實際上洞就,sqlSession本身是對mapper無感知的盆繁,所有關于mapper的信息,都在configuration屬性中旬蟋。所以getMapper先交給了configuration來完成油昂。
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
在第一篇文章中說過,對mapper的解析完成后,以type:MapperProxyFactory(type)的形式將mapper的類型和產生對應代理對象的工廠存放到了mapperRegistry中的knowMapppers內冕碟,并將mapper的parameterMap稠腊、resultMap、statement等屬性以namespace: val的形式存到了對應的HashMap里鸣哀。然后在這里configuration.getMapper就將工作交給了mapperRegistry.同時,為了完成mapper與sqlSession的綁定吞彤,還將sqlSession作為參數傳遞了進來我衬。
//委派給mapperRegistry完成
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
看看mapperRegistry是如何獲取到mapper代理對象的吧。
// 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);
}
}
}
實際上饰恕,mapperRegistry并不承擔創(chuàng)建代理對象的職責挠羔,它的責任就是完成mapper的注冊。創(chuàng)建代理對象交給mapperProxyFactory來完成埋嵌。mapperProxyFactory內部mapperInterface用于封裝mapper的類型對象破加,methodCache則存放方法緩存。
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap();
// ······
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);
}
重點關注代理對象的創(chuàng)建雹嗦,在這里首先調用的是 newInstance(SqlSession sqlSession)方法范舀,然后調newInstance(MapperProxy<T> mapperProxy),最后由Proxy.newProxyInstance()生成代理對象。至于這中間做了什么了罪,我們想想動態(tài)代理Proxy.newProxyInstance(...)是如何創(chuàng)建代理對象的吧锭环。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Proxy.newProxyInstance(loader, interfaces, ih)需要三個參數: 被代理對象的類加載器loader、被代理對象的接口類型數組Class<?> [] interfaces泊藕、定義了方法調用邏輯的InvocationHandler h.
先思考一下:假設現在我們有一個類對象辅辩,需要創(chuàng)建一個能夠對它的方法進行增強的代理實例對象,該對象進行方法調用的邏輯在invocationHandler中,該如何創(chuàng)建這個代理對象呢娃圆?
咱也不知道哇玫锋,咱只知道動態(tài)代理...這里的invocationHandler不就有方法的實現邏輯嗎?我們只需要一個對象讼呢,把該對象方法的調用關聯給這個invocationHandler去做不就行了嗎撩鹿?
//todo : 動態(tài)代理ref:https://zhuanlan.zhihu.com/p/60805342
//invocationHandler.invoke(proxy, method, args)
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
所以Proxy類就實現了這么一個功能:動態(tài)創(chuàng)建一個代理對象proxyObj,將對象與InvocationHandler ih關聯。然后當我們在程序中使用proxyObj.method(args)的時候吝岭,實際上就交給了ih.invoke(proxyObj, method, args)去處理三痰。
我們現在有了前兩個參數,但是當方法被調用時怎么進行處理的邏輯還沒有啊窜管。因此需要先創(chuàng)建一個InvocationHandler對象來,這個對象就是mapperProxy.他的構造方法很簡單散劫,就是將sqlSession, 接口和方法緩存關聯進來。沒什么好講的
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -4724728412955527868L;
private static final int ALLOWED_MODES = 15;
private static final Constructor<Lookup> lookupConstructor;
private static final Method privateLookupInMethod;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperProxy.MapperMethodInvoker> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperProxy.MapperMethodInvoker> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
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);
}
}
//......
}
在newInstance(SqlSession sqlSession)時創(chuàng)建了mapperProxy幕帆,然后再使用Proxy.newInstance(interface.getClassLoader, new Class[]{interface}, mapperProxy)創(chuàng)建了一個對象获搏,并將該對象與mapperProxy進行了關聯,最后返回代理對象。如下。
public class MapperProxyFactory<T> {
// ······
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);
}
至此常熙,xxxMapper = getMapper(xxxMapper.class)就結束了纬乍。我們拿到了代理對象,接下來的問題就是如何使用這個代理對象了裸卫,也就是當我們調用xxxMapper .xxxMethod()時仿贬,框架在后臺做了些什么。
to be continued.