上一篇讲解了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的使用过程。
@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) {
}
}
上面拦截的是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里面。