問題:#
- filterChain 是什麼時候執行的呢?
- filterChain 中的 filter 來源何處?
- standardContext 什麼時候開始收集的過濾器集合
1. filterChain 是什麼時候執行的呢?#
在org.apache.catalina.core.StandardWrapperValve
類中有如下一個方法
public final void invoke(Request request, Response response)
throws IOException, ServletException {
//省略掉大段無關代碼
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
//省略掉大段無關代碼
try {
if (!unavailable) {
//1.create servlet
servlet = wrapper.allocate();
}
} catch(){
...
}
// 2. Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
Container container = this.container;
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
//execute doFilter method of the FilterChain object.
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
}
} else {
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
} catch(){
} finally {
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
}
}
}
我們一會兒回過頭來看它是如何創建過濾器鏈對象的代碼,我們先來看他是如何執行過濾器鏈的,過濾器鏈對象執行的流程實現:
public final class ApplicationFilterChain implements FilterChain {
//cur executing filter index
private int pos = 0;
//matched filter count
private int n = 0;
//servlet
private Servlet servlet = null;
//matched filter arrays
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
//security been turned on
if( Globals.IS_SECURITY_ENABLED ) {
//... security bean filter
} else {
//execute filter logic
internalDoFilter(request,response);
}
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// loop and Call the next filter if there is one
if (pos < n) {
//pos index ++
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
if( Globals.IS_SECURITY_ENABLED ) {
} else {
//execute the doFilter() of the cur filter in the filter chain
filter.doFilter(request, response, this);
}
} catch(){
...
}
return;
}
// We fell off the end of the chain -- call the servlet instance
try {
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
} else {
//if there are no filters to be executed, the servlet's service method will be executed, which contains the business logic that we have written.
servlet.service(request, response);
}
}catch(){
...
}finally{
...
}
}
}
從 filterChain 類的源碼可以看出底層是包含了 所匹配上的 filter 數組 也就是添加進去匹配上過濾器對象是有序的,添加的時候就決定了。
那麼它是什麼時候添加的呢?
2. filterChain 中的 filter 來源何處?#
其實在org.apache.catalina.core.StandardWrapperValve
類的 invoke 方法中
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {
// If there is no servlet to execute, return null
if (servlet == null)
return null;
// Create and initialize a filter chain object
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
// Acquire the filter mappings for this Context
StandardContext context = (StandardContext) wrapper.getParent();
//Get an array of all the filters registered in the ServletContext object
FilterMap filterMaps[] = context.findFilterMaps();
// If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0))
return filterChain;
// Acquire the information we will need to match filter mappings
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
String requestPath = null;
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
}
String servletName = wrapper.getName();
// Add the relevant path-mapped filters to this filter chain
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Add filters that match on servlet name second
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Return the completed filter chain
return filterChain;
}
可以看出在創建 filterChain 對象時,從 ServletContext 獲取所有註冊的 filter 的數組取出需要的添加到這次請求創建的 filterChain 對象,而且 servletContext 對象的註冊的所有的過濾器本身就是一個數組(本身就是有序的), 所以遍歷匹配的時候,也就是有序的。
3. ServletContext 什麼時候開始收集的數組#
filterMaps 在 StandardContext 類中
public class StandardContext extends ContainerBase
implements Context, NotificationEmitter {
private final ContextFilterMaps filterMaps = new ContextFilterMaps();
//
@Override
public void addFilterMap(FilterMap filterMap) {
validateFilterMap(filterMap);
// Add this filter mapping to our registered set
filterMaps.add(filterMap);
fireContainerEvent("addFilterMap", filterMap);
}
}
啟動 tomcat,我們可以根據堆棧查看調用順序
StandardContext.startInternal()
-->fireLifecycleEvent()
-->ContextConfig.lifecycleEvent()
-->ContextConfig.lifecycleEventcon
-->ContextConfig.con.figureStart()
-->ContextConfig.webConfig()
查看方法
protected void webConfig() {
if (ok) {
configureContext(webXml);
}
}
private void configureContext(WebXml webxml) {
for (FilterMap filterMap : webxml.getFilterMappings()) {
context.addFilterMap(filterMap);
}
}
這裡就將 web.xml 收集到所有 filter 的 set 集合,然後將收集到的 filter 集合轉換成數組,設置給 StandardContext 對象