mybatis源码学习(七)

mybatis加载plugins

上一篇讲解了mybatis加载typeAliases的过程,mybatis加载别名的方法有3种,根据优先级,最优先的是注解,然后才是配置文件,整个过程简单的说,就是读取相关的bean,然后保存在TYPE_ALIASES集合里面,供后面的使用。它主要的作用就是为类写别名,使得mybatis在使用类的时候,可以直接使用别名,而不需要使用类名。
加载完typeAliases之后,接着就是加载plugins,在mybatis,plugins是非常有用的,它可以定义拦截器,对执行的sql语句进行拦截,是对mybatis的增强。

MyBatis 允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
在mybatis里使用插件是非常简单的,只需实现 Interceptor 接口,并指定了想要拦截的方法签名即可,下面举例讲解一下plugins的使用过程。

  1. 定义类,实现mybatis的Interceptor接口
@Intercepts(value = {@Signature(type= Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class})})
public class MyInterceptor implements Interceptor {

    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("----------- 执行开始。。。。。 ---------");
        // 调用方法,实际上就是拦截的方法
        Object result = invocation.proceed();
        System.out.println("----------- 执行结束。。。。。 ---------");
        return result;
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }

    public void setProperties(Properties properties) {

    }
}
  1. 在核心配置文件里,加上plugins配置
    
        
    

上面拦截的是Executor里面的query方法,其他的包括update、flushStatements等都不会拦截。同样的,拦截其他例如ParameterHandler 、ResultSetHandler等方法是同样的配置,只是在签名那里需要修改一下。
再看加载plugins的源码,通过调用pluginElement方法加载plugins插件,传入的是核心配置文件里面的plugins节点信息

  private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        //遍历该节点,获取interceptor节点属性
        String interceptor = child.getStringAttribute("interceptor");
        //获取节点下的其他属性
        Properties properties = child.getChildrenAsProperties();
        //这里是根据节点配置的类名去实例化类,在这里面,首先会去找上一步加载的别名里面的
        //TYPE_ALIASES集合,因为有的配置直接配置别名,而不是配置完整类名,如果在集合里面找到
        //那么直接返回集合里面的实例,否则,根据配置的类名去通过反射机制找到类,并实例化
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
        interceptorInstance.setProperties(properties);
        //把插件类添加进configuration里面,实际上就是加入到interceptorChain这个变量里面,
        //interceptorChain变量的类型就是InterceptorChain,拦截器链,它里面有一个list,这个方法就是把这个实例放到里面的list里
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }

configuration的addInterceptor如下

public void addInterceptor(Interceptor interceptor) {
    interceptorChain.addInterceptor(interceptor);
  }

InterceptorChain代码如下:

public class InterceptorChain {

  private final List interceptors = new ArrayList();

  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);
  }

}

到这里,加载plugins就完成了,在这里,仅仅是把插件实例化到configuration里面。

你可能感兴趣的:(源码学习,mybatis源码)