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

相關文章
相關標籤/搜索