深入刨析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个规则

  1. 第一个直接匹配 servletMappings.get(pattern));找到对应的wrapper
  2. 和 /A/B/C/D/E,将这个路径后面+/* 进行匹配找到wrapper如果找不到去掉/E,使用/A/B/C/D/* 来查找,知道遍历全部
  3.  /A/B/C/D/E .jpg先使用最后一个/E.jpg 如果有· 那么使用*.jpg进行匹配wrapper
  4. 以上都找不到,找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

posted @ 2021-07-25 16:43  张艳涛&java  阅读(157)  评论(0编辑  收藏  举报