Java三大器详解(Listener,Filter,Interceptor)

在开始阅读这篇文章之前你应该对servlet有了基本的认识,如果没有可参考我的另外一篇文章——servlet及其生命周期。话不多说,今天开始介绍Java三大器:Listener,Filter,Interceptor。文章结构如图所示:

1.监听器(待补充)

2.过滤器

2.1定义功能

定义:Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,可以用来转换HTTP请求,响应和头信息。它不能产生一个请求或者响应,只是修改对某一资源的请求或响应;

功能:通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等。

2.2工作过程

2.2.1工作原理

 

 如上图所示

Filter接口中有一个doFilter()方法,当实现好Filter接口,并配置对哪个web资源进行拦截后,Web服务器每次在调用web资源的service方法之前,都会先调用一下Filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
    调用目标资源之前,让一段代码执行。
    是否调用目标资源(通过是否调用FilterChain对象的doFilter()方法实现)。
    调用目标资源之后,让一段代码执行。

web服务器在调用doFilter()方法时,会传递一个FilterChain对象进来,FilterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter()方法,如果调用FilterChain对象的doFilter()方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。如果不调用FilterChain对象的doFilter()方法,则web资源不会被访问。

2.2.2生命周期

Filter的生命周期和Servlet一样,Filter的创建和销毁也是由web服务器负责。

1.在应用启动的时候就进行加载Filter类。

2.容器创建好Filter对象实例后,调用init()方法,。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。

3.当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter()方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法。

4.当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。

注意:init方法与destroy方法只会直接一次。

2.3代码实现

Filter开发分为2步:

1.编写java类实现Filter接口,并重写其doFilter()方法。

public class FilterTest implements Filter {
    //对filter进行一个初始化
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter is initing please wait");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");
        //调用servlet方法前(访问web资源前执行的代码,相当于图中的code1)
        servletResponse.setContentType("text/html;charset=UTF-8");
        System.out.println("filter before service() do");
        filterChain.doFilter(servletRequest,servletResponse);
        //调用servlet方法后(获得web资源后执行的代码,相当于图中的code2)
        System.out.println("filter after service() do");

    }
    //调用destroy方法,filter被摧毁,生命周期结束
    @Override
    public void destroy() {
        System.out.println("filter is destroy");
    }
}

2.在web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。注册和映射的配置是必不可少的。

    <!--    过滤器配置一-->
    <filter>
        <filter-name>FilterTest</filter-name>
    <!--   要填写全类名-->
        <filter-class>com.zeron.anoservlet.FilterTest</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterTest</filter-name>
        <!-- /*表示拦截所有请求  -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。通过filterConfig对象的方法,就可获得:
  String getFilterName():得到filter的名称。
  String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
  Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
  public ServletContext getServletContext():返回Servlet上下文对象的引用。

2.4特性总结

应用场景:获取用户身份,参数校验,设置字符编码,过滤敏感词汇,权限访问控制等等

总结:所谓过滤器就是对请求进行过滤,作用在servlet之前,它是系统级别的过滤,在实现上基于函数回调,依赖于servlet容器。

3.拦截器

3.1定义功能

定义:Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。

功能:可以进行权限验证,审计日志等。

3.2工作过程

 如图所示:

①程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理其中的方法,否则将不再向下执行。

②在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向客户端返回响应。

③处理完所有业务后,才会执行afterCompletion()方法。

生命周期:加载配置文件后初始化拦截器,当有对Action的请求的时候,调用interceptor方法,最后也是根据服务器停止进行销毁;

对于多个拦截器的执行顺序(以2个为例)

1.请求指定Controller的url
2.拦截器1的preHandle():处理请求之前的业务,return true时
   拦截器2的preHandle():处理请求之前的业务,return true时
3.执行Controller的url
4.拦截器2postHandle():处理响应之前业务
   拦截器1postHandle():处理响应之前业务
5.视图渲染
6.拦截器2的afterCompletion():处理外所有业务之后执行【释放资源等】
   拦截器1的afterCompletion():处理外所有业务之后执行【释放资源等】

3.3代码实现(待补充)

3.4特性总结

Java里的拦截器提供的是非系统级别的拦截,就覆盖面来说,不如过滤器强大,但是更有针对性。
Java中的拦截器是基于Java反射机制实现的,更准确的划分,应该是基于JDK实现的动态代理。它依赖于具体的接口,在运行期间动态生成字节码。
拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或
者之后加入某些操作。

4.对比总结:

4.1过滤器和拦截器的执行顺序

4.2区别对比(简单理解过滤器为取你所想取,拦截器为拒你所想拒)

      1.拦截器是基于java的反射机制的,而过滤器是基于函数回调。
      2.拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
      3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
      4.拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
      5.在action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。

4.3其他补充:Tomcat中的filter分析

Tomcat中的Filter 是采用责任链设计模式。

首先通过StandardWrapperValve.invoke()方法创建一个过滤器链,并把待执行的 servlet 对象存放到过滤器链中。

 如果servlet对象和过滤器链都不为空,则开始调用filterChain的doFilter()方法。该方法有三个参数request对象,response对象,filter chain对象。如图

pos:为过滤器链中当前执行的过滤器下标。 n:过滤器链中的过滤器个数。

每执行一个过滤器则把过滤器链中的post+1(下标),直到所有的过滤器的doFilter方法都调用成功。

这行代码是整个责任链模式的精妙之处,进入doFilter()方法后,,首先会对request请求进行处理, 然后调用了过滤器链的doFilter()方法.,让每个过滤器可以调用过滤器链本身执行下一个过滤器。
为什么要调用过滤器链本身?因为当调用过滤器本身后, 程序将跳转回到过滤器链的doFilter方法执行, 这时pos为1, 也就是拿到第二个过滤器, 然后继续处理。
正是由于这个跳转, 使得过滤器中对response的处理暂时无法执行, 它必须等待上面的对过滤器链的方法返回才能被执行。执行流程如下图:

5.参考资料

https://blog.csdn.net/reggergdsg/article/details/52962774

https://blog.csdn.net/dianruanbin6930/article/details/102021043

https://www.cnblogs.com/hellovoyager1/p/9152292.html

https://blog.csdn.net/taifei/article/details/88572669

https://blog.csdn.net/m0_46425463/article/details/108011336

https://blog.csdn.net/u011464124/article/details/75097710

https://www.cnblogs.com/tanshaoshenghao/p/10741160.html

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的监听器(Listener)是一种广泛应用的设计模式,它用于处理程序中的事件。通过监听器,我们可以在事件发生时执行一些特定的操作。在Java中,我们可以使用内置的监听器API或自定义监听器实现此功能。 下面是Java中的常见监听器类型: 1. ActionListener:用于处理按钮、菜单等组件的动作事件。 2. WindowListener:用于处理窗口事件,如窗口打开、关闭等。 3. MouseListener:用于处理鼠标事件,如单击、双击、拖动等。 4. KeyListener:用于处理键盘事件,如键盘按下、释放等。 5. FocusListener:用于处理组件焦点事件,如获得或失去焦点等。 使用监听器的步骤如下: 1. 创建一个监听器类,该类实现了相应的监听器接口。 2. 在需要监听的组件上添加监听器对象。 3. 在监听器类中实现相应的方法来处理事件。 下面是一个简单的示例代码,演示了如何使用ActionListener监听器处理按钮单击事件: ```java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ButtonListenerDemo implements ActionListener { private JFrame frame; private JButton button; public ButtonListenerDemo() { frame = new JFrame("Button Listener Demo"); button = new JButton("Click Me"); button.addActionListener(this); frame.getContentPane().add(button); frame.pack(); frame.setVisible(true); } public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(frame, "Button Clicked!"); } public static void main(String[] args) { new ButtonListenerDemo(); } } ``` 在上面的代码中,我们创建了一个ButtonListenerDemo类,该类实现了ActionListener接口。在构造函数中,我们创建了一个按钮对象,然后将该按钮添加到窗口中,并将该按钮的监听器设置为当前类。当用户单击按钮时,程序将调用actionPerformed()方法来处理事件,该方法将弹出一个消息框来告诉用户按钮已被单击。 总之,监听器是Java编程中非常重要的组成部分。使用监听器,我们可以轻松地处理程序中的事件,并实现交互式用户界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值