mybatis-插件使用手册

mybatis-插件详解

基本原理

使用了JDK动态代理,基于 interceptor 实现

public class Plugin implements InvocationHandler {

  private final Object target;
  private final Interceptor interceptor;
  private final Map<Class<?>, Set<Method>> signatureMap;

  @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)) {
         //走插件
        return interceptor.intercept(new Invocation(target, method, args));
      }
       //正常查询
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }
  
  //为目标对象target创建代理
  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) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
 }
}

看下Interceptor接口

public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  //创建代理对象并返回
  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
}
mybatis是如何使用的

创建 MybatisAutoConfiguration 的时候进行注入

@Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {

  private final MybatisProperties properties;

  private final Interceptor[] interceptors;

  private final TypeHandler[] typeHandlers;


  private final List<ConfigurationCustomizer> configurationCustomizers;

  private final List<SqlSessionFactoryBeanCustomizer> sqlSessionFactoryBeanCustomizers;

  public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider,
      ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider,
      ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider,
      ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,
      ObjectProvider<List<SqlSessionFactoryBeanCustomizer>> sqlSessionFactoryBeanCustomizers) {
    this.properties = properties;
    //通过构造器进行注入
    this.interceptors = interceptorsProvider.getIfAvailable();
    this.typeHandlers = typeHandlersProvider.getIfAvailable();
    this.languageDrivers = languageDriversProvider.getIfAvailable();
    this.resourceLoader = resourceLoader;
    this.databaseIdProvider = databaseIdProvider.getIfAvailable();
    this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
    this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();
  }
    
    
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
 	...............
    //赋值到sqlSessionFactory中,当开启会话时,便可以进行拦截
    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }
    //获取SqlSessionFactory
    return factory.getObject();
  }
}

获取SqlSessionFactory时,Configuration初始化 interceptorChain

public class Configuration {
    //实例化
    protected final InterceptorChain interceptorChain = new InterceptorChain();
    
    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql 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) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }
    
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
}

可见 ,插件作用于 ParameterHandler、ResultSetHandler、StatementHandler、Executor 这四种类型

拦截器责任链 InterceptorChain

public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<>();

  //给指定对象应用所有的拦截器
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
       //有多少个拦截器,就创建多少个代理对象,拦截器不要太多,影响性能
      target = interceptor.plugin(target);
    }
    return target;
  }
}

最后,开启会话session的时候,就会进行增强

自定义插件

实现Interceptor接口,根据方法签名@Signature声明需要拦截的方法

@Intercepts({@Signature(
        type= Executor.class, //上面说的四种类型之一
        method = "query", //方法名称
        args = {MappedStatement.class ,Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), //方法参数
        @Signature(
                type= Executor.class,
                method = "query",
                args = {MappedStatement.class ,Object.class, RowBounds.class, ResultHandler.class})})
public class MyIntercepter  implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        
        // 增强..................
        
        return invocation.proceed();
    }
    
}

注册到容器中

@Configuration
public class MybatisConfig {
    @Bean
    public Interceptor myInterceptor() {
        return new MyIntercepter();
    }
}

使用场景:分页,字段加密、自动赋值,监控等等。

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Mybatis-Plus 是一个 Mybatis 的增强插件,具有简化代码、优化性能等特点。使用方法包括: 1. 安装插件:在项目中引入 mybatis-plus 依赖 2. 配置插件:在配置文件中配置 mybatis-plus 插件的相关参数 3. 使用插件:在 DAO 层使用 mybatis-plus 提供的方法来实现对数据库的操作,例如增加、删除、修改、查询等。 总体而言,Mybatis-Plus 是一个易于使用、高效率的插件,能够大大简化开发人员的工作量。 ### 回答2: Mybatis-plus是Mybatis的增强工具,可以大大简化我们的开发流程,提高开发效率。Mybatis-plus插件Mybatis-plus提供的插件,为我们提供了一些更加便捷的功能,下面对这些功能进行详细介绍。 1. 自动生成SQL语句 Mybatis-plus插件提供了自动生成SQL语句的功能,我们只需要在实体类上加上一些注解,就可以自动生成相应的SQL语句,例如@TableId、@TableName、@TableField等,可以大大减少我们的编写SQL语句的时间。 2. 简化分页操作 Mybatis-plus插件还提供了分页操作的功能,我们只需要在service层调用分页方法,就可以轻松实现分页操作,而不必手动编写SQL语句,方便快捷。同时,Mybatis-plus也提供了多种分页方式,例如物理分页、内存分页、嵌套查询分页等。 3. 自动填充数据 Mybatis-plus插件还提供了自动填充数据的功能,可以在实体类中指定某些属性自动填充,例如创建时间、更新时间等,不需要手动填写,方便高效。 4. 全局拦截器 Mybatis-plus插件还提供了全局拦截器的功能,我们可以在全局拦截器中添加自己的业务逻辑,例如添加缓存、防止SQL注入等,对我们的系统有很好的保护作用。 总之,Mybatis-plus插件为我们提供了很多便利的功能,能够大大提高我们的开发效率和代码质量,同时也保护了我们系统的安全性。因此,在使用Mybatis-plus进行开发时,建议使用Mybatis-plus插件,以便更好地享受Mybatis-plus的便利和优越性能。 ### 回答3: Mybatis-Plus是Mybatis框架的一个增强工具,提供了很多强大的功能,如通用Mapper、分页插件、性能分析插件等等。其中最常用的就是通用Mapper和分页插件。 通用Mapper插件可以简化代码,省去了很多重复的CRUD操作。使用该插件可以直接操作实体类,无需编写XML文件,提高开发效率。需要注意的是,在使用通用Mapper插件时,需要在实体类中添加@TableId注解来指定主键,以及@TableField注解来指定字段。 分页插件则可以快速实现分页查询,只需要在具体的SQL查询方法中传入Page对象即可。其中Page对象包含了当前页码、每页显示条数、总记录数等属性,查询完毕后,将Page对象返回即可完成分页查询。 除了上述两个插件外,Mybatis-Plus还提供了很多其他的功能,例如:多租户支持、乐观锁、自动填充字段、代码生成器等等。这些功能可以大大提高开发效率,并且可以避免一些常见的错误。 总之,Mybatis-Plus是一个非常实用的插件,可以帮助开发者快速实现常见的数据库操作,提高开发效率和代码质量。如果您在使用Mybatis框架时遇到了一些常见的问题,可以尝试使用Mybatis-Plus插件来解决。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗罗的1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值