深入刨析tomcat 之---第23篇 聊一下web容器的filter配置和defaultservet
writedby 张艳涛,在一个webapp应用程序内如何配置filter?
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <filter> <filter-name>DispatcherFilter</filter-name> <filter-class>appdesign2.filter.DispatcherFilter</filter-class> </filter> <filter-mapping> <filter-name>DispatcherFilter</filter-name> <url-pattern>/appdesign2/*</url-pattern> </filter-mapping> </web-app>
和<servlet>标签对比发现,二者是同一个层级上的,那么servlet被tomcat封装成一个standardWrapper,那么对Filter是如何处理的呢?
先看下webruleset对标签的解析
可见对web-app/filter的表情操作时生成了一个FilterDef 对象,并且加入的starndardcontex成员变量上去了
成员变量
对filter-mapping标签的解读
新建了一个FilterMap类型的对象,复制对象,将 web-app/filter-mapping/url-pattern 设置为setURLPattern
web-app/filter-mapping/filter-name 设置为 setFilterName
然后执行standardcontex的addFilterMap方法
接着在standardcontextvalue中调用invoke方法
进入到方法map内部,这个是一个standardcontextmapper
看到有4个规则
- 第一个直接匹配 servletMappings.get(pattern));找到对应的wrapper
- 和 /A/B/C/D/E,将这个路径后面+/* 进行匹配找到wrapper如果找不到去掉/E,使用/A/B/C/D/* 来查找,知道遍历全部
- /A/B/C/D/E .jpg先使用最后一个/E.jpg 如果有· 那么使用*.jpg进行匹配wrapper
- 以上都找不到,找default的servlet
那么名字为default的servlet以前没配置过,其实这个是在/conf目录下的web.xml中配置的
<servlet> <servlet-name>default</servlet-name> <servlet-class> org.apache.catalina.servlets.DefaultServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- The mapping for the default servlet --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
那么他是用来访问静态资源的比如你配置如下
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping>
那么一个,如果上述就会按照rule3 匹配到,那么当我们设置springmvc的时候
给springmvc的匹配规则就是"/" 而不能是"/*,否则什么都给匹配了,
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器,适配器等等) 如果不配置,默认加载的是/WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml(springmvc-servlet.xml) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
那么就是就是将"/"的rule匹配上了,将原来的"/"对于为default,现在"/"对于为springmvc dispatcherservlet,可见对于源码的解读有助于学习sprngmvc
接着聊
现在什么也没匹配到,则,实际上是通过如果不使用springmvc,那么tomcat在default之中,实现了对静态资源的访问,
那么接着看如何调用filter,
在standardwrappervalue之中
进入
进入
看到调用filter.doFilter(),方法,我们看自己定义的filter怎么写的
package appdesign2.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import appdesign2.action.SaveProductAction; import appdesign2.form.ProductForm; import appdesign2.model.Product; import java.math.BigDecimal; public class DispatcherFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String uri = req.getRequestURI(); /* * uri is in this form: /contextName/resourceName, for * example /appdesign2/input-product. However, in the * case of a default context, the context name is empty, * and uri has this form /resourceName, e.g.: * /input-product */ // action processing int lastIndex = uri.lastIndexOf("/"); String action = uri.substring(lastIndex + 1); String dispatchUrl = null; if ("input-product".equals(action)) { // do nothing dispatchUrl = "/jsp/ProductForm.jsp"; } else if ("save-product".equals(action)) { // create form ProductForm productForm = new ProductForm(); // populate action properties productForm.setName(request.getParameter("name")); productForm.setDescription( request.getParameter("description")); productForm.setPrice(request.getParameter("price")); // create model Product product = new Product(); product.setName(productForm.getName()); product.setDescription(product.getDescription()); try { product.setPrice(new BigDecimal(productForm.getPrice())); } catch (NumberFormatException e) { } // execute action method SaveProductAction saveProductAction = new SaveProductAction(); saveProductAction.save(product); // store model in a scope variable for the view request.setAttribute("product", product); dispatchUrl = "/jsp/ProductDetails.jsp"; } // forward to a view if (dispatchUrl != null) { RequestDispatcher rd = request .getRequestDispatcher(dispatchUrl); rd.forward(request, response); } else { // let static contents pass filterChain.doFilter(request, response); } } }
看的,如果先接着访问下一个filter就执行 filterChain.doFilter(request, response); 返回到上级方法的执行链在doFilter,
如果想打住就执行自己的操作,返回之后执行链会return
从而执行完了调用,返回的connector中,执行response.finish()方法,
这个filter的使用非常类似于自定义value