web基础组件之Filter与Listener
1. Filter的使用以及实现原理
Filter是什么?
图解:
我们可以将Servlet
看作是一个最终要执行的目标,我们可以使用过滤器Filter
添加过滤代码,这个过滤器添加在Servlet
执行之前,也可以添加到Servlet
执行之后执行。一般情况下都是在过滤器中编写公共代码。
过滤器与用户的请求路径相对应而且请求和响应都会经过过滤器。
- 定义一个过滤器类,实现一个过滤器接口
public interface Filter {
default void init(FilterConfig filterConfig)
throws ServletException {
}
//该方法在过滤器对象第一次被创建之后调用,并且只调用一次
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3)
throws IOException, ServletException;
//只要用户发送一次请求,则执行一次,发送N次请求,在这个方法中编写过滤的规则
default void destroy() {}
}
配置xml文件或者配置注解
<filter>
<filter-name>filter01</filter-name>
<filter-class>Filter03</filter-class>
</filter>
<filter-mapping>
<filter-name>filter01</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--在配置文件中,越靠上,执行顺序越先-->
Servlet
对象在默认情况下,在服务器启动的时候是不会新建对象的而
Filter
对象默认情况下,在服务器启动的时候会新建对象
Servlet
和Filter
是单例的
@WebFilter("*.do")//匹配以.do结尾的路径
public class Filter03 implements Filter {}
@WebFilter("*.do")
public class Filter03 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
//执行下一个过滤器,如果下一个不是过滤器了,直接就执行目标程序Servlet
System.out.println("开始走下一个过滤器/Servlet");
filterChain.doFilter(servletRequest,servletResponse);//到下一个地方去,对当前的request执行放行。
System.out.println("从上一个过滤器/Servlet过来了");
}
就有点像递归调用的意思,一个函数到另一个函数去,然后函数执行完毕之后,这个函数又回来了。
那么去的过程就对应了请求的一条路径上的处理,回来的时候就对应了响应的一条路径上的处理。
关于路径的配置
- 精确匹配:
/a.do
/*
匹配所有的路径/dept/*
前缀匹配*.do
后缀匹配
使用注解的时候,Filter的执行顺序是默认根据Filter类名的字典序来执行的。
比如说是Filter1和Filter2
配置了相同的拦截路径,这时候会先执行Filter1
关于Filter的生命周期
与Servlet基本保持一致,不同点在于初始化的时候,Filter是在web服务器启动时就初始化。而Servlet则是第一次被访问的时候才初始化
2. 责任链设计模式
在上面过滤器(Filter
)的实现方式中,可以抽象成这样的模型
public static void main(String[] args) {
System.out.println("begin");
m1();
System.out.println("end");
}
public static void m1(){System.out.println("do something");m2();}
public static void m2(){System.out.println("do something");m3();}
public static void m3(){System.out.println("do something");m4();}
public static void m4(){System.out.println("do something");m5();}
public static void m5(){System.out.println("do something");}
在编译阶段已经完全确定了调用的关系。
如果想要改变他们的调用关系或者调用顺序,必须修改java代码,这就违反了我们的开闭(OCP
)原则
当然了这是没有配置过滤器的情况下的。
但是实际上我们的Filter
的配置是通过web.xml
以及注解进行配置的,这样的配置不需要修改源代码,而且支持扩展,符合开闭原则。
责任链设计模式核心思想:在程序运行阶段,动态组合程序的调用顺序。那么在实际的web开发中,对于Filter
最好使用web.xml
进行配置。从而可以进行灵活的配置。
3. Listener监听器
如果我们想要在web
项目开发中,在一些特殊的时机触发的时候执行指定代码,那么监听器就为程序员提供了相关的接口。
public interface ServletContextListener extends EventListener {
default void contextInitialized(ServletContextEvent sce) {
//可以在这里进行初始化,例如网站的用户登录人数属性
}//在上下文对象被初始化的时候执行相关代码,事件对象
default void contextDestroyed(ServletContextEvent sce) {}//在上下文对象被摧毁的时候执行相关代码
}
<listener>
<listener-class>listenerDemo.Listener01</listener-class>
</listener>>
监听器中的方法,不需要程序员手动调用,这是由服务器来负责调用的,当指定的特殊事件发生之后,指派给监听器的方法会自动调用。
public class ServletContextEvent extends EventObject {
private static final long serialVersionUID = -7501701636134222423L;
public ServletContextEvent(ServletContext source) {
super(source);
}
public ServletContext getServletContext() {
return (ServletContext)super.getSource();
}
}
public class EventObject implements java.io.Serializable {}
public interface ServletContextAttributeListener extends EventListener {
default void attributeAdded(ServletContextAttributeEvent event) {}
default void attributeRemoved(ServletContextAttributeEvent event) {}
default void attributeReplaced(ServletContextAttributeEvent event) {}
}
域属性监听器是提供了一个添加、删除、替换的时机的监听。
BindingListener
public interface HttpSessionBindingListener extends EventListener {
default void valueBound(HttpSessionBindingEvent event) {}
default void valueUnbound(HttpSessionBindingEvent event) {}
}
监听的是绑定对象类型
public class User implements HttpSessionBindingListener{}
//监听普通java对象
//一旦往session里面放,就会触发监听器。
监听session
对象的活化与钝化
public interface HttpSessionActivationListener extends EventListener {
default void sessionWillPassivate(HttpSessionEvent se) {}
default void sessionDidActivate(HttpSessionEvent se) {}
}
钝化:当session
对象序列化写入到磁盘文件中,称为钝化
活化:从磁盘文件把session
恢复到内存中