配色: 字号:
Mybatis接口编程原理分析
2016-09-19 | 阅:  转:  |  分享 
  
Mybatis接口编程原理分析

Mybatis接口编程相关的类主要有MapperProxyFactory、MapperProxy、MapperMethod和MapperRegister四个类:

MapperProxyFactory:通过类名我们可以猜到这是一个MapperProxy的工厂类,用于创建MapperProxy的,通过函数newInstance(SqlSessionsqlSession)来创建MapperProxy的代理类。

源码如下:

[java]viewplaincopyprint?在CODE上查看代码片派生到我的代码片

//这个类赋值创建具体mapper接口代理对象的工厂

publicclassMapperProxyFactory{



//具体Mapper接口的class对象

privatefinalClassmapperInterface;

//该接口下面的缓存,key是方法对象,value是对接口中方法对象的封装

privatefinalMapmethodCache=newConcurrentHashMap();



publicMapperProxyFactory(ClassmapperInterface){

this.mapperInterface=mapperInterface;

}



publicClassgetMapperInterface(){

returnmapperInterface;

}



publicMapgetMethodCache(){

returnmethodCache;

}



@SuppressWarnings("unchecked")

protectedTnewInstance(MapperProxymapperProxy){

//创建一个代理类并返回

return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{mapperInterface},mapperProxy);

}



publicTnewInstance(SqlSessionsqlSession){

//在这里创建MapperProxy对象,这个类实现了JDK的动态代理接口InvocationHandler

finalMapperProxymapperProxy=newMapperProxy(sqlSession,mapperInterface,methodCache);

//调用上面的方法,返回一个接口的代理类

returnnewInstance(mapperProxy);

}



}



MapperProxy:通过类名可以猜到这个类为一个代理类,它实现了JDK动态代理接口InvocationHandler,通过查看源码发现它又不像一个真正的代理类,它一般不会真正执行被代理类的函数方法,只是在执行被代理类函数方法时来执行MapperMethod类的execute方法,具体逻辑详看invoke函数

源码如下:

[java]viewplaincopyprint?在CODE上查看代码片派生到我的代码片

//实现了JDK动态代理的接口,InvocationHandler

//在invoke方法中实现了代理方法调用的细节

publicclassMapperProxyimplementsInvocationHandler,Serializable{



privatestaticfinallongserialVersionUID=-6424540398559729838L;

//sqlSession

privatefinalSqlSessionsqlSession;

//接口的类型对象

privatefinalClassmapperInterface;

//接口中方法的缓存,由MapperProxyFactory传递过来

privatefinalMapmethodCache;



//构造函数

publicMapperProxy(SqlSessionsqlSession,ClassmapperInterface,MapmethodCache){

this.sqlSession=sqlSession;

this.mapperInterface=mapperInterface;

this.methodCache=methodCache;

}

//接口代理对象所有的方法调用都会调用该方法

@Override

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{

//判断是不是基础方法比如toString、hashCode等,这些方法直接调用不需要处理

if(Object.class.equals(method.getDeclaringClass())){

try{

returnmethod.invoke(this,args);

}catch(Throwablet){

throwExceptionUtil.unwrapThrowable(t);

}

}

//进行缓存

finalMapperMethodmapperMethod=cachedMapperMethod(method);

//调用mapperMethod.execute核心的地方就在这个方法里,这个方法对才是真正对SqlSession进行的包装调用

returnmapperMethod.execute(sqlSession,args);

}

//缓存处理

privateMapperMethodcachedMapperMethod(Methodmethod){

MapperMethodmapperMethod=methodCache.get(method);

if(mapperMethod==null){

mapperMethod=newMapperMethod(mapperInterface,method,sqlSession.getConfiguration());

methodCache.put(method,mapperMethod);

}

returnmapperMethod;

}



}

MapperMethod:它是mybatis接口编程的核心,它封装了对sqlsession的操作,mybatis接口编程的实质还是sqlsession进行的CRUD操作

通过分析下面的源码我们可以了解到mybatis接口编程的实质还是sqlsession进行CRUD操作,接口编程不过是通过代理获得接口和函数名作为xml文件中的映射ID,获得接口函数的参数值作为sqlsession操作的参数值而已,所以mybatis的接口编程原理还是比较简单的。

源码如下:

[java]viewplaincopyprint?

/

@authorClintonBegin

@authorEduardoMacarron

@authorLasseVoss

/

//这个类是整个代理机制的核心类,对Sqlsession当中的操作进行了封装

publicclassMapperMethod{

//一个内部封封装了SQL标签的类型insertupdatedeleteselect

privatefinalSqlCommandcommand;

//一个内部类封装了方法的参数信息返回类型信息等

privatefinalMethodSignaturemethod;



//构造参数

publicMapperMethod(ClassmapperInterface,Methodmethod,Configurationconfig){

this.command=newSqlCommand(config,mapperInterface,method);

this.method=newMethodSignature(config,method);

}



//这个方法是对SqlSession的包装调用

publicObjectexecute(SqlSessionsqlSession,Object[]args){

//定义返回结果

Objectresult;

//如果是INSERT操作

if(SqlCommandType.INSERT==command.getType()){

//处理参数

Objectparam=method.convertArgsToSqlCommandParam(args);

//调用sqlSession的insert方法

result=rowCountResult(sqlSession.insert(command.getName(),param));

//如果是UPDATE操作同上

}elseif(SqlCommandType.UPDATE==command.getType()){

Objectparam=method.convertArgsToSqlCommandParam(args);

result=rowCountResult(sqlSession.update(command.getName(),param));

//如果是DELETE操作同上

}elseif(SqlCommandType.DELETE==command.getType()){

Objectparam=method.convertArgsToSqlCommandParam(args);

result=rowCountResult(sqlSession.delete(command.getName(),param));

//如果是SELECT操作那么情况会多一些但是也都和sqlSession的查询方法一一对应

}elseif(SqlCommandType.SELECT==command.getType()){

//如果返回void并且参数有resultHandler

//则调用voidselect(Stringstatement,Objectparameter,ResultHandlerhandler);方法

if(method.returnsVoid()&&method.hasResultHandler()){

executeWithResultHandler(sqlSession,args);

result=null;

//如果返回多行结果这调用ListselectList(Stringstatement,Objectparameter);

//executeForMany这个方法调用的

}elseif(method.returnsMany()){

result=executeForMany(sqlSession,args);

//如果返回类型是MAP则调用executeForMap方法

}elseif(method.returnsMap()){

result=executeForMap(sqlSession,args);

}else{

//否则就是查询单个对象

Objectparam=method.convertArgsToSqlCommandParam(args);

result=sqlSession.selectOne(command.getName(),param);

}

}elseif(SqlCommandType.FLUSH==command.getType()){

result=sqlSession.flushStatements();

}else{

//如果全都不匹配说明mapper中定义的方法不对

thrownewBindingException("Unknownexecutionmethodfor:"+command.getName());

}

//如果返回值为空并且方法返回值类型是基础类型并且不是VOID则抛出异常

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=Integer.valueOf(rowCount);

}elseif(Long.class.equals(method.getReturnType())||Long.TYPE.equals(method.getReturnType())){

result=Long.valueOf(rowCount);

}elseif(Boolean.class.equals(method.getReturnType())||Boolean.TYPE.equals(method.getReturnType())){

result=Boolean.valueOf(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));

}

}

//返回多行结果调用sqlSession.selectList方法

privateObjectexecuteForMany(SqlSessionsqlSession,Object[]args){

Listresult;

Objectparam=method.convertArgsToSqlCommandParam(args);

//如果参数含有rowBounds则调用分页的查询

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;

}



privateObjectconvertToDeclaredCollection(Configurationconfig,Listlist){

Objectcollection=config.getObjectFactory().create(method.getReturnType());

MetaObjectmetaObject=config.newMetaObject(collection);

metaObject.addAll(list);

returncollection;

}



@SuppressWarnings("unchecked")

privateE[]convertToArray(Listlist){

E[]array=(E[])Array.newInstance(method.getReturnType().getComponentType(),list.size());

array=list.toArray(array);

returnarray;

}



privateMapexecuteForMap(SqlSessionsqlSession,Object[]args){

Mapresult;

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;

}



publicstaticclassParamMapextendsHashMap{



privatestaticfinallongserialVersionUID=-2212268410512043556L;



@Override

publicVget(Objectkey){

if(!super.containsKey(key)){

thrownewBindingException("Parameter''"+key+"''notfound.Availableparametersare"+keySet());

}

returnsuper.get(key);

}



}

//一个内部类封装了具体执行的动作

publicstaticclassSqlCommand{



//xml标签的id

privatefinalStringname;

//insertupdatedeleteselect的具体类型

privatefinalSqlCommandTypetype;



publicSqlCommand(Configurationconfiguration,ClassmapperInterface,Methodmethod){

//拿到全名接口名加上方法名

StringstatementName=mapperInterface.getName()+"."+method.getName();

MappedStatementms=null;

//获取MappedStatement对象这个对象封装了XML当中一个标签的所有信息比如下面

//

//selectfromBlogwhereid=#{id}

//

if(configuration.hasStatement(statementName)){

ms=configuration.getMappwww.shanxiwang.netedStatement(statementName);

}elseif(!mapperInterface.equals(method.getDeclaringClass())){//issue#35

StringparentStatementName=method.getDeclaringClass().getName()+"."+method.getName();

if(configuration.hasStatement(parentStatementName)){

ms=configuration.getMappedStatement(parentStatementName);

}

}

//为空抛出异常

if(ms==null){

if(method.getAnnotation(Flush.class)!=null){

name=null;

type=SqlCommandType.FLUSH;

}else{

thrownewBindingException("Invalidboundstatement(notfound):"+statementName);

}

}else{

name=ms.getId();

type=ms.getSqlCommandType();

//判断SQL标签类型未知就抛异常

if(type==SqlCommandType.UNKNOWN){

thrownewBindingException("Unknownexecutionmethodfor:"+name);

}

}

}



publicStringgetName(){

returnname;

}



publicSqlCommandTypegetType(){

returntype;

}

}

//内部类封装了接口当中方法的参数类型返回值类型等信息

publicstaticclassMethodSignature{

//是否返回多调结果

privatefinalbooleanreturnsMany;

//返回值是否是MAP

privatefinalbooleanreturnsMap;

//返回值是否是VOID

privatefinalbooleanreturnsVoid;

//返回值类型

privatefinalClassreturnType;

//mapKey

privatefinalStringmapKey;

//resultHandler类型参数的位置

privatefinalIntegerresultHandlerIndex;

//rowBound类型参数的位置

privatefinalIntegerrowBoundsIndex;

//用来存放参数信息

privatefinalSortedMapparams;

//是否存在命名参数

privatefinalbooleanhasNamedParameters;



publicMethodSignature(Configurationconfiguration,Methodmethod){

this.returnType=method.getReturnType();

this.returnsVoid=void.class.equals(this.returnType);

this.returnsMany=(configuration.getObjectFactory().isCollection(this.returnType)||this.returnType.isArray());

this.mapKey=getMapKey(method);

this.returnsMap=(this.mapKey!=null);

this.hasNamedParameters=hasNamedParams(method);

this.rowBoundsIndex=getUniqueParamIndex(method,RowBounds.class);

this.resultHandlerIndex=getUniqueParamIndex(method,ResultHandler.class);

this.params=Collections.unmodifiableSortedMap(getParams(method,this.hasNamedParameters));

}



publicObjectconvertArgsToSqlCommandParam(Object[]args){

finalintparamCount=params.size();

if(args==null||paramCount==0){

returnnull;

}elseif(!hasNamedParameters&¶mCount==1){

returnargs[params.keySet().iterator().next().intValue()];

}else{

finalMapparam=newParamMap();

inti=0;

for(Map.Entryentry:params.entrySet()){

param.put(entry.getValue(),args[entry.getKey().intValue()]);

//issue#71,addparamnamesasparam1,param2...butensurebackwardcompatibility

finalStringgenericParamName="param"+String.valueOf(i+1);

if(!param.containsKey(genericParamName)){

param.put(genericParamName,args[entry.getKey()]);

}

i++;

}

returnparam;

}

}



publicbooleanhasRowBounds(){

returnrowBoundsIndex!=null;

}



publicRowBoundsextractRowBounds(Object[]args){

returnhasRowBounds()?(RowBounds)args[rowBoundsIndex]:null;

}



publicbooleanhasResultHandler(){

returnresultHandlerIndex!=null;

}



publicResultHandlerextractResultHandler(Object[]args){

returnhasResultHandler()?(ResultHandler)args[resultHandlerIndex]:null;

}



publicStringgetMapKey(){

returnmapKey;

}



publicClassgetReturnType(){

returnreturnType;

}



publicbooleanreturnsMany(){

returnreturnsMany;

}



publicbooleanreturnsMap(){

returnreturnsMap;

}



publicbooleanreturnsVoid(){

returnreturnsVoid;

}



privateIntegergetUniqueParamIndex(Methodmethod,ClassparamType){

Integerindex=null;

finalClass[]argTypes=method.getParameterTypes();

for(inti=0;i
if(paramType.isAssignableFrom(argTypes[i])){

if(index==null){

index=i;

}else{

thrownewBindingException(method.getName()+"cannothavemultiple"+paramType.getSimpleName()+"parameters");

}

}

}

returnindex;

}



privateStringgetMapKey(Methodmethod){

StringmapKey=null;

if(Map.class.isAssignableFrom(method.getReturnType())){

finalMapKeymapKeyAnnotation=method.getAnnotation(MapKey.class);

if(mapKeyAnnotation!=null){

mapKey=mapKeyAnnotation.value();

}

}

returnmapKey;

}



privateSortedMapgetParams(Methodmethod,booleanhasNamedParameters){

finalSortedMapparams=newTreeMap();

finalClass[]argTypes=method.getParameterTypes();

for(inti=0;i
if(!RowBounds.class.isAssignableFrom(argTypes[i])&&!ResultHandler.class.isAssignableFrom(argTypes[i])){

StringparamName=String.valueOf(params.size());

if(hasNamedParameters){

paramName=getParamNameFromAnnotation(method,i,paramName);

}

params.put(i,paramName);

}

}

returnparams;

}



privateStringgetParamNameFromAnnotation(Methodmethod,inti,StringparamName){

finalObject[]paramAnnos=method.getParameterAnnotations()[i];

for(ObjectparamAnno:paramAnnos){

if(paramAnnoinstanceofParam){

paramName=((Param)paramAnno).value();

break;

}

}

returnparamName;

}



privatebooleanhasNamedParams(Methodmethod){

finalObject[][]paramAnnos=method.getParameterAnnotations();

for(Object[]paramAnno:paramAnnos){

for(ObjectaParamAnno:paramAnno){

if(aParamAnnoinstanceofParam){

returntrue;

}

}

}

returnfalse;

}



}



}

献花(0)
+1
(本文系网络学习天...首藏)