温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

MyBatis插件原理是什么

发布时间:2021-10-21 15:16:45 来源:亿速云 阅读:171 作者:iii 栏目:开发技术

本篇内容主要讲解“MyBatis插件原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MyBatis插件原理是什么”吧!

如何集成分页插件

Spring-Boot+Mybatis+PageHelper 。

引入pom依赖

<dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper-spring-boot-starter</artifactId>    <version>1.2.3</version> </dependency>

配置分页插件配置项

pagehelper:   helperDialect: mysql   reasonable: true   supportMethodsArguments: true   params: count=countSql

service接口代码中

PageInfo selectUsersByName(int pageIndex, int pageSize);

service实现类代码中

@Override public PageInfo selectUsersByName(int pageIndex, int pageSize) {     PageHelper.startPage(pageIndex, pageSize);     List<User> users = userMapper.selectUsersByName(null);     return new PageInfo(users); }

Mapper代码代码

<select id="selectUsersByName" resultMap="User">     select * from m_user     <where>         <if test="userName != null and userName != ''">             `name` = #{userName}         </if>     </where> </select>
List<User> selectUsersByName(@Param("userName") String userName);

controller中代码

@GetMapping("/user/name") public PageInfo selectUsersByName(int pageIndex, int pageSize) {     return userService.selectUsersByName(pageIndex, pageSize); }

然后我们访问

http://localhost:9002/user/name?pageIndex=1&pageSize=10

输出结果:

MyBatis插件原理是什么

输出重要项说明:

  • pageNum:当前页码。

  • pageSize:每页数。

  • list:就是我们返回的业务数据。

  • total:总数据。

  • hasNextPage:是否存在下一页。

我们在看看输出SQL:

MyBatis插件原理是什么

发现其实执行了两条SQL:count和limit。

猜测分页插件实现

1.这个分页插件无非就是在我们的查询条件上拼接了个limit和做了一个count查询。

2.我们这里使用的是Mysql作为数据库,如果是Oracle的话那就不是limit了,所以这里有多重数据库对应的方案。

3.在没有此插件的前面拦截并做了sql和相关处理。

根据官网快速入门插件

下面是来自官网的一段话:

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction,  close, isClosed)

  • ParameterHandler (getParameterObject, setParameters)

  • ResultSetHandler (handleResultSets, handleOutputParameters)

  • StatementHandler (prepare, parameterize, batch, update, query)

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis  发行包中的源代码。如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis  的核心模块。这些都是更底层的类和方法,所以使用插件的时候要特别当心。

通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

那我们就尝试着按照官方来写一个插件。

自定义插件

@Intercepts({@Signature(         type= Executor.class,         method = "update",         args = {MappedStatement.class,Object.class})}) public class TianPlugin implements Interceptor {     private Properties properties = new Properties();      @Override     public Object intercept(Invocation invocation) throws Throwable {         System.out.println("老田写的一个Mybatis插件--start");         Object returnObject = invocation.proceed();         System.out.println("老田写的一个Mybatis插件---end");         return returnObject;     } }

然后把插件类注入到容器中。

MyBatis插件原理是什么

这里的自定义完全是官网给出的案例。从自定义的插件类中看到有个update,我们猜测肯定是需要执行update才会被拦截到。

访问前面的代码:http://localhost:9002/updateUser

MyBatis插件原理是什么

成功了。

这是大家肯定会联想到我们刚刚开始学动态代理的时候,不就是在要调用的方法的前面和后面做点小东东吗?

Mybatis的插件确实就是这样的。

我们来分析一下官方的那段话和我们自定义的插件。

分析

首先,我们自定义的插件必须是针对下面这四个类以及方法。

  • Executor (update, query, flushStatements, commit, rollback, getTransaction,  close, isClosed)

  • ParameterHandler (getParameterObject, setParameters)

  • ResultSetHandler (handleResultSets, handleOutputParameters)

  • StatementHandler (prepare, parameterize, batch, update, query)

其次,我们必须实现Mybatis的Interceptor。

MyBatis插件原理是什么

Interceptor中三个方法的作用:

  • intercept():执行拦截内容的地方,比如:在调用某类方法前后做一些自己的处理,简单就是打印日志。

  • plugin():决定是否触发intercept()方法。

  • setProperties():给自定义的拦截器传递我们配置的属性参数(这个可以暂时不管他,后面我们写一个相对完整点的插件,你就明白是干啥的了)。

plugin方法

default Object plugin(Object target) {     return Plugin.wrap(target, this);   }

默认实现方法,里面调用了Plugin.wrap()方法。

public class Plugin implements InvocationHandler {    private Object target;   private Interceptor interceptor;   private Map<Class<?>, Set<Method>> signatureMap;    private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {     this.target = target;     this.interceptor = interceptor;     this.signatureMap = signatureMap;   }    public static Object wrap(Object target, Interceptor interceptor) {     Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);     Class<?> type = target.getClass();     Class<?>[] interfaces = getAllInterfaces(type, signatureMap);     if (interfaces.length > 0) {       // 创建JDK动态代理对象       return Proxy.newProxyInstance(           type.getClassLoader(),           interfaces,           new Plugin(target, interceptor, signatureMap));     }     return target;   }    @Override   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {     try {       Set<Method> methods = signatureMap.get(method.getDeclaringClass());       // 判断是否是需要拦截的方法(很重要)       if (methods != null && methods.contains(method)) {         // 回调intercept()方法         return interceptor.intercept(new Invocation(target, method, args));       }       return method.invoke(target, args);     } catch (Exception e) {       throw ExceptionUtil.unwrapThrowable(e);     }   } //...省略其他不相关代码 }

这不就是一个JDK动态代理吗?

Map

所以,我们不要动不动就说反射性能很差,那是因为你没有像Mybatis一样去缓存一个对象的反射结果。

判断是否是需要拦截的方法,这句注释很重要,一旦忽略了,都不知道Mybatis是怎么判断是否执行拦截内容的,要记住。

Plugin.wrap(target, this)是干什么的?

使用JDK的动态代理,给target对象创建一个delegate代理对象,以此来实现方法拦截和增强功能,它会回调intercept()方法。

为什么要写注解?注解都是什么含义?

在我们自定义的插件上有一堆注解,别害怕。

Mybatis规定插件必须编写Annotation注解,是必须,而不是可选。

@Intercepts({@Signature( type= Executor.class, method = "update",                         args = {MappedStatement.class,Object.class})}            ) public class TianPlugin implements Interceptor {

@Intercepts注解:装载一个@Signature列表,一个@Signature其实就是一个需要拦截的方法封装。那么,一个拦截器要拦截多个方法,自然就是一个@Signature列表。

type= Executor.class, method = "update",args = {MappedStatement.class,Object.class}

解释:要拦截Executor接口内的query()方法,参数类型为args列表。

MyBatis插件原理是什么

那如果想拦截多个方法呢?

@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Intercepts {   Signature[] value(); }

这就简单了吧,我们在@Intercepts注解中可以存放多个@Signature注解。

比如说前面分页插件中就是拦截多个方法的。

MyBatis插件原理是什么

为什么拦截两个都是query方法呢?因为在Executor中有两个query方法。

MyBatis插件原理是什么

到此,相信大家对“MyBatis插件原理是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI