Mybatis mapper动态代理的原理解析
前言
在开始动态代理的原理讲解以前,我们先看一下集成mybatis以后dao层不使用动态代理以及使用动态代理的两种实现方式,通过对比我们自己实现dao层接口以及mybatis动态代理可以更加直观的展现出mybatis动态代理替我们所做的工作,有利于我们理解动态代理的过程,讲解完以后我们再进行动态代理的原理解析,此讲解基于mybatis的环境已经搭建完成,并且已经实现了基本的用户类编写以及用户类的Dao接口的声明,下面是Dao层的接口代码
publicinterfaceUserDao{ /* 查询所有用户信息 */ ListfindAll(); /** *保存用户 *@paramuser */ voidsave(Useruser); /** *更新用户 *@return */ voidupdate(Useruser); /** *删除用户 */ voiddelete(IntegeruserId); /** *查找一个用户 *@paramuserId *@return */ UserfindOne(IntegeruserId); /** *根据名字模糊查询 *@paramname *@return */ List findByName(Stringname); /** *根据组合对象进行模糊查询 *@paramvo *@return */ List findByQueryVo(QueryVovo); }
一、Mybatisdao层两种实现方式的对比
1.dao层不使用动态代理
dao层不使用动态代理的话,就需要我们自己实现dao层的接口,为了简便起见,我只是实现了Dao接口中的findAll方法,以此方法为例子来展现我们自己实现Dao的方式的情况,让我们来看代码:
publicclassUserDaoImplimplementsUserDao{ privateSqlSessionFactoryfactory; publicUserDaoImpl(SqlSessionFactoryfactory){ this.factory=factory; } publicListfindAll(){ //1.获取sqlSession对象 SqlSessionsqlSession=factory.openSession(); //2.调用selectList方法 List list=sqlSession.selectList("com.example.dao.UserDao.findAll"); //3.关闭流 sqlSession.close(); returnlist; } publicvoidsave(Useruser){ } publicvoidupdate(Useruser){ } publicvoiddelete(IntegeruserId){ } publicUserfindOne(IntegeruserId){ returnnull; } publicList findByName(Stringname){ returnnull; } publicList findByQueryVo(QueryVovo){ returnnull; }
这里的关键代码List
注意:如果是添加,更新或者删除操作的话需要在方法中增加事务的提交。
2.dao层使用Mybatis的动态代理
使用动态代理的话Dao层的接口声明完成以后只需要在使用的时候通过SqlSession对象的getMapper方法获取对应Dao接口的代理对象,关键代码如下:
//3.获取SqlSession对象 SqlSessionsession=factory.openSession(); //4.获取dao的代理对象 UserDaomapper=session.getMapper(UserDao.class); //5.执行查询所有的方法 Listlist=mapper.findAll();
获取到dao层的代理对象以后通过代理对象调用查询方法就可以实现查询所有用户列表的功能。
二、Mybatis动态代理实现方式的原理解析
动态代理中最重要的类:SqlSession、MapperProxy、MapperMethod,下面开始从入口方法到调用结束的过程分析。
1.调用方法的开始:
//4.获取dao的代理对象
UserDaomapper=session.getMapper(UserDao.class);因为SqlSesseion为接口,所以我们通过Debug方式发现这里使用的实现类为DefaultSqlSession。
2.找到DeaultSqlSession中的getMapper方法,发现这里没有做其他的动作,只是将工作继续抛到了Configuration类中,Configuration为类不是接口,可以直接进入该类的getMapper方法中
@Override publicTgetMapper(Class type){ returnconfiguration. getMapper(type,this); }
3.找到Configuration类的getMapper方法,这里也是将工作继续交到MapperRegistry的getMapper的方法中,所以我们继续向下进行。
publicTgetMapper(Class type,SqlSessionsqlSession){ returnmapperRegistry.getMapper(type,sqlSession); }
4.找到MapperRegistry的getMapper的方法,看到这里发现和以前不一样了,通过MapperProxyFactory的命名方式我们知道这里将通过这个工厂生成我们所关注的MapperProxy的代理类,然后我们通过mapperProxyFactory.newInstance(sqlSession);进入MapperProxyFactory的newInstance方法中
publicTgetMapper(Class type,SqlSessionsqlSession){ finalMapperProxyFactory mapperProxyFactory=(MapperProxyFactory )knownMappers.get(type); if(mapperProxyFactory==null){ thrownewBindingException("Type"+type+"isnotknowntotheMapperRegistry."); } try{ returnmapperProxyFactory.newInstance(sqlSession); }catch(Exceptione){ thrownewBindingException("Errorgettingmapperinstance.Cause:"+e,e); } }
5.找到MapperProxyFactory的newIntance方法,通过参数类型SqlSession可以得知,上面的调用先进入第二个newInstance方法中并创建我们所需要重点关注的MapperProxy对象,第二个方法中再调用第一个newInstance方法并将MapperProxy对象传入进去,根据该对象创建代理类并返回。这里已经得到需要的代理类了,但是我们的代理类所做的工作还得继续向下看MapperProxy类。
protectedTnewInstance(MapperProxymapperProxy){ return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{mapperInterface},mapperProxy); } publicTnewInstance(SqlSessionsqlSession){ finalMapperProxy mapperProxy=newMapperProxy (sqlSession,mapperInterface,methodCache); returnnewInstance(mapperProxy); }
6.找到MapperProxy类,发现其确实实现了JDK动态代理必须实现的接口InvocationHandler,所以我们重点关注invoke()方法,这里看到在invoke方法里先获取MapperMethod类,然后调用mapperMethod.execute(),所以我们继续查看MapperMethod类的execute方法。
publicclassMapperProxyimplementsInvocationHandler,Serializable{ privatestaticfinallongserialVersionUID=-6424540398559729838L; privatefinalSqlSessionsqlSession; privatefinalClass mapperInterface; privatefinalMap methodCache; publicMapperProxy(SqlSessionsqlSession,Class mapperInterface,Map methodCache){ this.sqlSession=sqlSession; this.mapperInterface=mapperInterface; this.methodCache=methodCache; } @Override publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{ try{ if(Object.class.equals(method.getDeclaringClass())){ returnmethod.invoke(this,args); }elseif(isDefaultMethod(method)){ returninvokeDefaultMethod(proxy,method,args); } }catch(Throwablet){ throwExceptionUtil.unwrapThrowable(t); } finalMapperMethodmapperMethod=cachedMapperMethod(method); returnmapperMethod.execute(sqlSession,args); } privateMapperMethodcachedMapperMethod(Methodmethod){ MapperMethodmapperMethod=methodCache.get(method); if(mapperMethod==null){ mapperMethod=newMapperMethod(mapperInterface,method,sqlSession.getConfiguration()); methodCache.put(method,mapperMethod); } returnmapperMethod; } @UsesJava7 privateObjectinvokeDefaultMethod(Objectproxy,Methodmethod,Object[]args) throwsThrowable{ finalConstructor constructor=MethodHandles.Lookup.class .getDeclaredConstructor(Class.class,int.class); if(!constructor.isAccessible()){ constructor.setAccessible(true); } finalClass>declaringClass=method.getDeclaringClass(); returnconstructor .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE|MethodHandles.Lookup.PROTECTED |MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.PUBLIC) .unreflectSpecial(method,declaringClass).bindTo(proxy).invokeWithArguments(args); } /** *Backportofjava.lang.reflect.Method#isDefault() */ privatebooleanisDefaultMethod(Methodmethod){ return((method.getModifiers() &(Modifier.ABSTRACT|Modifier.PUBLIC|Modifier.STATIC))==Modifier.PUBLIC) &&method.getDeclaringClass().isInterface(); } }
7.找到类MapperMethod类的execute方法,发现execute中通过调用本类中的其他方法获取并封装返回结果,我们来看一下MapperMethod整个类。
publicObjectexecute(SqlSessionsqlSession,Object[]args){ Objectresult; switch(command.getType()){ caseINSERT:{ Objectparam=method.convertArgsToSqlCommandParam(args); result=rowCountResult(sqlSession.insert(command.getName(),param)); break; } caseUPDATE:{ Objectparam=method.convertArgsToSqlCommandParam(args); result=rowCountResult(sqlSession.update(command.getName(),param)); break; } caseDELETE:{ Objectparam=method.convertArgsToSqlCommandParam(args); result=rowCountResult(sqlSession.delete(command.getName(),param)); break; } caseSELECT: if(method.returnsVoid()&&method.hasResultHandler()){ executeWithResultHandler(sqlSession,args); result=null; }elseif(method.returnsMany()){ result=executeForMany(sqlSession,args); }elseif(method.returnsMap()){ result=executeForMap(sqlSession,args); }elseif(method.returnsCursor()){ result=executeForCursor(sqlSession,args); }else{ Objectparam=method.convertArgsToSqlCommandParam(args); result=sqlSession.selectOne(command.getName(),param); } break; caseFLUSH: result=sqlSession.flushStatements(); break; default: thrownewBindingException("Unknownexecutionmethodfor:"+command.getName()); } if(result==null&&method.getReturnType().isPrimitive()&&!method.returnsVoid()){ thrownewBindingException("Mappermethod'"+command.getName() +"attemptedtoreturnnullfromamethodwithaprimitivereturntype("+method.getReturnType()+")."); } returnresult; }
8.MapperMethod类是整个代理机制的核心类,对SqlSession中的操作进行了封装使用。
该类里有两个内部类SqlCommand和MethodSignature。SqlCommand用来封装CRUD操作,也就是我们在xml中配置的操作的节点。每个节点都会生成一个MappedStatement类。
MethodSignature用来封装方法的参数以及返回类型,在execute的方法中我们发现在这里又回到了SqlSession中的接口调用,和我们自己实现UerDao接口的方式中直接用SqlSession对象调用DefaultSqlSession的实现类的方法是一样的,经过一大圈的代理又回到了原地,这就是整个动态代理的实现过程了。
publicclassMapperMethod{ privatefinalSqlCommandcommand; privatefinalMethodSignaturemethod; publicMapperMethod(Class>mapperInterface,Methodmethod,Configurationconfig){ this.command=newSqlCommand(config,mapperInterface,method); this.method=newMethodSignature(config,mapperInterface,method); } publicObjectexecute(SqlSessionsqlSession,Object[]args){ Objectresult; switch(command.getType()){ caseINSERT:{ Objectparam=method.convertArgsToSqlCommandParam(args); result=rowCountResult(sqlSession.insert(command.getName(),param)); break; } caseUPDATE:{ Objectparam=method.convertArgsToSqlCommandParam(args); result=rowCountResult(sqlSession.update(command.getName(),param)); break; } caseDELETE:{ Objectparam=method.convertArgsToSqlCommandParam(args); result=rowCountResult(sqlSession.delete(command.getName(),param)); break; } caseSELECT: if(method.returnsVoid()&&method.hasResultHandler()){ executeWithResultHandler(sqlSession,args); result=null; }elseif(method.returnsMany()){ result=executeForMany(sqlSession,args); }elseif(method.returnsMap()){ result=executeForMap(sqlSession,args); }elseif(method.returnsCursor()){ result=executeForCursor(sqlSession,args); }else{ Objectparam=method.convertArgsToSqlCommandParam(args); result=sqlSession.selectOne(command.getName(),param); } break; caseFLUSH: result=sqlSession.flushStatements(); break; default: thrownewBindingException("Unknownexecutionmethodfor:"+command.getName()); } if(result==null&&method.getReturnType().isPrimitive()&&!method.returnsVoid()){ thrownewBindingException("Mappermethod'"+command.getName() +"attemptedtoreturnnullfromamethodwithaprimitivereturntype("+method.getReturnType()+")."); } returnresult; } privateObjectrowCountResult(introwCount){ finalObjectresult; if(method.returnsVoid()){ result=null; }elseif(Integer.class.equals(method.getReturnType())||Integer.TYPE.equals(method.getReturnType())){ result=rowCount; }elseif(Long.class.equals(method.getReturnType())||Long.TYPE.equals(method.getReturnType())){ result=(long)rowCount; }elseif(Boolean.class.equals(method.getReturnType())||Boolean.TYPE.equals(method.getReturnType())){ result=rowCount>0; }else{ thrownewBindingException("Mappermethod'"+command.getName()+"'hasanunsupportedreturntype:"+method.getReturnType()); } returnresult; } privatevoidexecuteWithResultHandler(SqlSessionsqlSession,Object[]args){ MappedStatementms=sqlSession.getConfiguration().getMappedStatement(command.getName()); if(void.class.equals(ms.getResultMaps().get(0).getType())){ thrownewBindingException("method"+command.getName() +"needseithera@ResultMapannotation,a@ResultTypeannotation," +"oraresultTypeattributeinXMLsoaResultHandlercanbeusedasaparameter."); } Objectparam=method.convertArgsToSqlCommandParam(args); if(method.hasRowBounds()){ RowBoundsrowBounds=method.extractRowBounds(args); sqlSession.select(command.getName(),param,rowBounds,method.extractResultHandler(args)); }else{ sqlSession.select(command.getName(),param,method.extractResultHandler(args)); } } privateObjectexecuteForMany(SqlSessionsqlSession,Object[]args){ List result; Objectparam=method.convertArgsToSqlCommandParam(args); if(method.hasRowBounds()){ RowBoundsrowBounds=method.extractRowBounds(args); result=sqlSession. selectList(command.getName(),param,rowBounds); }else{ result=sqlSession. selectList(command.getName(),param); } //issue#510Collections&arrayssupport if(!method.getReturnType().isAssignableFrom(result.getClass())){ if(method.getReturnType().isArray()){ returnconvertToArray(result); }else{ returnconvertToDeclaredCollection(sqlSession.getConfiguration(),result); } } returnresult; } private Cursor executeForCursor(SqlSessionsqlSession,Object[]args){ Cursor result; Objectparam=method.convertArgsToSqlCommandParam(args); if(method.hasRowBounds()){ RowBoundsrowBounds=method.extractRowBounds(args); result=sqlSession. selectCursor(command.getName(),param,rowBounds); }else{ result=sqlSession. selectCursor(command.getName(),param); } returnresult; } private ObjectconvertToDeclaredCollection(Configurationconfig,List list){ Objectcollection=config.getObjectFactory().create(method.getReturnType()); MetaObjectmetaObject=config.newMetaObject(collection); metaObject.addAll(list); returncollection; } @SuppressWarnings("unchecked") private ObjectconvertToArray(List list){ Class>arrayComponentType=method.getReturnType().getComponentType(); Objectarray=Array.newInstance(arrayComponentType,list.size()); if(arrayComponentType.isPrimitive()){ for(inti=0;i Map executeForMap(SqlSessionsqlSession,Object[]args){ Map result; Objectparam=method.convertArgsToSqlCommandParam(args); if(method.hasRowBounds()){ RowBoundsrowBounds=method.extractRowBounds(args); result=sqlSession. selectMap(command.getName(),param,method.getMapKey(),rowBounds); }else{ result=sqlSession. selectMap(command.getName(),param,method.getMapKey()); } returnresult; } publicstaticclassParamMap extendsHashMap { privatestaticfinallongserialVersionUID=-2212268410512043556L; @Override publicVget(Objectkey){ if(!super.containsKey(key)){ thrownewBindingException("Parameter'"+key+"'notfound.Availableparametersare"+keySet()); } returnsuper.get(key); } } publicstaticclassSqlCommand{ privatefinalStringname; privatefinalSqlCommandTypetype; publicSqlCommand(Configurationconfiguration,Class>mapperInterface,Methodmethod){ finalStringmethodName=method.getName(); finalClass>declaringClass=method.getDeclaringClass(); MappedStatementms=resolveMappedStatement(mapperInterface,methodName,declaringClass, configuration); if(ms==null){ if(method.getAnnotation(Flush.class)!=null){ name=null; type=SqlCommandType.FLUSH; }else{ thrownewBindingException("Invalidboundstatement(notfound):" +mapperInterface.getName()+"."+methodName); } }else{ name=ms.getId(); type=ms.getSqlCommandType(); if(type==SqlCommandType.UNKNOWN){ thrownewBindingException("Unknownexecutionmethodfor:"+name); } } } publicStringgetName(){ returnname; } publicSqlCommandTypegetType(){ returntype; } privateMappedStatementresolveMappedStatement(Class>mapperInterface,StringmethodName, Class>declaringClass,Configurationconfiguration){ StringstatementId=mapperInterface.getName()+"."+methodName; if(configuration.hasStatement(statementId)){ returnconfiguration.getMappedStatement(statementId); }elseif(mapperInterface.equals(declaringClass)){ returnnull; } for(Class>superInterface:mapperInterface.getInterfaces()){ if(declaringClass.isAssignableFrom(superInterface)){ MappedStatementms=resolveMappedStatement(superInterface,methodName, declaringClass,configuration); if(ms!=null){ returnms; } } } returnnull; } } publicstaticclassMethodSignature{ privatefinalbooleanreturnsMany; privatefinalbooleanreturnsMap; privatefinalbooleanreturnsVoid; privatefinalbooleanreturnsCursor; privatefinalClass>returnType; privatefinalStringmapKey; privatefinalIntegerresultHandlerIndex; privatefinalIntegerrowBoundsIndex; privatefinalParamNameResolverparamNameResolver; publicMethodSignature(Configurationconfiguration,Class>mapperInterface,Methodmethod){ TyperesolvedReturnType=TypeParameterResolver.resolveReturnType(method,mapperInterface); if(resolvedReturnTypeinstanceofClass>){ this.returnType=(Class>)resolvedReturnType; }elseif(resolvedReturnTypeinstanceofParameterizedType){ this.returnType=(Class>)((ParameterizedType)resolvedReturnType).getRawType(); }else{ this.returnType=method.getReturnType(); } this.returnsVoid=void.class.equals(this.returnType); this.returnsMany=(configuration.getObjectFactory().isCollection(this.returnType)||this.returnType.isArray()); this.returnsCursor=Cursor.class.equals(this.returnType); this.mapKey=getMapKey(method); this.returnsMap=(this.mapKey!=null); this.rowBoundsIndex=getUniqueParamIndex(method,RowBounds.class); this.resultHandlerIndex=getUniqueParamIndex(method,ResultHandler.class); this.paramNameResolver=newParamNameResolver(configuration,method); } publicObjectconvertArgsToSqlCommandParam(Object[]args){ returnparamNameResolver.getNamedParams(args); } publicbooleanhasRowBounds(){ returnrowBoundsIndex!=null; } publicRowBoundsextractRowBounds(Object[]args){ returnhasRowBounds()?(RowBounds)args[rowBoundsIndex]:null; } publicbooleanhasResultHandler(){ returnresultHandlerIndex!=null; } publicResultHandlerextractResultHandler(Object[]args){ returnhasResultHandler()?(ResultHandler)args[resultHandlerIndex]:null; } publicStringgetMapKey(){ returnmapKey; } publicClass>getReturnType(){ returnreturnType; } publicbooleanreturnsMany(){ returnreturnsMany; } publicbooleanreturnsMap(){ returnreturnsMap; } publicbooleanreturnsVoid(){ returnreturnsVoid; } publicbooleanreturnsCursor(){ returnreturnsCursor; } privateIntegergetUniqueParamIndex(Methodmethod,Class>paramType){ Integerindex=null; finalClass>[]argTypes=method.getParameterTypes(); for(inti=0;i 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。