This is the fifth day of my participation in the First Challenge 2022

Introduce a,

ParameterHandler is a parameter processor, StatementHandler is a StatementHandler statement processor, and parameterHandler is a StatementHandler statement processor. Result set processor ResultSetHandler etc. If the developer needs to perform some specific processing on a certain link of SQL execution, such as parameter type conversion, data paging function, printing executed SQL statements, etc., it can be achieved by mybatis plug-in mechanism.

Ii. Responsibility chain of Mybatis

The plugin mechanism of mybatis is actually to intercept an internal List array. After implementing the Interceptor interface, the business side will add the specific implementation class to the responsibility chain by InterceptorChain#addInterceptor. When mybatis initializes resources, The InterceptorChain#pluginAll invocation returns a proxy object that wraps all plug-ins inside core components (such as ParameterHandler) in a layer by layer proxy.

The real execution is because the inner core components are wrapped as proxy classes, so when an execution method is called, it is intercepted by the proxy object into the Invoke method to determine whether to execute the interceptor or the original method based on the class and annotations of the execution method.

public interface Interceptor {

  /** * intercepts the execution of the method **/
  Object intercept(Invocation invocation) throws Throwable;

  /** * insert **/
  Object plugin(Object target);

  /** * sets the property **/
  void setProperties(Properties properties);
}

public class InterceptorChain {

  /** * inside is a List of interceptors */
  private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

  public Object pluginAll(Object target) {
    // Loop through each interceptor.plugin method
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

  public List<Interceptor> getInterceptors(a) {
    returnCollections.unmodifiableList(interceptors); }}Copy the code

Three, filter related responsibility chain

In some check permissions interceptor, typically have a multi-layer interception, such as simple login process, first check the user name password is correct, check whether has an action after operation permissions will allows users access to resources, but if the user name password validation fails, there is no need to enter the second operation permission to check, So using the mybatis style chain of responsibility in this scenario is not appropriate. The following is the responsibility chain mode based on multi-layer interception, if one layer fails, it directly rejects further verification.

Interceptor by interceptor When an interceptor fails to execute, the system returns without continuing:

/** * interceptor interface **/
public interface Filter {

  /** * intercepts execution methods **/
  Object doFilter(Object target, FilterChain filterChain);
}

/** * implement A interceptor **/
class FilterA implements Filter{

  @Override
  public Object doFilter(Object target, FilterChain filterChain){
    System.out.println("A");
    // Select whether to continue down here, this way will go down
    returnfilterChain.doFilter(target); }}/** **/
class FilterB implements Filter{

  @Override
  public Object doFilter(Object target, FilterChain filterChain){
    System.out.println("B");
    // This method returns directly and does not continue with other interceptors (of course there are no other interceptors in my example)
    return ""; }}/** * maintains an array internally to store each interceptor **/
public static class FilterChain{

  private List<Filter> filters = new ArrayList<>();

  private Iterator iterator;

  public Object doFilter(Object target){

    if(iterator == null){
      iterator = filters.iterator();
    }

    if(iterator.hasNext()){
      Filter filter = (Filter) iterator.next();
      filter.doFilter(target, this);
    }
    return target;
  }

  public void addFilter(Filter filter){ filters.add(filter); }}/** * test **/
public static void main(String[] args) {
  FilterChain filterChain = new FilterChain();
  FilterA filterA = new FilterA();
  FilterB filterB = new FilterB();
  filterChain.addFilter(filterA);
  filterChain.addFilter(filterB);
  filterChain.doFilter("");
}
Copy the code

Four,

These are two different manifestations of the chain of responsibility, which are actually applied to different business scenarios. When all interceptions need to be executed in one round, the first one is used. The second method is used when an interception fails and subsequent interceptions do not proceed. In actual application scenarios, you need to take a comprehensive consideration and adopt the format that best meets the service scenario.