Mybatisソース解析-プラグインモジュール

10974 ワード

MyBatisは、マッピングされたステートメントの実行中のある点でブロックコールを行うことができます.デフォルトでは、MyBatisがプラグインを使用してブロックする方法の呼び出しを許可することができます.
// MyBatis   , MyBatis      ,  SQL             
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
//             JDBC Statement       ,
ParameterHandler (getParameterObject, setParameters)
//   JDBC   ResultSet        List     
ResultSetHandler (handleResultSets, handleOutputParameters)
//   JDBC Statement  ,   JDBC statement    ,     、 Statement      List  。
StatementHandler (prepare, parameterize, batch, update, query)
これらの種類の方法の詳細は、各方法の署名を確認することによって、またはMyBatisの発行パケットのソースコードを直接確認することができる.もしあなたがやりたいのは監視方法の呼び出しだけではないなら、書き直している方法の行動をよく知るべきです.既存の方法の動作を修正したり書き換えたりすると、MyBatisのコアモジュールを破壊する可能性が高いからです.これらはより低い層の種類と方法ですので、プラグインを使う時は特に注意してください.Mybatis Mybatisプラグインは、責任連鎖モードを採用し、動的エージェントを通じてコードブロックを実現し、プラグインの役割を果たします.
MyBatisが提供する強力なメカニズムにより、プラグインを使用することは非常に簡単で、Interceptorインターフェースを実現するだけで、ブロックしたい方法を指定して署名すればいいです.もちろん、ファイルを設定してプラグインのパスを指定する必要があります.
まず配置を見てください
<plugins>
//
   <plugin interceptor="Test.ExecutorPlugin">
    <property name="someProperty" value="100"/>
  plugin>
plugins>
プラグインインターフェース
public interface Interceptor {
//    ,         ,    invocation.proceed()  ,      method.invoke(target, args)  ,       
  Object intercept(Invocation invocation) throws Throwable;
//         ,    target
  Object plugin(Object target);
//    
  void setProperties(Properties properties);

}
プロファイル解析
  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);
      }
    }
  }
Mybatis 4つのインターフェース初期化の重要な方法を参照してください.この方法に何があったか見てください.
//       ,        
  public Object pluginAll(Object target) {
  //      ,              ,      
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }
        public Object plugin(Object target) {
        if (target instanceof ResultSetHandler) {
        //    
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }
Plugin類を見に来ました
//   InvocationHandler  ,          
public class Plugin implements InvocationHandler {
//    
  private Object target;
  //   
  private Interceptor interceptor;
  //    
  private Map, Set> signatureMap;
//          
  private Plugin(Object target, Interceptor interceptor, 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;
  }

  @Override
  //      
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
    //        
      Set methods = signatureMap.get(method.getDeclaringClass());
      //       (            ,           ),      
      if (methods != null && methods.contains(method)) {
        return interceptor.intercept(new Invocation(target, method, args));
      }
      //            
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }

  private static Map, Set> getSignatureMap(Interceptor interceptor) {
  //  Intercepts  
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    //         ,      
    if (interceptsAnnotation == null) {
      throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());      
    }
    //      
    Signature[] sigs = interceptsAnnotation.value();
    Map, Set> signatureMap = new HashMap, Set>();
    //      
    for (Signature sig : sigs) {
      Set methods = signatureMap.get(sig.type());
      if (methods == null) {
        methods = new HashSet();
        //key     ,value     
        signatureMap.put(sig.type(), methods);
      }
      try {
      //            
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
      }
    }
    return signatureMap;
  }
//          
  private static Class>[] getAllInterfaces(Class> type, Map, Set> signatureMap) {
    Set> interfaces = new HashSet>();
    //    
    while (type != null) {
      for (Class> c : type.getInterfaces()) {
//          
        if (signatureMap.containsKey(c)) {
          interfaces.add(c);
        }
      }
      type = type.getSuperclass();
    }
    return interfaces.toArray(new Class>[interfaces.size()]);
  }

}
次のページでは、ページ別の例を作りましょう.