plugin的实现和原理(mybatis3.4.6)

Mybatis

plugin原理和实现思路

摘要:本文主要讲解3.6.4版本mybatis下plugin的原理和实现思路;

包目录说明

该包整体类比较少,但实现插件的思路指的学习和模仿,包下主要有Interceptor(拦截器顶级接口)、InterceptorChain(责任链)、Intercepts和Signature(两个注解配合,标定那些类和方法需要拦截)、Invocation(反射机制类)、Plugin(插件对象本身)、PluginException(异常类);

包的层级图

在开始说如何实现插件之前,需要了解一下,mybatis的执行概要图和mybatis的核心类:

执行概要图

核心类:

 从MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:


Configuration初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如,插件,映射器,ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中

SqlSessionFactory 

SqlSession工厂

SqlSession作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能

Executor

MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护

StatementHandler   封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。

ParameterHandler   负责对用户传递的参数转换成JDBC Statement 所需要的参数,

ResultSetHandler    负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;

TypeHandler          负责java数据类型和jdbc数据类型之间的映射和转换

MappedStatement   MappedStatement维护了一条<select|update|delete|insert>节点的封装,

SqlSource            负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

BoundSql表示动态生成的SQL语句以及相应的参数信息


类的说明:

Interceptor

拦截器接口,所有的拦截器都需要实现;代码如下

public interface Interceptor {


  //拦截的方法(里面需要执行invocation的proceed方法,用于执行代码对象的自身方法)

 Object intercept(Invocation invocation) throws Throwable;


 //获取代理对象

 Object plugin(Object target);


  //暂时没有看到一些用处,可以自己注入一下属性

 void setProperties(Properties properties);


}


Invocation

执行类(反射类),代码如下

public class Invocation {


  //代码对象

 private final Object target;

// 代码方法

 private final Method method;

  //参数

 private final Object[] args;

  //这些属性,刚好可以执行反射机制中的方法


 public Invocation(Object target, Method method, Object[] args) {

   this.target = target;

   this.method = method;

   this.args = args;

  }


 public Object getTarget() {

   return target;

  }


 public Method getMethod() {

   return method;

  }


 public Object[] getArgs() {

   return args;

  }


  //每次拦截之后,需要调用这个方法,用于执行本身的方法

 public Object proceed() throws InvocationTargetException,IllegalAccessException {

   return method.invoke(target, args);

  }


}


Intercepts和Signature

两个注解配合使用,Intercepts标记类,Signature标记拦击的类、方法、和参数;

public @interface Signature {

 Class type();


 String method();


 Class[] args();

}

Plugin

publicclass Plugin implements InvocationHandler {


  //代理对象

  private final Object target;

// 拦截对象

  private final Interceptor interceptor;

// 存放的是类和方法(通过注解获取到的)

  private final Map,Set> signatureMap;


  private Plugin(Object target, Interceptorinterceptor, Map, Set> signatureMap) {

    this.target = target;

    this.interceptor = interceptor;

    this.signatureMap = signatureMap;

  }


  //封装插件对象

  public static Object wrap(Object target,Interceptor interceptor) {

    //可以看一下源码了,就是简单的反射机制代码了

    Map,Set> 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;

  }


  //执行方法,如果方法存在map中,就执行拦截(interceptor的intercept方法)

  @Override

  public Object invoke(Object proxy, Methodmethod, Object[] args) throws Throwable {

    try {

      Set methods =signatureMap.get(method.getDeclaringClass());

      if (methods != null &&methods.contains(method)) {

        return interceptor.intercept(newInvocation(target, method, args));

      }

      return method.invoke(target, args);

    } catch (Exception e) {

      throw ExceptionUtil.unwrapThrowable(e);

    }

  }

InterceptorChain

责任链,初始化的时候,赋值了所有的拦截器,代码也很简单,如下

public class InterceptorChain {


 private final List interceptors = newArrayList();


 public Object pluginAll(Object target) {

   for (Interceptor interceptor : interceptors) {

     target = interceptor.plugin(target);

    }

   return target;

  }


 public void addInterceptor(Interceptor interceptor) {

   interceptors.add(interceptor);

  }


 public List getInterceptors() {

   return Collections.unmodifiableList(interceptors);

  }

}

值得注意的是,什么时候interceptors赋的值?这里就关联到了Configuration这个类,目前有两种初始化的方式:

[if !supportLists]1、  [endif]通过SqlSessionFactoryBean去构建Configuration添加拦截器并构建获取SqlSessionFactory;

[if !supportLists]2、  [endif]通过原始的XMLConfigBuilder 构建configuration添加拦截器;

源码就不黏贴了;


项目中思路的应用

Plugin的作用就是将项目中的执行对象某些方法暴露在外面,允许第三方在方法执行之前,执行自己的逻辑;相对来说将自己的逻辑暴露在外面还是有很大的风险,目前自己想到的有参数效验,自己原来封装了一个jar,里面有一些类似@MAX @MIN等等注解,这个时候,可以向外提供plugin,到达不修改jar的前提,又向外提供添加注解的能力;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,132评论 6 523
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,457评论 3 404
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,411评论 0 368
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,147评论 1 301
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,145评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,611评论 1 315
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,962评论 3 429
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,948评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,479评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,514评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,640评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,228评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,973评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,402评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,551评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,210评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,714评论 2 366

推荐阅读更多精彩内容