本文主要内容:大多数框架都支持插件,用户可以通过编写插件来扩展自己的功能,Mybatis也不例外。Mybatis中最著名的是PageHelper分页插件。让我们先使用这个分页插件。如何集成分页插件Spring-Boot+Mybatis+PageHelper。引入pom依赖com.github.pagehelperpagehelper-spring-boot-starter1.2.3配置分页插件配置项pagehelper:helperDialect:mysqlreasonable:truesupportMethodsArguments:trueparams:count=countSqlservice接口代码PageInfoselectUsersByName(intpageIndex,intpageSize);服务实现类代码@OverridepublicPageInfoselectUsersByName(intpageIndex,intpageSize){PageHelper.startPageSize){PageHelper.startPageSize)xpage(List>users=userMapper.selectUsersByName(null);returnnewPageInfo(users);}映射器代码select*fromm_user`name`=#{userName}ListselectUsersByName(@Param("userName")StringuserName);控制器中的代码@GetMapping("/user/name")publicPageInfoselectUsersByName(intpageIndex,intpageSize){returnuserService.selectUsersByName(pageIndex,pageSize);}然后我们访问http://localhost:9002/user/name?pageIndex=1&pageSize=10输出结果:输出重要项描述:pageNum:当前页码pageSize:每页数。list:就是我们返回的业务数据。total:总数据。hasNextPage:是否有下一页。我们在看输出的SQL:发现实际上执行了两条SQL:count和limit。猜猜分页插件的实现1.这个分页插件无非是在我们的查询条件上拼接了一个limit和一个count查询。2、我们这里使用Mysql作为数据库。如果是Oracle,那么就不是限制了,所以这里给出多数据库的解决方案。3.拦截并在插件前面做sql及相关处理。根据官网的快速启动插件,这里引用官网的一段话:MyBatisallowsyoutointerceptcallsatacertainpointoftheexecutionofthemappingstatement。默认情况下,MyBatis允许插件拦截方法调用包括:batch,update,query)这些类中方法的详细信息可以通过查看各个方法的签名,或者直接查看MyBatis分发包中的源码找到。如果您想做的不仅仅是监视方法调用,那么您最好很好地理解您正在覆盖的方法的行为。因为当试图修改或覆盖现有方法的行为时,很可能会破坏MyBatis的核心模块。这些是较低级别的类和方法,因此在使用插件时要小心。通过MyBatis提供的强大机制,使用插件非常简单,只需要实现Interceptor接口并指定你要拦截的方法签名即可。然后我们尝试按照官方写一个插件。自定义插件@Intercepts({@Signature(type=Executor.class,method="update",args={MappedStatement.class,Object.class})})publicclassTianPluginimplementsInterceptor{privatePropertiesproperties=newProperties();@OverridepublicObjectintercept(Invocationinvocation)throwsThrowable{System.out.println("一个老挝人写的Mybatis插件--start");ObjectreturnObject=invocation.proceed();System.out.println("一个老挝人写的Mybatis插件--end");返回返回对象;}}然后将插件类注入到容器中。这里的定制完全是官网给出的案例。看到来自自定义插件类的更新,我们猜测必须执行更新才会被拦截。访问之前的代码:http://localhost:9002/updateUser成功。这是大家刚开始学习动态代理的时候都会想到的,不就是在要调用的方法前后做点什么吗?Mybatis插件确实是这样的。我们来分析一下官方的段落和我们自定义的插件。分析首先,我们自定义的插件一定是针对以下四个类和方法的。Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)ParameterHandler(getParameterObject,setParameters)ResultSetHandler(handleResultSets,handleOutputParameters)StatementHandler(prepare,parameterize,batch,update,Myquery)其次要实现Interbatis。Interceptor中三个方法的作用:intercept():执行拦截内容的地方,例如:调用某类方法前后做一些处理,简单的打印log。plugin():决定是否触发intercept()方法。setProperties():将我们配置的property参数传递给自定义拦截器(这个可以暂时忽略,后面我们会写一个比较完整的插件,你就明白它是干什么的了)。插件方法defaultObjectplugin(Objecttarget){returnPlugin.wrap(target,this);}是默认的实现方法,调用了Plugin.wrap()方法。publicclassPluginimplementsInvocationHandler{privateObjecttarget;privateInterceptorinterceptor;privateMap,Set>signatureMap;privatePlugin(Objecttarget,Interceptorinterceptor,Map,Set>signatureMap){this.target=target;this.interceptor=拦截器;this.signatureMap=signatureMap;}publicstaticObjectwrap(Objecttarget,Interceptorinterceptor){Map,Set>signatureMap=getSignatureMap(interceptor);Class>type=target.getClass();Class>[]interfaces=getAllInterfaces(type,signatureMap);if(interfaces.length>0){//创建JDK动态代理对象returnProxy.newProxyInstance(type.getClassLoader(),interfaces,newPlugin(target,interceptor,signatureMap));}returntarget;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{try{Setmethods=signatureMap.get(method.getDeclaringClass());//判定是否是需要截取的方法(很重要)if(方法!=null&&方法。包含(方法)){//回调拦截()方法}}//...省略其他无关代码}这不就是一个JDK动态代理吗?Map所以,我们不要总说反射性能差,是因为你没有缓存像Mybatis这样的对象的反射结果这个注解对于判断是否需要拦截非常重要。一旦被忽略,不知道Mybatis是如何判断是否执行截获的内容的。记住。Plugin.wrap(target,this)是做什么的?利用JDK的动态代理为目标对象创建委托代理对象,实现方法拦截和增强。它将回调intercept()方法。为什么要写注解?注释是什么意思?我们自定义的插件上面有一堆注解,不用怕。Mybatis规定插件必须写Annotation注解,这是强制的,不是可选的。@Intercepts({@Signature(type=Executor.class,method="update",args={MappedStatement.class,Object.class})})publicclassTianPluginimplementsInterceptor{@Intercepts注解:加载一个@Signature列表,一个@Signature其实就是需要拦截的方法包装器。那么,如果一个拦截器需要拦截多个方法,那自然是一个@Signature列表。type=Executor.class,method="update",args={MappedStatement.class,Object.class}解释:拦截Executor接口中的query()方法,参数类型为args列表。那么如果要拦截多个方法怎么办呢?@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfaceIntercepts{Signature[]value();}这个很简单,我们可以在@Intercepts注解中存放多个@Signature注解。比如之前的分页插件中拦截了多个方法。为什么要拦截这两种查询方法?因为Executor中有两个查询方法。总结一下:Mybatis规定必须使用@Intercepts注解。@Intercepts注解中可以添加多个类和多个方法。注意方法名和参数类型个数必须对应。本文转载自微信公众号《Java后端技术全栈》,可通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。