Responsibility chain mode and custom filter chain

What is the chain of Responsibility model:

This avoids coupling between the sender and receiver of the request by giving multiple objects the opportunity to process the request. Chain the object and pass the request along the chain until an object processes it.

Common understanding: the chain of responsibility model is like a product production line, each production shop after processing the product to the next production shop. As shown in figure:

Responsibility chain design pattern class diagram in Java:

Case Study 1:

There is now a collection of three processing methods, each of which determines whether there are conditions in the collection for the current method to execute, outputs if there are, and passes on the current request if there are no conditions suitable for its processing.

Here is an implementation snippet:

Abstract superclass:

public abstract class Hanler { protected Hanler successor; public void SetSuccessor(Hanler successor){ this.successor=successor; Public abstract void HandlerRequest(int Request); }Copy the code

Three roles in the chain of responsibility:

ConcreteHandler1

public class ConcreteHandler1 extends Hanler { @Override public void HandlerRequest(int request) { if(request>=0 && Request <10){system.out.println ("ConcreteHandler1 "+request); // Other logic} else if(succeeded! Succeeded =null){// Go to the next forgo.handlerRequest (request); }}}Copy the code

ConcreteHandler2:

public class ConcreteHandler2 extends Hanler { @Override public void HandlerRequest(int request) { if(request>=10 && Request <20){system.out. println("ConcreteHandle2 handle request "+request); // Other logic} else if(succeeded! Succeeded =null){// Go to the next forgo.handlerRequest (request); }}}Copy the code

ConcreteHandler3:

public class ConcreteHandler3 extends Hanler { @Override public void HandlerRequest(int request) { if(request>=20 && Request <30){system.out.println ("ConcreteHandler3 "+request); // Other logic} else if(succeeded! Succeeded =null){// Go to the next forgo.handlerRequest (request); }}}Copy the code

The main method: concatenates the implementation classes to form a “chain” as follows:

public static void main(String[] args) { Hanler h1 = new ConcreteHandler1(); Hanler h2 = new ConcreteHandler2(); Hanler h3 = new ConcreteHandler3(); // Tandem the implementation classes h1.setsucceeded (H2); h2.SetSuccessor(h3); Int [] requests =,15,20,62 {0}; for(int i=0; i<requests.length; i++){ h1.HandlerRequest(requests[i]); }}Copy the code

The test results are:

I believe that these code snippets should not be a problem for you to understand, the chain of responsibility model is so simple.

Chain of Responsibility model Case 2

If you have used SpringSecurity, you should be familiar with the chain of responsibility mode. Its principle design also uses the chain of responsibility mode. Below, we define a simple version of the chain of responsibility mode according to the Filter Filter.

Filter chain version 1 is implemented based on Filter

Create multiple classes to implement the Filter interface, using @ORDER annotation to specify the execution Order of each implementation class:

Filter1: MyFilter1 gets the requested address

@Component @Order(1) public class MyFilter1 implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" Execute MyFilter1 current request address ==" + request.getrequestURL ()); filterChain.doFilter(servletRequest,servletResponse); }}Copy the code

Filter 2: Obtain the request mode

@Component @Order(2) public class MyFilter2 implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" execute MyFilter2 current request method ==" + request.getMethod()); filterChain.doFilter(servletRequest,servletResponse); }}Copy the code

Filter 3: Get the request request URI

@Component @Order(3) public class MyFilter3 implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" Execute MyFilter3 current request URI==" + request.getrequesturi ()); filterChain.doFilter(servletRequest,servletResponse); }}Copy the code

The running results are shown as follows:

There is an @order () annotation on each of these filters, and we default to incrementing the value from the first filter to the third filter, which naturally results in all filters being executed in sequence.

Change the @order () value on the filter from myFilter3-myFilter1 as shown:

You can see that MyFilter3 is the first execution and MyFilter1 is the last execution!

As you can see from the example above, the @order () annotation can define the Order in which the filters are executed. In the previous version, we implemented the Filter interface for each Filter, overriding its methods, and then sorting the filters by the size of the @order () value.

Filter chain version 2 is implemented based on Filter

Design idea: it is not necessary for all filters in the Filter chain to implement the Filter interface. We can keep all filters in one set, and let one Filter call the Filter in the set.

Add MyFilter interface:

Public interface MyFilter {// public interface MyFilter {Boolean doFilter(ServletRequest Request, ServletResponse response, FilterChain chain) throws IOException, ServletException; }Copy the code

MyFilter1: Remove @Component and @Order annotations and control blocking or releasing by returning true or false

public class MyFilter1 implements MyFilter { @Override public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" Execute MyFilter1 current request address ==" + request.getrequestURL ()); Return true; // Block or pass by returning true or false; }}Copy the code

MyFilter2:

public class MyFilter2 implements MyFilter { @Override public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" execute MyFilter2 current request method ==" + request.getMethod()); return true; }}Copy the code

MyFilter3:

public class MyFilter3 implements MyFilter { @Override public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" Execute MyFilter3 current request URI==" + request.getrequesturi ()); return true; }}Copy the code

Define a Filter control class MyFilterContainer that implements Filter to execute the Filter. Here are the key points:

@Component public class MyFilterContainer implements Filter {// Public List<MyFilter> filterList=new ArrayList<>(); Private Integer current=0; @bean public void addFilter(){filterList.add(new MyFilter1()); filterList.add(new MyFilter2()); filterList.add(new MyFilter3()); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain FilterChain) throws IOException, ServletException {// Ensure that each request starts with the first interceptor. This.current =0; // Get the next filter and execute Boolean isDoNext= doMyFilter(servletRequest, servletResponse, filterChain); if(! IsDoNext){// Return false; } / / release filterChain doFilter (servletRequest, servletResponse); } // Get the next filter and execute private Boolean doMyFilter(ServletRequest ServletRequest, ServletResponse ServletResponse, FilterChain filterChain) throws IOException, MyFilter MyFilter = filterList.get(this.current); ServletException {// Get the executed filter object based on the current index MyFilter MyFilter = filterList.get(this.current); Boolean aBoolean = myFilter.doFilter(servletRequest, servletResponse, filterChain); if(aBoolean && this.current<this.filterList.size()-1){ this.current=this.current+1; Return doMyFilter(servletRequest, servletResponse, filterChain); } else if(aBoolean && this.current==this.filterList.size()-1){ return true; }else { return false; }}}Copy the code

The test results of the startup project are shown below:

The order in which filters are executed is determined by the order in which the filters are in the collection; switch to the following order

@Bean
    public void addFilter(){
        filterList.add(new MyFilter3());
        filterList.add(new MyFilter1());
        filterList.add(new MyFilter2());
       
    }
Copy the code

The running results are shown as follows:

Interception rule configuration tests

Now there is an interface:

@RestController public class FilterController { @GetMapping("test") public String test(){ return "hello filter"; }}Copy the code

If the request is /test, block otherwise. Simply change MyFilter3 as follows:

public class MyFilter3 implements MyFilter { @Override public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; System.out.println(" Execute MyFilter3 current request URI==" + request.getrequesturi ()); // If (! Request.getrequesturi ().equals("/test")){system.out.println ("MyFilter3 intercepts request, current request URI==" + request.getrequesturi ()); return false; } return true; }}Copy the code

Run tests:

As you can see from the figure above, the test results are in line with what we need, and returning intercepts is also easily extensible, not demonstrated here. That’s the end of this article!!

The last

This article starts from the responsibility chain design pattern, I believe that through this study we should also master the responsibility chain pattern, filter and other knowledge.