mybatis(八):Mybatis插件开发原理

Mybatis插件开发

MyBatis采用责任链模式,通过动态代理组织多个插件(拦截器) ,允许用户自定义拦截器类,从而实现插件开发功能。

默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler(getParameterObject, setParameters)
  • ResultSetHandler(handleResultSets, handleOutputParameters)
  • StatementHandler(prepare, parameterize, batch, update, query)
1. 拦截器接口介绍

Mybatis插件可以通过实现接口org.apache.ibatis.plugin.Interceptor

Interceptor接口源码:

public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  Object plugin(Object target);

  void setProperties(Properties properties);

}
  • Object intercept(Invocation invocation):是mybatis要执行的拦截方法。
  • Object plugin(Object target):在创建被拦截的接口实现类时调用。
  • void setProperties(Properties properties):用来传递插件参数,可以通过参数修改插件的行为。
2. 拦截器签名介绍

Mybatis插件实现需要给接口实现类配置拦截器签名。需要在实现类上配置注解。

@Intercepts@Signature注解。注解类源码如下:

public @interface Intercepts {
  Signature[] value();
}

public @interface Signature {
  Class<?> type();

  String method();

  Class<?>[] args();
}

@Intercepts注解中的属性为@Signature数组,可以在同一个拦截器中同时拦截不同的接口和方法。

@Signature注解包含3个属性。

​ type:设置拦截的接口。参数值为Executor、ParameterHandler、ResultSetHandler、StatementHandler

​ 4个接口

​ method:设置拦截接口中的方法名。参数为上面4个接口中的方法名。

​ args:设置拦截方法的参数类型数组。通过方法名和参数类型确定唯一的一个方法。

Executor接口源码

public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;

  int update(MappedStatement ms, Object parameter) throws SQLException;

  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

  List<BatchResult> flushStatements() throws SQLException;

  void commit(boolean required) throws SQLException;

  void rollback(boolean required) throws SQLException;

  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

  boolean isCached(MappedStatement ms, CacheKey key);

  void clearLocalCache();

  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);

  Transaction getTransaction();

  void close(boolean forceRollback);

  boolean isClosed();

  void setExecutorWrapper(Executor executor);

}

ParameterHandler接口源码:

public interface ParameterHandler {

  Object getParameterObject();

  void setParameters(PreparedStatement ps)
      throws SQLException;

}

ResultSetHandler接口源码:

public interface ResultSetHandler {

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

StatementHandler接口源码:

public interface StatementHandler {

  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;

  void parameterize(Statement statement)
      throws SQLException;

  void batch(Statement statement)
      throws SQLException;

  int update(Statement statement)
      throws SQLException;

  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;

  BoundSql getBoundSql();

  ParameterHandler getParameterHandler();

}
3. Mybatis PageHelper插件使用
3.1 通过Maven引入Jar包
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.2.1</version>
</dependency>

​ 注意pagehelper版本和mybatis版本。版本差异可能导致如下错误。

Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor
3.2 mybatis-config.xml中添加plugin
<plugins>
        <!-- com.github.pagehelper为PageHelper类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 方言 -->
            <property name="dialect" value="mysql"/>
            <!-- 该参数默认为false -->
            <!-- 设置为true时,使用RowBounds分页会进行count查询 -->
            <property name="rowBoundsWithCount" value="true"/>
        </plugin>
    </plugins>
3.3 CountryMapper.xml
<select id="getCountry" resultType="com.zm.entity.Country">
        select id,countryname,countrycode from country
</select>
3.4 测试类
 @Test
    public void test8() {
        SqlSession session = sqlSessionFactory.openSession();
        CountryMapper mapper = session.getMapper(CountryMapper.class);
        // pageNum 第几页 pageSize 每页的条数
        PageHelper.startPage(1,3);

        List<Country> list = mapper.getCountry();

        PageInfo<Country> info = new PageInfo<>(list);

        list.forEach(country -> System.out.println(country));
        System.out.println("------------");
        System.out.println("查询结果条数:"+info.getTotal());
        System.out.println("数据总页数:"+info.getPages());
        System.out.println("每页的size:"+info.getPageSize());
        System.out.println("最后页数:"+info.getEndRow());
    }

3.5 结果
DEBUG [main] - ==>  Preparing: SELECT count(0) FROM country 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 1
DEBUG [main] - ==>  Preparing: select id,countryname,countrycode from country limit ?,? 
DEBUG [main] - ==> Parameters: 0(Integer), 3(Integer)
DEBUG [main] - <==      Total: 3
Country{id=1, countryname='中国', countrycode='CN'}
Country{id=2, countryname='美国', countrycode='US'}
Country{id=3, countryname='俄罗斯', countrycode='RU'}
------------
查询结果条数:7
数据总页数:3
每页的size:3
最后页数:3
3.6 PageInfo 类的方法
 	private void calcNavigatepageNums() 
    private void calcPage() 
    private void judgePageBoudary()
    public int getPageNum() 
    public void setPageNum(int pageNum)
    public int getPageSize() 
    public void setPageSize(int pageSize)
    public int getSize() 
    public void setSize(int size)
    public String getOrderBy()
    public void setOrderBy(String orderBy)
    public int getStartRow()
    public void setStartRow(int startRow)
    public int getEndRow()
    public void setEndRow(int endRow)
    public long getTotal()
    public void setTotal(long total)
    public int getPages()
    public void setPages(int pages)
    public List<T> getList() 
    public void setList(List<T> list) 
    public int getFirstPage()
    public void setFirstPage(int firstPage)
    public int getPrePage()
    public void setPrePage(int prePage)
    public int getNextPage()
    public void setNextPage(int nextPage)
    public int getLastPage() 
    public void setLastPage(int lastPage) 
    public boolean isIsFirstPage()
    public void setIsFirstPage(boolean isFirstPage)
    public boolean isIsLastPage() 
    public void setIsLastPage(boolean isLastPage)
    public boolean isHasPreviousPage()
    public void setHasPreviousPage(boolean hasPreviousPage)
    public boolean isHasNextPage() 
    public void setHasNextPage(boolean hasNextPage)
    public int getNavigatePages()
    public void setNavigatePages(int navigatePages)
    public int[] getNavigatepageNums() 
    public void setNavigatepageNums(int[] navigatepageNums)
    public int getNavigateFirstPage()
    public int getNavigateLastPage()
    public void setNavigateFirstPage(int navigateFirstPage)
    public void setNavigateLastPage(int navigateLastPage) 
    public String toString()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值