mybatis 开发自定义插件,你学废了吗(上)

简介: mybatis 开发自定义插件,你学废了吗

文章目录

介绍

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。比如执行前、执行后或者对SQL结果集处理、sql入参处理等,这样就可以在不修改mybatis源码的情况下对sql执行的过程或结果进行修改,实现了解耦。mybatis 是在动态代理的基础上实现的。对动态代理感兴趣的可以看下JAVA 代理模式不了解一下吗?

使用场景

如果业务中需要设置一些通用数据库操作,比如创建时间、创建人等通用字段又或者是分页操作等,这类都可以使用插件开发方式,PageHelper就是基于Interceptor的一个mybatis插件。

Interceptor拦截器

public interface Interceptor {
  /**
   * 子类拦截器必须要实现的方法,
   * 在该方法对内自定义拦截逻辑
   * @param invocation
   * @return
   * @throws Throwable
   */
  Object intercept(Invocation invocation) throws Throwable;
  /**
   生成目标类的代理对象
   * 也可以根据需求不返回代理对象,这种情况下这个拦截器将不起作用
   * 无特殊情况使用默认的即可
   * @param target
   * @return
   */
  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  /**
   * 设置变量
   * 在注册拦截器的时候设置变量,在这里可以获取到
   * @param properties
   */
  default void setProperties(Properties properties) {
    // NOP
  }
}

InterceptorChain拦截器链

在org.apache.ibatis.plugin包下有个InterceptorChain类,该类有个interceptors属性,所有实现了Interceptor接口的拦截器都会被存储到interceptors中。

源码如下:

public class InterceptorChain {
  private final List<Interceptor> interceptors = new ArrayList<>();
  /**
   *  让目标类在所有的拦截器中生成代理对象,并返回代理对象
   * @param target
   * @return
   */
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }
  /**
   * 添加过滤器
   * @param interceptor
   */
  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }
  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }
}

拦截方法

默认情况下,MyBatis 允许使用插件来拦截Executor 、ParameterHandler 、ResultSetHandler 、StatementHandler 接口下面的方法。如果系统中有配置自定义插件,默认情况下,系统会把上面四个类的默认子类都作为目标类来让所有的拦截器进行拦截,

以保证所有的拦截器都能对Executor 、ParameterHandler 、ResultSetHandler 、StatementHandler子类进行拦截。


源码如下:

在org.apache.ibatis.session.Configuration类中

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    // 使用拦截器进行拦截
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
  }
  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    // 使用拦截器进行拦截
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }
  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 使用拦截器进行拦截
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }
  public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
  }
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    // 使用拦截器进行拦截
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

注解

Intercepts

Intercepts的作用是拦截Signature注解数组中指定的类的方法。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
  /**
   * Returns method signatures to intercept.
   * Signature注解列表
   * @return method signatures
   */
  Signature[] value();
}

Signature

Signature注解作用是拦截指定类的方法。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
  /**
   * Returns the java type.
   * 要拦截的类
   * @return the java type
   */
  Class<?> type();
  /**
   * Returns the method name.
   * 要拦截的类的方法
   * @return the method name
   */
  String method();
  /**
   * Returns java types for method argument.
   * 要拦截的类的方法的参数列表
   * @return java types for method argument
   */
  Class<?>[] args();
}

示例

步骤

1、实现org.apache.ibatis.plugin.Interceptor接口

2、添加Intercepts和Signature注解

3、根据需求实现Interceptor方法逻辑

入门使用

这里会写两个使用示例,一个是动态给属性赋值,一个是打印SQL。

表结构:

CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `gender` varchar(20) DEFAULT NULL,
  `userName` text NOT NULL,
  `create_date` datetime DEFAULT NULL COMMENT '创建日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

实体类:

public class UserInfo {
    private Long id;
    private String gender;
    private String userName;
    private Date createDate;
    // 省略get、set方法
}
目录
相关文章
|
1月前
|
SQL XML Java
8、Mybatis-Plus 分页插件、自定义分页
这篇文章介绍了Mybatis-Plus的分页功能,包括如何配置分页插件、使用Mybatis-Plus提供的Page对象进行分页查询,以及如何在XML中自定义分页SQL。文章通过具体的代码示例和测试结果,展示了分页插件的使用和自定义分页的方法。
8、Mybatis-Plus 分页插件、自定义分页
|
1月前
|
SQL Java Kotlin
MybatisPlus怎么拓展自定义BaseMapper
通过扩展Mybatis-Plus的`BaseMapper`,可以自定义SQL模板以满足特定业务需求。例如,当遇到唯一键冲突而不希望抛出异常时,可使用`INSERT IGNORE`语法。首先,创建`InsertIgnore`类继承`AbstractMethod`并定义`insertIgnore`方法及其SQL模板。接着,在自定义的`UltraBaseMapper`接口中声明`insertIgnore`方法,并让业务Mapper继承此接口。最后,通过`UltraSqlInjector`类将`InsertIgnore`方法注册到Mybatis-Plus插件中。
|
3天前
|
SQL Java 数据库连接
解决mybatis-plus 拦截器不生效--分页插件不生效
本文介绍了在使用 Mybatis-Plus 进行分页查询时遇到的问题及解决方法。依赖包包括 `mybatis-plus-boot-starter`、`mybatis-plus-extension` 等,并给出了正确的分页配置和代码示例。当分页功能失效时,需将 Mybatis-Plus 版本改为 3.5.5 并正确配置拦截器。
解决mybatis-plus 拦截器不生效--分页插件不生效
|
6天前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
1月前
|
Java 数据库 Spring
MyBatisPlus分页插件在SpringBoot中的使用
这篇文章介绍了如何在Spring Boot项目中配置和使用MyBatis-Plus的分页插件,包括创建配置类以注册分页拦截器,编写测试类来演示如何进行分页查询,并展示了测试结果和数据库表结构。
MyBatisPlus分页插件在SpringBoot中的使用
|
22天前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
54 0
|
2月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
56 3
|
2月前
|
SQL 监控 Java
IDEA插件-Mybatis Log Free日志替换
MyBatis Log Free 是一个免费的用于在 IntelliJ IDEA 中显示 MyBatis 日志的插件。它可以帮助您更方便地查看和分析 MyBatis 的 SQL 执行情况,以及定位潜在的性能问题,提高开发效率。
204 0
IDEA插件-Mybatis Log Free日志替换
|
1月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(7、使用注解开发)
这篇文章讲述了如何使用MyBatis框架的注解方式进行开发,包括在接口上使用注解定义SQL语句,并通过动态代理实现对数据库的增删改查操作,同时强调了接口需要在核心配置文件中注册绑定。
|
2月前
|
SQL
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注