Filter接口
Servlet Filter也称为过滤器,用于拦截请求和响应,从而动态地改变包含在请求和响应中的信息。即在用户请求request到达相应的Servlet之前对其进行预处理,在服务器请求response到达客户端之前对其进行处理。
由于过滤器执行过程类似于「横切」(类似于Spring MVC中的拦截器),过滤器常常用于请求身份验证、请求乱码处理、日志记录等。
实现Filter
为了实现一个过滤器Filter,需要实现javax.servlet.Servlet
接口,该接口定义了以下三个方法:
1 2 3 4 5 6 7 8
| public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException; public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;
public void destroy(); }
|
这三个方法分别对应了Filter声明周期的三个阶段:
- 初始化阶段,Servlet容器负责加载和实例化Filter,读取
web.xml
配置文件中的配置信息对过滤器加载和实例化,之后调用过滤器的init()
方法。在整个声明周期中,init方法只执行一次,可以在该方法中执行一些初始化操作。
- 过滤阶段,当用户发送请求访问Web资源时,Servlet容器根据过滤器的配置规则(拦截路径)将请求进行拦截,并调用
doFilter()
方法,该方法有三个参数,分别是被拦截的请求request和响应response,还有过滤链chain对象,前二者用于处理用户请求和响应,chain对象用于控制请求的放行与否。
- 销毁阶段,Servlet容器只在最开始创建和加载过滤器,此后过滤器将一直存在内存中,知道最后Servlet容器关闭的时候,会调用过滤器的
destroy()
方法,该方法在整个生命周期中也只执行一次。
接下来,我们编写两个过滤器演示过滤器的工作过程:
过滤器一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class HelloFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("HelloFilter初始化...."); }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("HelloFilter拦截了请求...."); filterChain.doFilter(servletRequest, servletResponse); System.out.println("HelloFilter拦截了响应...."); }
@Override public void destroy() { System.out.println("HelloFilter被销毁...."); } }
|
过滤器二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class HelloFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("HelloFilter2初始化...."); }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("HelloFilter2拦截了请求...."); filterChain.doFilter(servletRequest, servletResponse); System.out.println("HelloFilter2拦截了响应...."); }
@Override public void destroy() { System.out.println("HelloFilter2被销毁...."); } }
|
在web.xml
中配置这两个过滤器及其过滤路径规则(也可以通过@WebFilter
注解来配置):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <servlet> <servlet-name>helloServlet</servlet-name> <servlet-class>com.fxd.HelloServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
<filter> <filter-name>helloFilter</filter-name> <filter-class>com.fxd.filter.HelloFilter</filter-class> </filter>
<filter> <filter-name>helloFilter2</filter-name> <filter-class>com.fxd.filter.HelloFilter2</filter-class> </filter>
<filter-mapping> <filter-name>helloFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter-mapping> <filter-name>helloFilter2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
这里将两个过滤器的路径都配置为/*
,即拦截所有请求。将容器跑起来,可以看到过滤器被初始化,通过浏览器输入/hello
路径访问helloServlet,可以看到请求先被第一个过滤器helloFilter
拦截,然后被第二个过滤器helloFilter2
拦截。关闭容器时,可以看到两个过滤器的销毁回调执行,下面是整个执行过程。
这里需要注意两个过滤器的拦截顺序,由web.xml配置文件中的标签顺序决定,也就是说,先配置的过滤器先对请求进行拦截,然后通过FilterChain
将其放行至下一个过滤器或者web资源,某一个过滤器在处理请求时不调用FilterChain.doFilter()
方法,则请求将在该过滤器终止。
FilterConfig接口
与ServletConfig
接口类似,FilterConfig
接口用于在过滤器初始化期间传递消息。可以在init()
方法中加入FilterConfig
类型的参数,就能够获得该对象。
1 2 3 4
| @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println(filterConfig.getFilterName()); }
|
该接口一共定义了四个方法:
返回类型 |
方法名 |
描述 |
String |
getInitParameter(String name) |
根据name获取该过滤器的初始化参数 |
Enumeration |
getInitParameterNames() |
获取过滤器中所有初始化参数的name |
ServletContext |
getServletContext() |
获取ServletContext对象 |
String |
getFilterName() |
返回过滤器的名称 |
Listener
Servlet中监听器Listener用于监听ServletContext
,HttpSession
以及ServletRequest
对象的生命周期或属性的变化,当相应的事件发生时,会调用监听器相关的回调函数。
Servlet共规定了以下监听器接口:
- 监听对象创建和销毁的监听器:
ServletContextListener
,HttpSessionListener
,ServletRequestListener
。
- 监听对象中属性变更的监听器:
ServletContextAttributeListener
,HttpSessionAttributeListener
。
以ServletContextListener
为例,实现该类型监听器时,需要实现该接口:
1 2 3 4 5 6 7 8 9 10 11
| public class HelloListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) {
}
@Override public void contextDestroyed(ServletContextEvent sce) {
} }
|
并将实现的监听器注册(也可以使用@WebListener
注解实现):
1 2 3
| <listener> <listener-class>com.fxd.listener.HelloListener</listener-class> </listener>
|
总结
本篇文章简要的介绍了Servlet中的过滤器和监听器的概念,其中过滤器应用比较广泛,当然在Spring中有拦截器用于实现类似的功能,还有AOP手段来实现横切式的编程。
参考文献
- C语言中文网Servlet教程