4.34.3 FilterConfig对象的使用
FilterConfig对象是用来读取<filter>中<init-param>初始化参数的对象。该对象通过参数传递到init方法中,用于读取初始化参数。
通过name获取对应的value。
filterConfig.getInitParameter("name")
返回该Filter中所有中的值。
filterConfig.getInitParameterNames()
<filter> <filter-name>EncodingFilter</filter-name> <filter-class>cn.it.filter.EncodingFilter</filter-class> <init-param> <param-name>code</param-name> <param-value>gbk</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> <!--所有请求都能进入过滤器--> </filter-mapping>
package cn.it.filter; import javax.servlet.*; import java.io.IOException; public class EncodingFilter implements Filter { //设置默认编码 private String defaultEncoding = "UTF-8"; @Override public void init(FilterConfig filterConfig) throws ServletException { String code = filterConfig.getInitParameter("code"); //如果设置了编码方式就用设置的编码方式,没有设置就用默认的编码方式 if (code != null && code.length() > 0) { defaultEncoding = code; } } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding(defaultEncoding); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
4.34.4 FilterChain(过滤器链)
Filter技术的特点是在对请求或响应做预处理时,可实现“插拔式”的程序设计。我们可以根据自己需求添加多个Filter,也可以根据需求去掉某个Filter,通过修改web.xml文件即可实现。那么如果有多个过滤器对某个请求及响应进行过滤,那么这组过滤器就称为过滤器链。
Filter执行顺序
则按照在web.xml文件中配置的上下顺序来决定先后。在上的先执行,在下的后执行。
4.34.5 基于注解式开发Filter
Filter支持注解式开发,通过@WebFilter注解替代web.xml中Filter的配置。
属性名 | 类型 | 作用 |
filterName | String | 指定过滤器的 name 属性 |
urlPatterns | String[] | 拦截请求的URL,支持多个 |
value | String[] | 拦截请求的URL,支持多个 |
description | String | 过滤器的描述 |
displayName | String | 过滤器的显示名称 |
initParams | WebInitParam[] | 指定一组过滤器初始化参数,等价于 标签。 |
使用注解式开发Filter时,执行顺序会根据Filter的名称进行排序的结果决定调用的顺序。web.xml配置的优先级要高于注解。
package cn.it.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import java.io.IOException; @WebFilter(urlPatterns = "/ann.do",initParams = { @WebInitParam(name = "key",value = "web"), @WebInitParam(name = "key2",value = "java") }) public class AnnotationFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { String key1 = filterConfig.getInitParameter("key1"); String key2 = filterConfig.getInitParameter("key2"); System.out.println(key1); System.out.println(key2); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("请求处理"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("响应处理"); } @Override public void destroy() { } }
4.34.6 Filter的生命周期
Filter的生命周期是由容器管理的。当容器启动时会实例化Filter并调用init方法完成初始化动作。当客户端浏览器发送请求时,容器会启动一个新的线程来处理请求,如果请求的URL能够被过滤器所匹配,那么则先调用过滤器中 的doFilter方法,再根据是否有chain.doFilter的指令,决定是否继续请求目标资源。当容器关闭时会销毁Filter对象,在销毁之前会调用destroy方法。
4.35 Listener监听器
监听器用于监听web应用中某些对象的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器会自动调用监听器对象中的方法。
监听器分类
按监听的对象划分,可以分为:
- ServletContext对象生命周期监听器与属性操作监听器;
- HttpSession对象生命周期监听器与属性操作监听器;
- ServletRequest对象生命周期监听器与属性操作监听器;
4.35.1 ServletContext对象的生命周期监听器
ServletContextListener接口定义了ServletContext对象生命周期的监听行为。
void contextInitialized(ServletContextEvent sce)
ServletContext对象创建之后会触发该监听方法,并将ServletContext对象传递到该方法中。
void contextDestroyed(ServletContextEvent sce)
ServletContext对象在销毁之前会触发该监听方法,并将ServletContext对象传递到该方法中。
<!--配置ServletLifeCircleListener--> <listener> <listener-class>cn.it.listener.ServletLifeCircleListener</listener-class> </listener>
package cn.it.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class ServletLifeCircleListener implements ServletContextListener { //监听ServletContext创建的监听方法(容器启动时创建ServletContext对象,而且只会创建一个) @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("servletContextInitialized:"+sce.getServletContext()); } //监听ServletContext销毁的监听方法(容器关闭时销毁ServletContext对象) @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("servletContextDestroyed:"+sce.getServletContext()); } }
4.35.2 ServletContext对象的属性操作监听器
ServletContextAttributeListener接口定义了对于ServletContext对象属性操作的监听行为。
void attributeAdded(ServletContextAttributeEvent scae)
向ServletContext对象中添加属性时会触发该监听方法,并将ServletContext对象传递到该方法中。触发事件的方法servletContext.setAttribute("key","value")。
void attributeRemoved(ServletContextAttributeEvent scae)
当从ServletContext对象中删除属性时会触发该监听方法,并将ServletContext对象传递到该方法中。触发事件方法servletContext.removeAttribute("key")。
void attributeReplaced(ServletContextAttributeEvent scae)
当从ServletContext对象中属性的值发生替换时会触发该监听方法,并将ServletContext对象传递到该方法中。触发事件的方法servletContext.setAttribute("key","value")。
<!--配置ServletContextAttrListener--> <listener> <listener-class>cn.it.listener.ServletContextAttrListener</listener-class> </listener>
package cn.it.listener; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(urlPatterns = "/context.do") public class ServletContextAttrServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取ServletContext ServletContext servletContext = this.getServletContext(); servletContext.setAttribute("servletContextKey","123"); servletContext.setAttribute("servletContextKey",111); servletContext.removeAttribute("servletContextKey"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
package cn.it.listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; public class ServletContextAttrListener implements ServletContextAttributeListener { @Override public void attributeAdded(ServletContextAttributeEvent scae) { System.out.println("-------------addStart-------------------"); System.out.println("监听添加属性:"+scae.getName()+"="+scae.getValue()); ServletContext servletContext = scae.getServletContext(); System.out.println("--------------addend------------------"); } @Override public void attributeRemoved(ServletContextAttributeEvent scae) { System.out.println("-------------removeStart-------------------"); System.out.println("监听删除属性:"+scae.getName()+"="+scae.getValue()); ServletContext servletContext = scae.getServletContext(); System.out.println("--------------removeEnd------------------"); } @Override public void attributeReplaced(ServletContextAttributeEvent scae) { System.out.println("-------------replaceStart-------------------"); System.out.println("监听替换属性:"+scae.getName()+"="+scae.getValue()); ServletContext servletContext = scae.getServletContext(); System.out.println("--------------replaceEnd------------------"); } }
4.35.3 HttpSession对象的生命周期监听器
HttpSessionListener接口定义了HttpSession对象生命周期的监听行为。
void sessionCreated(HttpSessionEvent se)
HttpSession对象创建后会触发该监听方法,并将已创建HttpSession对象传递到该方法中。
void sessionDestroyed(HttpSessionEvent se)
HttpSession对象在销毁之前会触发该监听方法,并将要销毁的HttpSession对象传递到该方法中。
<!--配置HttpSessionLifeCircleListener--> <listener> <listener-class>cn.it.listener.HttpSessionLifeCircleListener</listener-class> </listener> <session-config> <session-timeout>1</session-timeout> </session-config>
package cn.it.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class HttpSessionLifeCircleListener implements HttpSessionListener { //监听HttpSession对象创建的方法 @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("session对象创建:"+se.getSession()); } //监听HttpSession对象销毁的方法 @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("session对象销毁:"+se.getSession()); } }
4.35.4 HttpSession对象的属性操作监听器
HttpSessionAttributeListener接口定义了对于HttpSession对象属性操作的监听行为。
void attributeAdded(HttpSessionBindingEvent se)
向HttpSession对象中添加属性时会触发该监听方法,并将HttpSession对象传递到该方法中。触发事件的方法HttpSession.setAttribute("key","value")。
void attributeRemoved(HttpSessionBindingEvent se)
当从HttpSession对象中删除属性时会触发该监听方法,并将HttpSession对象传递到该方法中。触发事件方法HttpSession.removeAttribute("key")。
void attributeReplaced(HttpSessionBindingEvent se)
当从HttpSession对象中属性的值发生替换时会触发该监听方法,并将HttpSession对象传递到该方法中。触发事件的方法HttpSession.setAttribute("key","value")。
<!--配置HttpSessionAttrListener--> <listener> <listener-class>cn.it.listener.HttpSessionAttrListener</listener-class> </listener>
package cn.it.listener; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/sessionAttr.do") public class HttpSessionAttrServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); session.setAttribute("sessionKey","123"); session.setAttribute("sessionKey",1123); session.removeAttribute("sessionKey"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
package cn.it.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; public class HttpSessionAttrListener implements HttpSessionAttributeListener { @Override public void attributeAdded(HttpSessionBindingEvent se) { System.out.println("-------------addStart-------------------"); System.out.println("监听添加属性:"+se.getName()+"="+se.getValue()); System.out.println(se.getSession()); System.out.println("--------------addend------------------"); } @Override public void attributeReplaced(HttpSessionBindingEvent se) { System.out.println("-------------replaceStart-------------------"); System.out.println("监听替换属性:"+se.getName()+"="+se.getValue()); System.out.println(se.getSession()); System.out.println("--------------replaceEnd------------------"); } @Override public void attributeRemoved(HttpSessionBindingEvent se) { System.out.println("-------------removeStart-------------------"); System.out.println("监听删除属性:"+se.getName()+"="+se.getValue()); System.out.println(se.getSession()); System.out.println("--------------removeEnd------------------"); } }
4.35.5 HttpServletRequest对象的生命周期监听器
ServletRequestListener接口定义了ServletRequest(是HttpServletRequest接口的父接口类型)对象生命周期的监听行为。
void requestInitialized(ServletRequestEvent sre)
HttpServletRequest对象创建后会触发该监听方法,并将已创建HttpServletRequest对象传递到该方法中。
void requestDestroyed(ServletRequestEvent sre)
HttpServletRequest对象在销毁之前会触发该监听方法,并将要销毁HttpServletRequest对象传递到该方法中。
<!--配置HttpServletRequestCircleListener--> <listener> <listener-class>cn.it.listener.HttpServletRequestCircleListener</listener-class> </listener>
package cn.it.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; public class HttpServletRequestCircleListener implements ServletRequestListener { @Override public void requestInitialized(ServletRequestEvent sre) { System.out.println((HttpServletRequest)sre.getServletRequest()+"创建-----------"); } @Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println((HttpServletRequest)sre.getServletRequest()+"销毁-----------"); } }
4.35.6 HttpServletRequest对象的属性操作监听器
<!--配置HttpServletRequestAttrListener--> <listener> <listener-class>cn.it.listener.HttpServletRequestAttrListener</listener-class> </listener>
package cn.it.listener; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/reqAttr.do") public class HttpServletRequestAttrServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setAttribute("requestKey","123"); req.setAttribute("requestKey","123123123"); req.removeAttribute("requestKey"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
package cn.it.listener; import javax.servlet.ServletContext; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; public class HttpServletRequestAttrListener implements ServletRequestAttributeListener { @Override public void attributeAdded(ServletRequestAttributeEvent srae) { System.out.println("-------------addStart-------------------"); System.out.println("监听添加属性:"+srae.getName()+"="+srae.getValue()); System.out.println(srae.getServletRequest()); System.out.println("--------------addend------------------"); } @Override public void attributeReplaced(ServletRequestAttributeEvent srae) { System.out.println("-------------replaceStart-------------------"); System.out.println("监听替换属性:"+srae.getName()+"="+srae.getValue()); System.out.println(srae.getServletRequest()); System.out.println("--------------replaceEnd------------------"); } @Override public void attributeRemoved(ServletRequestAttributeEvent srae) { System.out.println("-------------removeStart-------------------"); System.out.println("监听删除属性:"+srae.getName()+"="+srae.getValue()); System.out.println(srae.getServletRequest()); System.out.println("--------------removeEnd------------------"); } }
4.35.7 基于注解式开发监听器
Listener支持注解式开发,通过@WebListener注解替代web.xml中Listener的配置。
@WebListener public class HttpServletContextAttrListener implements ServletContextAttributeListener {}
@WebListener public class HttpServletContextLifeCircleListener implements ServletContextListener {}
4.36 Filter与Listener设计模式
“知其然,知其所以然”。面试会问。
4.36.1 Filter的设计模式
在Servlet的Filter中使用的责任链设计模式。
责任链模式特点
责任链(Chain of Responsibility):责任链模式也叫职责链模式,是一种对象行为模式。在责任链模式里,很多对象由每一个对象对其下一个对象的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不需要知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
责任链的优缺点
优点:
- 降低了对象之间的耦合度。
- 增强了系统的可扩展性。
- 增强了给对象指派职责的灵活性。
- 责任链简化了对象之间的连接。
- 责任分担。每个类只需要处理自己该处理的工作。
缺点:
- 不能保证请求一定被接收。
- 对比较长的责任链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 可能会由于责任链的错误设置而导致系统出错,如可能会造成循环调用。
4.36.2 Listener的设计模式
在Servlet的Listener中使用的观察者设计模式。
观察者模式的特点
观察者模式(Observer Pattern):观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式的优缺点
优点:
- 观察者和被观察者是抽象耦合的。
- 建立一套触发机制。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。