您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > Mybatis接口编程原理分析
Mybatis接口编程原理分析Mybatis接口编程相关的类主要有MapperProxyFactory、MapperProxy、MapperMethod和MapperRegister四个类:MapperProxyFactory:通过类名我们可以猜到这是一个MapperProxy的工厂类,用于创建MapperProxy的,通过函数newInstance(SqlSessionsqlSession)来创建MapperProxy的代理类。源码如下:[java]viewplaincopyprint?在CODE上查看代码片派生到我的代码片//这个类赋值创建具体mapper接口代理对象的工厂publicclassMapperProxyFactoryT{//具体Mapper接口的class对象privatefinalClassTmapperInterface;//该接口下面的缓存,key是方法对象,value是对接口中方法对象的封装privatefinalMapMethod,MapperMethodmethodCache=newConcurrentHashMapMethod,MapperMethod();publicMapperProxyFactory(ClassTmapperInterface){this.mapperInterface=mapperInterface;}publicClassTgetMapperInterface(){returnmapperInterface;}publicMapMethod,MapperMethodgetMethodCache(){returnmethodCache;}@SuppressWarnings(unchecked)protectedTnewInstance(MapperProxyTmapperProxy){//创建一个代理类并返回return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{mapperInterface},mapperProxy);}publicTnewInstance(SqlSessionsqlSession){//在这里创建MapperProxy对象,这个类实现了JDK的动态代理接口InvocationHandlerfinalMapperProxyTmapperProxy=newMapperProxyT(sqlSession,mapperInterface,methodCache);//调用上面的方法,返回一个接口的代理类returnnewInstance(mapperProxy);}}MapperProxy:通过类名可以猜到这个类为一个代理类,它实现了JDK动态代理接口InvocationHandler,通过查看源码发现它又不像一个真正的代理类,它一般不会真正执行被代理类的函数方法,只是在执行被代理类函数方法时来执行MapperMethod类的execute方法,具体逻辑详看invoke函数源码如下:[java]viewplaincopyprint?在CODE上查看代码片派生到我的代码片//实现了JDK动态代理的接口,InvocationHandler//在invoke方法中实现了代理方法调用的细节publicclassMapperProxyTimplementsInvocationHandler,Serializable{privatestaticfinallongserialVersionUID=-6424540398559729838L;//sqlSessionprivatefinalSqlSessionsqlSession;//接口的类型对象privatefinalClassTmapperInterface;//接口中方法的缓存,由MapperProxyFactory传递过来privatefinalMapMethod,MapperMethodmethodCache;//构造函数publicMapperProxy(SqlSessionsqlSession,ClassTmapperInterface,MapMethod,MapperMethodmethodCache){this.sqlSession=sqlSession;this.mapperInterface=mapperInterface;this.methodCache=methodCache;}//接口代理对象所有的方法调用都会调用该方法@OverridepublicObjectinvoke(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标签的类型insertupdatedeleteselectprivatefinalSqlCommandcommand;//一个内部类封装了方法的参数信息返回类型信息等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;//如果返回多行结果这调用EListEselectList(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.r
本文标题:Mybatis接口编程原理分析
链接地址:https://www.777doc.com/doc-2889299 .html