MyBatis的运行的核心原理解析(三)

#插件java

  • 四大对象在运行得时候,在Configuration对象得建立方法里MyBatis使用了责任链得方式去封装,也就是说咱们能够有机会在四大对象调度得时候插入咱们自定义得代码区执行一些特殊得要求来知足咱们特殊得场景需求,就是MyBatis得插件技术.

插件的接口

MyBatis中使用插件,咱们必须实现Interceptor接口,接口的代码以下:apache

package org.apache.ibatis.plugin;
import java.util.Properties;
public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  Object plugin(Object target);

  void setProperties(Properties properties);

}

  • intercept():它将直接覆盖你所拦截对象原有的方法,所以它是插件的核心方法。intercept里面有个参数Invocation对象,经过它能够反射调度原来的对象的方法。性能

  • plugin():里面的参数Object target是被拦截的对象,它的做用是给被拦截对象生成一个代理对象,而且返回它。在MyBatis里直接使用org.apache.ibatis.plugin.Plugin中的wrap静态(static)方法提供了生成代理对象,咱们每每使用plugin方法即可以生成一个代理对象了。ui

    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;
    }
  • setProperties():容许在plugin元素中配置咱们须要的参数,方法在插件初始化的时候就会被调用一次,而后把插件对象存入到配置中,方便后面获取。 在org.apache.ibatis.builder.xml.XMLConfigBuilder咱们能够看到: private void pluginElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); } } }.net

其实在解析配置文件的过程当中,咱们的插件节点和咱们配置参数,同时使用反射技术生成对应的插件实例,而后调用插件方法中的setProperties(),设置咱们配置的参数,而后将插件实例保存到配置对象里,方便后面的读取使用它。因此插件的实例对象是以开始就被初始化的,不是在使用到的时候才初始化,这样能够提高性能。插件

Configuration保存插件的方式(初始化完的参数保存在了List<Interceptor> interceptors这个list里面):代理

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

public class InterceptorChain {

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

  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<Interceptor> getInterceptors() {
	return Collections.unmodifiableList(interceptors);
  }

}

Plugin类的plugin()能够生成代理对象,在生成代理对象以后将对象存进了Configuration里面,若是须要直接从Configuration实例获取就能够了。从第一个对象(四大对象中的一个)开始,将对象传递给plugin(),而后返回一个代理;若是存在第二个插件,那么咱们拿到第一个代理对象,传递给plugin()再返回第一个代理独享的代理......依此类推,拦截器越多,代理的对象就越多(多少个拦截器就多少个代理对象)。保证了每个插件均可以拦截到真是的对象。这就号比每个插件均可以一层层的处理拦截的对象。MyBatis的四大对象也是如此处理的。code

相关文章
相关标签/搜索