Mybatis动态代理解析
1、引言
Mybatis作为一种持久层框架,它支持自定义SQL、存储过程以及高级映射。里面大量使用了代理技术,这篇文章将从以下几个问题对Mybatis中的代理进行解析。
MybatisMapper接口在无实现类的情况下,如何实现的动态代理。
JDK动态代理为什么不能对非接口类进行代理。2、JDK动态代理2。1、基于接口的动态代理
代码实例publicinterfaceStudentDao{publicvoidsayHello();}publicclassStudentDaoImplimplementsStudentDao{OverridepublicvoidsayHello(){System。out。println(你好);}}publicclassProxyHandlerimplementsInvocationHandler{privateObjecttarget;publicProxyHandler(Objecttarget){this。targettarget;}OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object〔〕args)throwsThrowable{System。out。println(调用代理类);returnmethod。invoke(target,args);}publicstaticvoidmain(String〔〕args){StudentDaostudentDaonewStudentDaoImpl();StudentDaoproxy(StudentDao)Proxy。newProxyInstance(studentDao。getClass()。getClassLoader(),studentDao。getClass()。getInterfaces(),newProxyHandler(studentDao));proxy。sayHello();}}
上述代码运行后,可以发现对应proxy对象有一个特殊标记(Proxy拼接一个数字),这代表该对象的类型是一个代理对象。那么这个代理类是如何生成的,这些标记是如何构建的,下面我们走入Proxy。newProxyInstance里面去一瞅真相。
newProxyInstance
该方法主要是生成代理类,其内部主要的流程为getProxyClass0与newInstance,其时序图如下所示:
1。getProxyClass0会创建代理类
2。newInstance会绑定代理类和增强类的关系
3、Mybatis中的动态代理
Mybatis未出现之前,开发人员需要在每个mapper层的实现类中重复进行如下操作,对数据库进行增删查改。装载Mysql驱动Class。forName(driveName);获取连接conDriverManager。getConnection(url,user,pass);创建StatementStatementstatecon。createStatement();构建SQL语句StringstuQuerySqlStrSELECTFROMSTUDENT;执行SQL返回结果ResultSetresultstate。executeQuery(stuQuerySqlStr);
Mybatis针对该痛点,利用JDK动态代理对以上逻辑进行封装,使用者只需要自定义Mapper和xml文件,利用注解或者xml的形式定义SQL语句,项目启动时通过解析器解析SQL语句组装为Java中的对象。
但是日常使用Mybatis过程中我们都是直接定义的mapper接口,没有定义其实现类,那么JDK动态代理是如何代理未实现的接口呐,和上文具有实现类的接口代理有什么区别?
未实现类接口的动态代理publicinterfaceSubject{StringsayHello();}publicclassProxyInvocationHandlerimplementsInvocationHandler{OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object〔〕args)throwsThrowable{System。out。println(进入代理调用处理器);returnsuccess;}}
可以发现对于未实现类接口的动态代理,其InvocationHandler并未执行代理类的方法,而是执行完增强方法后就返回InvocationHandler的返回值;而具有实现类接口的动态代理则会执行代理类方法并且返回其执行结果。
那么,Mybatis对于maaper接口的代理方法是怎样的呐,其InvocationHandler的具体实现细节是什么?我们接着分析。
MapperProxyFactory
该类是通过工厂模式去生成mapper代理类,其中mapperInterface是等待生成代理对象的接口。publicclassMapperProxyFactoryT{privatefinalClassTmapperInterface;privatefinalMapMethod,MapperMethodInvokermethodCachenewConcurrentHashMap();publicMapperProxyFactory(ClassTmapperInterface){this。mapperInterfacemapperInterface;}publicClassTgetMapperInterface(){returnmapperInterface;}publicMapMethod,MapperMethodInvokergetMethodCache(){returnmethodCache;}SuppressWarnings(unchecked)protectedTnewInstance(MapperProxyTmapperProxy){return(T)Proxy。newProxyInstance(mapperInterface。getClassLoader(),newClass〔〕{mapperInterface},mapperProxy);}publicTnewInstance(SqlSessionsqlSession){finalMapperProxyTmapperProxynewMapperProxy(sqlSession,mapperInterface,methodCache);returnnewInstance(mapperProxy);}}
这里我们重点关注该类中的两个newInstance方法,由于mapper是一个接口,最终代理类的调用是执行的InvocationHandler中的invoke方法,所以最终的mybatis封装mapper的操作放在MapperProxy中。我们接着看里面的细节。
MapperProxy
由于该类代码较多,我们这里只关注封装部分的方法逻辑,该部分逻辑获取对应mapper中的方法的增强实现,并调用其invoke方法。MapperMethod类是整个代理机制的核心类,对SqlSession中的操作进行了封装使用。该类里有两个内部类SqlCommand和MethodSignature。SqlCommand用来封装CRUD操作,也就是我们在xml中配置的操作的节点。每个节点都会生成一个MappedStatement类。MethodSignature用来封装方法的参数以及返回类型privateMapperMethodInvokercachedInvoker(Methodmethod)throwsThrowable{try{Aworkaroundforhttps:bugs。openjdk。java。netbrowseJDK8161372ItshouldberemovedoncethefixisbackportedtoJava8orMyBatisdropsJava8support。Seegh1929MapperMethodInvokerinvokermethodCache。get(method);if(invoker!null){returninvoker;}returnmethodCache。computeIfAbsent(method,m{if(m。isDefault()){try{if(privateLookupInMethodnull){returnnewDefaultMethodInvoker(getMethodHandleJava8(method));}else{returnnewDefaultMethodInvoker(getMethodHandleJava9(method));}}catch(IllegalAccessExceptionInstantiationExceptionInvocationTargetExceptionNoSuchMethodExceptione){thrownewRuntimeException(e);}}else{returnnewPlainMethodInvoker(newMapperMethod(mapperInterface,method,sqlSession。getConfiguration()));}});}catch(RuntimeExceptionre){Throwablecausere。getCause();throwcausenull?re:cause;}}
MapperMethod
该类是整个代理机制的核心类,对SqlSession中的操作进行了封装使用。从而实现了CRUD,其最后还是回到SqlSession中进行调用数据库。ublicObjectexecute(SqlSessionsqlSession,Object〔〕args){Objectresult;switch(command。getType()){caseINSERT:{Objectparammethod。convertArgsToSqlCommandParam(args);resultrowCountResult(sqlSession。insert(command。getName(),param));break;}caseUPDATE:{Objectparammethod。convertArgsToSqlCommandParam(args);resultrowCountResult(sqlSession。update(command。getName(),param));break;}caseDELETE:{Objectparammethod。convertArgsToSqlCommandParam(args);resultrowCountResult(sqlSession。delete(command。getName(),param));break;}caseSELECT:if(method。returnsVoid()method。hasResultHandler()){executeWithResultHandler(sqlSession,args);resultnull;}elseif(method。returnsMany()){resultexecuteForMany(sqlSession,args);}elseif(method。returnsMap()){resultexecuteForMap(sqlSession,args);}elseif(method。returnsCursor()){resultexecuteForCursor(sqlSession,args);}else{Objectparammethod。convertArgsToSqlCommandParam(args);resultsqlSession。selectOne(command。getName(),param);if(method。returnsOptional()(resultnull!method。getReturnType()。equals(result。getClass()))){resultOptional。ofNullable(result);}}break;caseFLUSH:resultsqlSession。flushStatements();break;default:thrownewBindingException(Unknownexecutionmethodfor:command。getName());}if(resultnullmethod。getReturnType()。isPrimitive()!method。returnsVoid()){thrownewBindingException(Mappermethodcommand。getName()attemptedtoreturnnullfromamethodwithaprimitivereturntype(method。getReturnType())。);}returnresult;}
资生堂新七色蜜粉好用吗?一盒多用高颜值代表资生堂新七色蜜粉,七色蜜粉本来是资生堂的老款,但是2018年今年又出了新款,这款粉饼颜值逆天,有多种用法,下面5号网小编带大家来看一下资生堂新七色蜜粉好用吗?资生堂新七色……
嘉娜宝这个牌子怎么样?嘉娜宝彩妆好用吗?嘉娜宝是日本人气美妆品牌,仅次于资深堂后一位,是日本第二大化妆品牌。那么不少人困惑,嘉娜宝彩妆好用吗?关于,嘉娜宝这个牌子怎么样?嘉娜宝彩妆好用吗?5号网小编来为您一一解答!……
楼市筑底态势明显黑暗中微见曙光拿地同比几近腰斩,开工面积降幅远超竣工,个贷、开发贷跌幅仍超两成6月15日,国家统计局发布的房地产相关数据依然低迷,但黑暗中微见曙光:5月单月,新房销售出现年内首次环比增长、开……
李晟京兰芝口红色号李晟京同款口红推荐李晟京最近在举重精灵中的表演可谓是十分出色呀,大家是否还记得剧中她涂抹兰芝双色口红的场景呢?今天5号网小编就要为大家介绍一下,李晟京兰芝口红色号是什么?李晟京同款口红推荐有哪些……
toofaced爱心眼影盘试色toofacedlove眼影盘这次给大家介绍的是很受欢迎的toofaced爱心眼影盘,里面还配有一只眼线笔,配色自然,值得入手,下面为大家介绍toofacedlove爱心眼影盘试色toofaced爱心……
女性养生的好处女性保养的好处女性注意保健可以给身体带来好处,包括延缓衰老,保持好身材,减少疾病的发生。。。这种受益是由内而外的,不是单一的,而是全方位的。众所周知,养生和保健对我……
科学家解开跨越几个世纪的谜团图片来源:SachihiroMatsunaga,东京大学上部面板显示非Rabl配置。洋红色着丝粒分散在绿色的原子核中。下面的面板显示了Rabl配置。着丝粒在细胞核中分布不……
怎么自制护发素5款自制护发素天然配方市面上的护发产品难免含各种化学物质,想避免化学物质刺激皮肤,同时节省金钱?不如尝试用天然材料自制护发素吧!5款自制护发素天然配方1。苹果醋材料包括切了一半的柠……
自制防晒霜能放多久自制防晒霜配方说明夏季我们需要防晒产品,防晒也是一年四季最必须的护肤方式,除了可以购买防晒产品之外,我们也可以自己制作防晒霜哦,大家一定想知道自制防晒霜的方法,下面5号网小编带大家来看一下自制防……
口红的正确涂法口红的正确涂抹方式口红是每个女性朋友包包必备的一种化妆品,都说女人第一个拥有的化妆品就是口红,涂了口红的女生更加富有魅力,我们平时都会经常使用口红,那么下面就由5号网的小编来为大家介绍口红的正确……
每次洗头大把掉发?提醒平时远离这3物,或能让头发变好导语:相信每个人都想拥有一头乌黑亮丽的秀发,不仅可以提升自身形象,也能让自己变得更加自信。然而现实总是那么不尽人意,随着生活节奏的加快,人们的压力变得越来越大,所以有很多……
这类零食或在偷偷摧毁你的胰岛,医生不管男女老少,都要少吃导语:当前大家不断的改善饮食方面问题,但是不注重饮食的规律和结构,会使三高发生,其中糖尿病困扰着大家,近年来,越来越多的人出现糖尿病问题,而且呈现年轻化趋势。出现糖尿病后……