filter的执行顺序
一直没有仔细去研究下filter ,最近系统的测试了下:
先看代码吧
FirstFilter.java ================== package com.test.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class FirstFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("before invoke firstFilter's chain.doFilter() .."); chain.doFilter(request, response); System.out.println("after invoke firstFilter's chain.doFilter() .."); } @Override public void init(FilterConfig arg0) throws ServletException { System.out.println("firstFilter init()..."); } } ============ SecondFilter.java ============== package com.test.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class SecondFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("before invoke secondFilter's chain.doFilter() .."); chain.doFilter(request, response); System.out.println("after invoke secondFilter's chain.doFilter() .."); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("secondFilter init()..."); } } ========== FirstServlet.java ============= package com.test.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class FirstServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet doGet be invoked..."); req.getRequestDispatcher("test.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub doGet(req, resp); } }
web.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <filter> <filter-name>firstFilter</filter-name> <filter-class>com.test.filter.FirstFilter</filter-class> </filter> <filter> <filter-name>secondFilter</filter-name> <filter-class>com.test.filter.SecondFilter</filter-class> </filter> <filter-mapping> <filter-name>secondFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>firstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>firstServlet</servlet-name> <servlet-class>com.alimama.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>firstServlet</servlet-name> <url-pattern>/firstServlet</url-pattern> </servlet-mapping> </web-app>
然后发布,发现打印的日志如下:
。。。
firstFilter init()...
secondFilter init()...
。。。
2008-10-23 11:36:43 org.apache.catalina.startup.Catalina start
信息: Server startup in 3665 ms
这里过滤器初始化好了。
当我们访问我们的 应用:http://127.0.0.1:8080/appName
发现打印日记如下:
before invoke secondFilter's chain.doFilter() ..
before invoke firstFilter's chain.doFilter() ..
after invoke firstFilter's chain.doFilter() ..
after invoke secondFilter's chain.doFilter() ..
当我们将web.xml中filter的位置进行调整后:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <filter> <filter-name>firstFilter</filter-name> <filter-class>com.test.filter.FirstFilter</filter-class> </filter> <filter> <filter-name>secondFilter</filter-name> <filter-class>com.test.filter.SecondFilter</filter-class> </filter> <span style="color: rgb(255, 0, 0);" mce_style="color: #ff0000;"> <filter-mapping> <filter-name>firstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>secondFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping></span> <servlet> <servlet-name>firstServlet</servlet-name> <servlet-class>com.alimama.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>firstServlet</servlet-name> <url-pattern>/firstServlet</url-pattern> </servlet-mapping> </web-app>
然后在启动应用,会看到打印:
before invoke firstFilter's chain.doFilter() ..
before invoke secondFilter's chain.doFilter() ..
after invoke secondFilter's chain.doFilter() ..
after invoke firstFilter's chain.doFilter() ..
总结:
filter的执行顺序是按照web.xml中定义的顺序进行执行的(当多个filter都匹配的时候),执行顺序如下图表示。(PS图取自http://hi.baidu.com/cathy_200182/blog/item/1f686238df10eb22b8998fe3.html 感谢之)
出处:http://esteem.javaeye.com/blog/256894
FilterChain 执行过程
下面是一个避免提交数据乱码问题的EncodingFilter:
package anni; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class EncodingFilter implements Filter { public void init(FilterConfig config) throws ServletException {} public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("gb2312"); chain.doFilter(request, response); } }
相应的web.xml为:
<filter> <filter-name>EncodingFilter</filter-name> <filter-class>anni.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
过滤控制访问权限的SecurityFilter:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; HttpSession session = req.getSession(); if (session.getAttribute("username") != null) { chain.doFilter(request, response); } else { res.sendRedirect("../failure.jsp"); } }
相应的web.xml为:
<filter> <filter-name>SecurityFilter</filter-name> <filter-class>anni.SecurityFilter</filter-class> </filter> <filter-mapping> <filter-name>SecurityFilter</filter-name> <url-pattern>/admin/*</url-pattern> </filter-mapping>
EncodingFilter负责设置编码,SecurityFilter负责控制权限,那这两个过滤器是怎么起作用的呢?它们两个同时过滤一个请求时谁先谁后呢?
所有的奥秘就在Filter中的FilterChain中。服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的 doFilter()方法。执行的顺序就如上图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的 chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的 chain.doFilter()之后的代码,最后返回响应。
因此在07-02中执行的代码顺序是:
-
执行EncodingFilter.doFilter()中chain.doFilter()之前的部分:request.setCharacterEncoding("gb2312");
-
执行SecurityFilter.doFilter()中chain.doFilter()之前的部分:判断用户是否已登录。
如果用户已登录,则访问请求的资源:/admin/index.jsp。
如果用户未登录,则页面重定向到:/failure.jsp。
-
执行SecurityFilter.doFilter()中chain.doFilter()之后的部分:这里没有代码。
-
执行EncodingFilter.doFilter()中chain.doFilter()之后的部分:这里也没有代码。
过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题,像EncodingFilter就一定要放在所有Filter之前,这样才能确保在使用请求中的数据前设置正确的编码。
出处:http://blog.csdn.net/wibnmo/archive/2009/10/22/4714227.aspx