Design Patterns in Tomcat - ValveBase Responsibility Chain

opening

Chain of responsibility mode: The chain of responsibility mode can be used in such a scenario. When a request comes, a series of processing needs to be done on the request. Using the chain of responsibility mode can make each process componentized and reduce coupling. It can also be used when a request comes and needs to find a suitable processing method. When a processing method is not suitable for the request, it is passed to the next processing method, and the processing method tries to process the request again.

The call between containers in tomcat uses the design pattern of chain of responsibility. When a request comes, the engine container first accepts the request, and then the engine container will pass the request to the host container, and the host container will pass it to the context container. The context container is passed to the wrapper container, and finally the wrapper container uses the servlet that adapts the request to process the request.
insert image description here

Chain of Responsibility Composition

Valve
 Valve, as each node on the responsibility chain, is mainly used to process the request object flowing to this node.

illustrate:

  • 1. A part of Valve's specific implementation class is shown in the figure above.
  • 2. Valve's abstract class ValveBase contains the Valve next element, that is, each Value contains an object pointing to the next Valve, similar to recursion.
public interface Valve {
    
    
    public Valve getNext();
    public void setNext(Valve valve);
    public void backgroundProcess();
    public void invoke(Request request, Response response) throws IOException, ServletException;
    public boolean isAsyncSupported();
}
public abstract class ValveBase extends LifecycleMBeanBase implements Contained, Valve {
    
    
    // 指向下一个Valve对象
    protected Valve next = null;

    public Valve getNext() {
    
    
        return next;
    }

    public void setNext(Valve valve) {
    
    
        this.next = valve;
    }

    public void backgroundProcess() {
    
    
    }
}
final class StandardEngineValve extends ValveBase {
    
    

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    
    

        Host host = request.getHost();
        if (host == null) {
    
    
            response.sendError
                (HttpServletResponse.SC_BAD_REQUEST,
                 sm.getString("standardEngine.noHost",
                              request.getServerName()));
            return;
        }
        if (request.isAsyncSupported()) {
    
    
            request.setAsyncSupported(host.getPipeline().isAsyncSupported());
        }

        host.getPipeline().getFirst().invoke(request, response);
    }
}

Pipeline

As a responsibility chain object, Pipeline mainly maintains Valve responsibility chain node objects.
StandardPipeline.png
Description:

  • 1. Pipeline is used as a responsibility chain object to maintain Valve responsibility chain objects.
  • 2. Pipeline includes the head node Valve first and the tail node Valve basic of the chain of responsibility object.
public interface Pipeline {
    
    

    public Valve getBasic();

    public void setBasic(Valve valve);

    public void addValve(Valve valve);

    public Valve[] getValves();

    public void removeValve(Valve valve);

    public Valve getFirst();

    public boolean isAsyncSupported();

    public Container getContainer();

    public void setContainer(Container container);

    public void findNonAsyncValves(Set<String> result);
}
public class StandardPipeline extends LifecycleBase
        implements Pipeline, Contained {
    
    

    public StandardPipeline() {
    
    
        this(null);
    }

    public StandardPipeline(Container container) {
    
    
        super();
        setContainer(container);
    }

    protected Valve basic = null;
    protected Container container = null;
    protected Valve first = null;

    public Valve getBasic() {
    
    
        return (this.basic);
    }

    public void setBasic(Valve valve) {
    
    
        Valve oldBasic = this.basic;
        if (oldBasic == valve)
            return;

        if (oldBasic != null) {
    
    
            if (getState().isAvailable() && (oldBasic instanceof Lifecycle)) {
    
    
                try {
    
    
                    ((Lifecycle) oldBasic).stop();
                } catch (LifecycleException e) {
    
    
                }
            }
            if (oldBasic instanceof Contained) {
    
    
                try {
    
    
                    ((Contained) oldBasic).setContainer(null);
                } catch (Throwable t) {
    
    
                }
            }
        }

        if (valve == null)
            return;
        if (valve instanceof Contained) {
    
    
            ((Contained) valve).setContainer(this.container);
        }
        if (getState().isAvailable() && valve instanceof Lifecycle) {
    
    
            try {
    
    
                ((Lifecycle) valve).start();
            } catch (LifecycleException e) {
    
    
                return;
            }
        }

        Valve current = first;
        while (current != null) {
    
    
            if (current.getNext() == oldBasic) {
    
    
                current.setNext(valve);
                break;
            }
            current = current.getNext();
        }
        this.basic = valve;
    }

    public void addValve(Valve valve) {
    
    
        if (valve instanceof Contained)
            ((Contained) valve).setContainer(this.container);

        if (getState().isAvailable()) {
    
    
            if (valve instanceof Lifecycle) {
    
    
                try {
    
    
                    ((Lifecycle) valve).start();
                } catch (LifecycleException e) {
    
    
                }
            }
        }

        if (first == null) {
    
    
            first = valve;
            valve.setNext(basic);
        } else {
    
    
            Valve current = first;
            while (current != null) {
    
    
                if (current.getNext() == basic) {
    
    
                    current.setNext(valve);
                    valve.setNext(basic);
                    break;
                }
                current = current.getNext();
            }
        }
        container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve);
    }


    public Valve getFirst() {
    
    
        if (first != null) {
    
    
            return first;
        }
        return basic;
    }
}

Responsibility chain element combination relationship

insert image description herechain of responsibility

illustrate:

  • 1. The container StandardEngine contains the chain of responsibility object StandardPipeline.
  • 2. StandardPipeline, as a responsibility chain object, includes responsibility grounding and Valve objects.
  • 3. Valve objects have some specific implementation classes such as StandardEngineValve objects.

chain of responsibility call stack

insert image description here
call stack

illustrate:

  • 1. Each container contains the chain of responsibility object Pipeline.
  • 2. The specific implementation of each responsibility object Valve will include the next container object, which means that the Valve object will access the next container internally, and then realize the chain of responsibility transfer.

Guess you like

Origin blog.csdn.net/riding_horse/article/details/132224145