代理模式源码解析(jdk+spring+mybatis)
生活随笔
收集整理的這篇文章主要介紹了
代理模式源码解析(jdk+spring+mybatis)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
首先是java.lang.reflect,也就是我們剛剛使用的Proxy這個類,這里面coding的時候,也就是debug的時候,這個就是代理的一個典型應用,還有proxyFactoryBean,這個是一個代理的工廠bean,他呢首先是一個bean@SuppressWarnings("serial")
public class ProxyFactoryBean extends ProxyCreatorSupportimplements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {他是一個什么bean呢,它是代理的工廠類,這么一個bean,那這里面的實現(xiàn)我們就不擴展來講了,有興趣的小伙伴可以來這里看一下,那這個代理工廠bean呢,核心方法就是getObject這么一個方法,里面進行各種判斷,同時在這里面生成一個單例對象,生成一個PrototypeInstance,那我們在使用Spring的時候/*** Return a proxy. Invoked when clients obtain beans from this factory bean.* Create an instance of the AOP proxy to be returned by this factory.* The instance will be cached for a singleton, and create on each call to* {@code getObject()} for a proxy.* @return a fresh AOP proxy reflecting the current state of this factory*/@Override@Nullablepublic Object getObject() throws BeansException {initializeAdvisorChain();if (isSingleton()) {return getSingletonInstance();}else {if (this.targetName == null) {logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +"Enable prototype proxies by setting the 'targetName' property.");}return newPrototypeInstance();}}不加prototype這種聲明的話,他就是一個單例對象,那如果聲明成prototype這種類型呢,他就是一個多例對象,也就是每次重新調(diào)用它的時候呢,都會生成一個新的instance,那這個類呢比較復雜,有興趣的可以來這里看一下,這個類也是Spring的一個核心類,那Spring實現(xiàn)AOP的話,還有兩個重要的類,分別是JdkDynamicAopProxy,它是AOP包下的,這里就是對JDK的動態(tài)代理進行了一些封裝,那JDK的動態(tài)代理在這里,final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable我們還要看一下CglibAopProxy,這些都是在Spring中的一些體現(xiàn)class CglibAopProxy implements AopProxy, Serializable那在Mybatis當中當然也有使用代理模式,我們來看一下MapperProxyFactory這么一個類,他呢是Mybatis下邊的,從名字就可以看出來,它是Mapper的代理工廠,我們主要看一下這個方法public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}這里面?zhèn)魅肓薙qlSession,哪里調(diào)用他了呢,在MapperRegistry里邊,有一個getMapper方法,這里面調(diào)用了工廠的newInstance,那這個getMapper又在哪里調(diào)用了呢,@SuppressWarnings("unchecked")public <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}他呢是在Configuration這里邊,public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);}getMapper調(diào)用了,Configuration里面是對應的各種配置,然后我們看一下里面的聲明,方法聲明,里面有addMapper,還有處理一些ResultMap,比如ResultMap,這里面處理ResultMap,各種配置的處理,public ResultMap getResultMap(String id) {return resultMaps.get(id);}再回到工廠里面我們看一下,這里面是怎么做的呢,首先它通過具體的各種參數(shù),包括methodCache,public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}這個就是接口,然后創(chuàng)建一個MapperProxy,然后又調(diào)用了newInstance(mapperProxy);這個方法,這個方法就是@SuppressWarnings("unchecked")protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}可以看到呢,Proxy.newProxyInstance,和我們剛剛寫動態(tài)代理調(diào)用的方法是一樣的,里面?zhèn)魅肓薈lassLoader,還有對應的interface,還有MapperProxy,也就是這里生成了一個代理對象,然后把它進行返回,那我們來看一下MapperProxy這里面是怎么寫的,進來,我們主要關注一個invoke方法,@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (Object.class.equals(method.getDeclaringClass())) {try {return method.invoke(this, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);}invoke方法自然是InvocationHandler這個接口所要實現(xiàn)的方法public class MapperProxy<T> implements InvocationHandler, Serializable接著來看,因為我們動態(tài)代理也實現(xiàn)了invoke方法, if (Object.class.equals(method.getDeclaringClass()))這里進行一個判斷,判斷這個類型是不是Object類型,如果是的就直接返回,return method.invoke(this, args);然后重點看這兩行final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);對Method進行一個Cache,怎么Cache的呢,看一下,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;}這里像不像我們這里的享元模式呢,這里面可以理解為享元模式,return就開始執(zhí)行execute,也就是說,通過這種方式,只需要編寫對應的Mapper.java的interface就可以了,我們用戶訂單,產(chǎn)品的Mapper呢,通過工具生成一個ProductMapper.java,而當執(zhí)行這個接口里面的insert,update操作的時候呢,就會給MapperProxy這個代理,然后就會調(diào)用invoke這個方法,如果沒有Object.class.equals(method.getDeclaringClass()),final MapperMethod mapperMethod = cachedMapperMethod(method);這里首先通過享元進行一個Cache,提高速度,mapperMethod.execute方法,我們進來看一下public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;}這里面進行了各種判斷,如果是INSERT,UPDATE,DELETE,SELECT,各種判斷,還有FLUSH等等,然后把返回結果返回回去,那這一塊就是代理模式在Mybatis里面的應用,而且使用的是JDK的原生動態(tài)代理,通過實現(xiàn)InvocationHandler這個接口就可以看出來,那代理模式在各種框架中,應用非常廣泛,也是因為他的動態(tài)特性,把代理模式學好,為以后學習其他框架,也是非常非常有幫助的,相信在代理模式這里,學到的不僅僅是代理模式,還有代理模式在源碼中的應用
?
總結
以上是生活随笔為你收集整理的代理模式源码解析(jdk+spring+mybatis)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代理模式coding-动态代理
- 下一篇: 模板方法模式讲解