Principle mybatis plug - reflects the chain of responsibility and dynamic proxies

@

If you have not had a custom interceptor, you can see my previous article . If you do not know how to use the JDK dynamic proxy, I can see this article . Chain of Responsibility design pattern is very simple to understand, you can look online to find examples.

mybatis Plug the principle of using a dynamic agent and the chain of responsibility to achieve.

1 which methods to intercept

In front of said, you can comment Inteceptsand Signatureto specify which method interception. However, it does not mean that all of the methods can be intercepted.

Method mybatis interceptor intercepted, there are the following types:

1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
2. ParameterHandler (getParameterObject, setParameters)
3. ResultSetHandler (handleResultSets, handleOutputParameters)
4. StatementHandler (prepare, parameterize, batch, update, query)

Why are these methods can intercept it?

In mybatisthe above several classes are SqlSessionfour objects. SqlSessionThese objects are achieved by the operation of the database, the result of the processing. Therefore, in the process, the method is to intercept these objects is a very important role.
Configuration objects in
And it is reflected in the source code, in Configurationclass, the importance of this class do not do too much exposition, you can see the previous article.

Xml parsed into the total Configurationprocess, the need for more than a few new class. The above will call back in a few class interceptorChain#pluginAllmethod.

2 How the Agent

public class InterceptorChain {

  /**
   * 拦截器列表
   */
  private final List<Interceptor> interceptors = new ArrayList<>();

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

  /**
   * 添加拦截器
   *
   * @param interceptor
   */
  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

  /**
   * 获取拦截器列表
   *
   * @return
   */
  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}

It can be seen that the interceptor will call all the pluginway to return a proxy object after the final layers of agents. Pay attention to the layers of agents here.

If there are A, B, C three interceptor (the same signature), in this case, layers are encapsulated. Finally, when executed, it is A> B> C> target.proceed ()> C> B> A.

3 proxy object

InterceptorChainEach interceptor will call the pluginmethod. This method will return the corresponding proxy object.

/**
 * 拦截器接口
 *
 * @author Clinton Begin
 */
public interface Interceptor {

  /**
   * 执行拦截逻辑的方法
   *
   * @param invocation 调用信息
   * @return 调用结果
   * @throws Throwable 异常
   */
  Object intercept(Invocation invocation) throws Throwable;

  /**
   * 代理
   *
   * @param target
   * @return
   */
  Object plugin(Object target);

  /**
   * 根据配置来初始化 Interceptor 方法
   * @param properties
   */
  void setProperties(Properties properties);

}

Which pluginis we need to achieve. The mybatis also provides us with a very convenient way.

  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;
  }

When we rewrite plugin method, simply call the above method can be. It will return Pluginan object of this class.

public class Plugin implements InvocationHandler
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // 获取方法所在类中, 可以被拦截的所有的方法
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      // 如果需要被拦截, 则调用 interceptor.intercept
      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);
    }
  }

Since JDK dynamic proxy is the interface level. Thus, agents that all methods of the class interface. However, not all methods are to be proxied, therefore, to distinguish the signature process by the information in the notes.

4 Chain of Responsibility design pattern

In the process of using plug-in, the chain of responsibility design pattern is reflected in the dynamic proxy deeply nested Agent enhancements. Reflected in the interceptorChain#pluginAllmethod. It will call upon layers of proxy. Principle mybatis plug - reflects the chain of responsibility and dynamic proxies

Guess you like

Origin www.cnblogs.com/homejim/p/11605228.html