Mybatis接口编程原理分析.docx
- 文档编号:4913292
- 上传时间:2022-12-11
- 格式:DOCX
- 页数:17
- 大小:20.16KB
Mybatis接口编程原理分析.docx
《Mybatis接口编程原理分析.docx》由会员分享,可在线阅读,更多相关《Mybatis接口编程原理分析.docx(17页珍藏版)》请在冰豆网上搜索。
Mybatis接口编程原理分析
Mybatis接口编程原理分析
Mybatis接口编程相关的类主要有MapperProxyFactory、MapperProxy、MapperMethod和MapperRegister四个类:
MapperProxyFactory:
通过类名我们可以猜到这是一个MapperProxy的工厂类,用于创建MapperProxy的,通过函数newInstance(SqlSessionsqlSession)来创建MapperProxy的代理类。
源码如下:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
//这个类赋值创建具体mapper接口代理对象的工厂
publicclassMapperProxyFactory
//具体Mapper接口的class对象
privatefinalClass
//该接口下面的缓存,key是方法对象,value是对接口中方法对象的封装
privatefinalMap
publicMapperProxyFactory(Class
this.mapperInterface=mapperInterface;
}
publicClass
returnmapperInterface;
}
publicMap
returnmethodCache;
}
@SuppressWarnings("unchecked")
protectedTnewInstance(MapperProxy
//创建一个代理类并返回
return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{mapperInterface},mapperProxy);
}
publicTnewInstance(SqlSessionsqlSession){
//在这里创建MapperProxy对象,这个类实现了JDK的动态代理接口InvocationHandler
finalMapperProxy
//调用上面的方法,返回一个接口的代理类
returnnewInstance(mapperProxy);
}
}
MapperProxy:
通过类名可以猜到这个类为一个代理类,它实现了JDK动态代理接口InvocationHandler,通过查看源码发现它又不像一个真正的代理类,它一般不会真正执行被代理类的函数方法,只是在执行被代理类函数方法时来执行MapperMethod类的execute方法,具体逻辑详看invoke函数
源码如下:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
//实现了JDK动态代理的接口,InvocationHandler
//在invoke方法中实现了代理方法调用的细节
publicclassMapperProxy
privatestaticfinallongserialVersionUID=-6424540398559729838L;
//sqlSession
privatefinalSqlSessionsqlSession;
//接口的类型对象
privatefinalClass
//接口中方法的缓存,由MapperProxyFactory传递过来
privatefinalMap
//构造函数
publicMapperProxy(SqlSessionsqlSession,Class
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){
mand=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;
//如果返回多行结果这调用
//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方法
private
List
Objectparam=method.convertArgsToSqlCommandParam(args);
//如果参数含有rowBounds则调用分页的查询
if(method.hasRowBounds()){
RowBoundsrowBounds=method.extractRowBounds(args);
result=sqlSession.
}else{
//没有分页则调用普通查询
result=sqlSession.
}
//issue#510Collections&arrayssupport
if(!
method.getReturnType().isAssignableFrom(result.getClass())){
if(method.getReturnType().isArray()){
returnconvertToArray(result);
}else{
returnconvertToDeclaredCollection(sqlSession.getConfiguration(),result);
}
}
returnresult;
}
private
Objectcollection=config.getObjectFactory().create(method.getReturnType());
MetaObjectmetaObject=config.newMetaObject(collection);
metaObject.addAll(list);
returncollection;
}
@SuppressWarnings("unchecked")
private
E[]array=(E[])Array.newInstance(method.getReturnType().getComponentType(),list.size());
array=list.toArray(array);
returnarray;
}
private
Map
Objectparam=method.convertArgsToSqlCommandParam(args);
if(method.hasRowBounds()){
RowBoundsrowBounds=method.extractRowBounds(args);
result=sqlSession.
}else{
result=sqlSession.
}
returnresult;
}
publicstaticclassParamMap
privatestaticfinallongserialVersionUID=-2212268410512043556L;
@Override
publicVget(Objectkey){
if(!
super.containsKey(key)){
thrownewBindingException("Parameter'"+key+"'notfound.Availableparametersare"+keySet());
}
returnsuper.get(key);
}
}
//一个内部类封装了具体执行的动作
publicstaticclassSqlCommand{
//xml标签的id
privatefinalStringname;
//insertupdatedeleteselect的具体类型
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Mybatis 接口 编程 原理 分析