MyBatis插件(拦截器)记录

未完待接着往里面更新

  • 关于插件的在原始配置文件中的解析请查看MyBatis解析自身配置文件记录一篇
  • 插件的声明周期

        public interface Interceptor {
    
          Object intercept(Invocation invocation) throws Throwable;
    
          Object plugin(Object target);
    
          void setProperties(Properties properties);
    
    }
    
    • 实例化和setProperties
      • 在应用解析配置文件的时候,将会读取插件相关配置,并创建插件实例,并调用插件的interceptorInstance.setProperties(properties);接口,以设置配置的相关配置,比如
      • 关于peroperties信息的解析,读取插件配置本身node节点
        public Properties getChildrenAsProperties() {
            Properties properties = new Properties();
            for (XNode child : getChildren()) {
              String name = child.getStringAttribute("name");
              String value = child.getStringAttribute("value");
              if (name != null && value != null) {
                properties.setProperty(name, value);
              }
            }
            return properties;
    }
    
    • Object plugin(Object target);执行时机

      在我们想去获取一个session的时候(可以查看上一篇MyBatis 一句sql的执行流程 针对session生成的时机),会创建执行sql的Executor接口实现,在得到该对象的时候,就会调用我们注册的插件的plugin方法:

    package org.apache.ibatis.session;
    public class Configuration {
         public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
            //...
            //interceptorChain即全局配置对象中系统注册的拦截器插件缓存容器:protected final InterceptorChain interceptorChain = new InterceptorChain();
            executor = (Executor) interceptorChain.pluginAll(executor);//关键
            return executor;
          }
    

    实际调用端:

    package org.apache.ibatis.plugin;
    
        import java.util.ArrayList;
        import java.util.Collections;
        import java.util.List;
    
        /**
         * @author Clinton Begin
         */
        public class InterceptorChain {
    
          private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
    
          public Object pluginAll(Object target) {
            for (Interceptor interceptor : interceptors) {
              target = interceptor.plugin(target);//这里,那么我们拿到的就是一个Executor接口的对象
            }
            return target;
          }
    
          public void addInterceptor(Interceptor interceptor) {
            interceptors.add(interceptor);
          }
    
          public List<Interceptor> getInterceptors() {
            return Collections.unmodifiableList(interceptors);
      }
    
    }
    

    Plugin.wrap(target, this);执行:

    private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
        Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);//获取插件必配的Intercepts注解
        // issue #251
        if (interceptsAnnotation == null) {//之所以是必配
          throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());      
        }
        Signature[] sigs = interceptsAnnotation.value();
        Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>();
        /*
            将注解的信息解析并创建一个代理对象包裹Executor接口的对象,那么之后我们在使用这个Executor对象的时候,实际会先过代理,如果执行的是我们需要拦截的方法,那么就进入拦截器的Object intercept(Invocation invocation)接口,否则就放过,我想应该是这样的哈,嘿嘿,等之后真的用到在补充;
            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;
    }
        */
        for (Signature sig : sigs) {
          Set<Method> methods = signatureMap.get(sig.type());
          if (methods == null) {
            methods = new HashSet<Method>();
            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;
    }
    

你可能感兴趣的:(MyBatis插件(拦截器)记录)