WEB基础组件-过滤器与监听器


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对象默认情况下,在服务器启动的时候会新建对象

ServletFilter是单例的

@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恢复到内存中


文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录