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(Class>mapperInterface,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,Class>mapperInterface,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;
//返回值类型
privatefinalClass>returnType;
//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 |
|