Welcome to “Algorithms and the Beauty of Programming” ↑ pay attention to us!
This article was first published on the wechat official account “Beauty of Algorithms and Programming”. Welcome to follow and learn more about this series of blogs in time.
In the first lecture, we explained that when a request arrives at a Servlet, the ServletRequest and ServletResponse are first converted to HttpServletRequest and HttpServletResponse. It then gets the method type of the HTTP request, and finally invokes different methods based on the different method types. For more information, please read the doGet method of Tomcat source analysis (I).
In the first lecture we focused on figuring out everything that happens when a request reaches the Servlet. What happens before the request reaches the Servlet?
Many, many things happen before a request reaches the Servlet, which is the subject of this blog series. This tutorial will focus on the request passing through a series of filters before reaching the Servlet. How is Tomcat’s Filter mechanism implemented?
1 goal
In-depth understanding of Tomcat filter mechanism and internal implementation principle of ApplicationFilterChain.
2 Analysis Methods
According to the last stack information, combined with Intellij Idea stack view, breakpoints, single step debugging and other means of source analysis.
4. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
5.at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
6.at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
7.at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
8.at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
3 Analysis Process
You can see from the figure above that before the request reaches the Servlet, it passes through a series of filters Filter1 Filter2… FilterN, what we need to explore in this lecture is how Tomcat implements this mechanism.
3.1 Simple implementation of filter mechanism
How do we implement this filter mechanism if we implement it ourselves?
Let’s start with a simple implementation.
/ / code 1
Filter[] filters;
for (Filter filter : filters){
filter.doFilter(req, resp);
}
servlet.service(req, resp);
Copy the code
The simplest way to do this is to define an array of filters, iterate through each filter in that array and execute it, and then the request arrives at the Servlet and calls the Service method.
This approach does achieve the process described above, but there is a serious problem.
When a request reaches a filter, if it does not meet the filter’s requirements, the request is not passed to the next filter.
The code above, on the other hand, executes all filters no matter what, so it can’t handle the special case mentioned above.
3.2 Improved version of filter mechanism
Through careful analysis of the above issues, we found that each filter can decide for itself whether to pass requests to the next filter, whether to pass requests to the next filter if certain requirements are met, or not, to the Servlet.
How to implement this mechanism?
First let’s implement code 1 above in a different way:
/ / code 2
Filter[]filters;
int n = filters.length;
int pos = 0;
while( pos < n){
Filter filter = filters[pos++];
filter.doFilter(req, resp);
}
Copy the code
Define a filter index pos to indicate the current filter position and iterate through the while loop. This code should be simple, except that the for loop becomes the while loop.
Isn’t that a change of scenery? Not much has changed.
Now, can we iterate through this array without using any loops?
Can you iterate through an array without using any loop structure? That’s funny, right? I’ve never seen that before.
Now we’ll show you a way to iterate without using any loop structure.
public class FilterChain {
private int pos = 0; // Current filter subscript
private int n; // Filter array size
private Filter[] filters;
public void doFilter(ServletRequestreq, ServletResponse resp){
if(pos < n){
Filter filter = filters[pos++];
filter.doFilter(req, resp, this);
}
servlet.service(req, resp);
}
// Other code omitted
}
Copy the code
Start by defining a class, FilterChain, whose property code is commented out similar to the previous code 2.
Focus on the doFilter method, first check whether the current index exceeds the size of the array, if not, get the current filter, index increment, and then execute the filter.
You start with pos being 0, so you get the first filter and execute it, and then you go to the servlet method. Have you ever traversed the entire array? It’s just executing the first filter.
Don’t worry, guest officer. Here are the highlights:
public class SampleFilter implements Filter {
@Override
public void doFilter(ServletRequestreq, ServletResponse resp, FilterChain filterChain) {
System.out.println("do something!"); filterChain.doFilter(req, resp); }}Copy the code
For each Filter, there is one line of code in the doFilter method that is critical, and that is filterchain-dofilter (req, resP). After executing the doFilter method of the first Filter, We’re back in the filterChain, and pos=1 points to the second filter. That’s the essence of design.
if(pos < n){ // After the first filter, the value of pos is 1
Filter filter = filters[pos++];
filter.doFilter(req, resp, this);
}
Copy the code
Similarly, when all filters have been executed and pos == n, the if statement executes the servlet method.
The above is a kind of design idea that can be completed without using any loop structure, is not very interesting. The core design idea is to use a single index to record the current element, and then each element, when executed, returns to where it started.
Using this design idea, you can rewrite many of the loop structures you’ve written before. Practice can help you understand this design idea better.
If a request does not meet the requirements of a filter, the doFilter method of filterChain will not be executed, which means that the if criterion will not be returned, and the next filter will not be available. Therefore, the servlet will be directly skipped.
3.3 Source code analysis of Tomcat filter mechanism
With this foundation in mind, it is easy to understand the implementation of Tomcat’s filter mechanism. The implementation mechanism of Tomcat Filter mainly involves the core class ApplicationFilterChain and interface Filter.
The Filter interface is defined as follows:
public interface Filter {
public default void init(FilterConfigfilterConfig) throws ServletException {}
public void doFilter(ServletRequestrequest, ServletResponse response, FilterChain chain) throws IOException,ServletException;
public default void destroy(a) {}}Copy the code
The core implementation code for the filter mechanism is:
private void internalDoFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
/ /..
Filter filter =filterConfig.getFilter();
filter.doFilter(request,response, this);
/ /...
return;
}
// We fell off the end of the chain --call the servlet instance
servlet.service(request,response);
}
Copy the code
We’ve blocked out a lot of irrelevant code, keeping only the core code, just to help you understand how it works.
Now that we understand the core mechanism of filters, let’s go back to the execution stack in lecture 1.
From the first test case, we did not configure any filters, but from the stack information above, we can see that the request is passed through a filter named WsFilter. Why? Welcome to leave a message.
6.at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
4 summarizes
This lecture mainly discusses the request before reaching the Servlet will pass through a series of filters, from the perspective of Tomcat source code in-depth analysis of the filter implementation mechanism, its implementation of the core class is ApplicationFilterChain.
From Lecture 1 and Lecture 2 we know that a request goes through a series of filters before it reaches the Servlet. Careful, you might ask, what happens to the request before it reaches the filter?
To know what will happen next, please continue to follow the “Beauty of Algorithms and programming” wechat public account, timely learn more exciting articles.
DoGet method for Tomcat source Code Analysis (1)
Append method for StringBuffer source analysis