设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 站长学院 > MySql教程 > 正文

Mybatis超详细插件机制解析,弄懂拦截器So easy(6)

发布时间:2019-12-25 22:25 所属栏目:115 来源:站长网
导读:如果有N个插件,就有N个代理,每个代理都要执行上面的逻辑。这里面的层层代理要多次生成动态代理,是比较影响性能的。虽然能指定插件拦截的位置,但这个是在执行方法时动态判断,初始化的时候就是简单的把插件包装

如果有N个插件,就有N个代理,每个代理都要执行上面的逻辑。这里面的层层代理要多次生成动态代理,是比较影响性能的。虽然能指定插件拦截的位置,但这个是在执行方法时动态判断,初始化的时候就是简单的把插件包装到了所有可以拦截的地方。

因此,在编写插件时需注意以下几个原则:

不编写不必要的插件;

实现plugin方法时判断一下目标类型,是本插件要拦截的对象才执行Plugin.wrap方法,否者直接返回目标本身,这样可以减少目标被代理的次数。

// 假如我们只要拦截Executor对象,那么我们应该这么做 

public Object plugin(final Object target) { 

  if (target instanceof Executor) { 

   return Plugin.wrap(target, this); 

  } else { 

   return target; 

  } 

Mybatis插件很强大,可以对Mybatis框架进行很大的扩展。当然,如果你不理解Mybatis插件的原理,开发起来只能是模拟两可。在实际开发过程中,我们可以参考别人写的插件。下面是一个Mybatis分页的插件,可以为以后开发做参考。

/** 

 * Mybatis - 通用分页插件(如果开启二级缓存需要注意) 

 */ 

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}), 

    @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})}) 

@Log4j 

public class PageHelper implements Interceptor { 

 

  public static final ThreadLocal<Page> localPage = new ThreadLocal<Page>(); 

 

  /** 

   * 开始分页 

   * 

   * @param pageNum 

   * @param pageSize 

   */ 

  public static void startPage(int pageNum, int pageSize) { 

    localPage.set(new Page(pageNum, pageSize)); 

  } 

 

  /** 

   * 结束分页并返回结果,该方法必须被调用,否则localPage会一直保存下去,直到下一次startPage 

   * 

   * @return 

   */ 

  public static Page endPage() { 

    Page page = localPage.get(); 

    localPage.remove(); 

    return page; 

  } 

 

  public Object intercept(Invocation invocation) throws Throwable { 

    if (localPage.get() == null) { 

      return invocation.proceed(); 

    } 

    if (invocation.getTarget() instanceof StatementHandler) { 

      StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); 

      MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); 

      // 分离代理对象链(由于目标类可能被多个插件拦截,从而形成多次代理,通过下面的两次循环 

      // 可以分离出最原始的的目标类) 

      while (metaStatementHandler.hasGetter("h")) { 

        Object object = metaStatementHandler.getValue("h"); 

        metaStatementHandler = SystemMetaObject.forObject(object); 

      } 

      // 分离最后一个代理对象的目标类 

      while (metaStatementHandler.hasGetter("target")) { 

        Object object = metaStatementHandler.getValue("target"); 

        metaStatementHandler = SystemMetaObject.forObject(object); 

      } 

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读