JAVAWeb中Listener、Filter、Interceptor、servlet的区别

563 阅读6分钟

JAVAWeb中Listener、Filter、Interceptor、servlet的区别

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

1.生命周期

在springboot 我们利用controller基本都可以完成web开发,但是在一些情况 我们是需要用到Filter、Servlet、Listener、Interceptor来完成一些需求的 接下来主要就是写一下关于Filter、Servlet、Listener、Interceptor的认识以及在springboot和web.xml中的写法及他们的区别

1.Filter

(1)、启动服务器时加载过滤器的实例,并调用init()方法来初始化实例; 
(2)、每一次请求时都只调用方法doFilter()进行处理; 
(3)、停止服务器时调用destroy()方法,销毁实例。

2.Listener

Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。

3.Interceptor

以struts的拦截器为例,加载了struts.xml以后,初始化相应拦截器。当action请求来时调用intercept方法,服务器停止销毁interceptor。

4.Servlet

servlet:一般继承HttpServlet(一般的,通用Servlet由javax.servlet.GenericServlet实现Servlet接口。javax.servlet.http.HttpServlet实现了专门用于响应HTTP请求的Servlet,提供了响应对应HTTP标准请求的doGet()、doPost()等方法)。servlet一旦被加载,一般不会从容器中删除,直至应用服务器关闭或重新启动。但当容器做内存回收动作时,servlet有可能被删除。也正是因为这个原因,第一次访问servlet所用的时间要大大多于以后访问所用的时间。servlet在服务器的运行生命周期为,在第一次请求(或其实体被内存垃圾回收后再被访问)时被加载并执行一次初始化方法,跟着执行正式运行方法,之后会被常驻并每次被请求时直接执行正式运行方法,直到服务器关闭或被清理时执行一次销毁方法后实体销毁。 (1)、装入:启动服务器时加载Servlet的实例; 
(2)、初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工作有init()方法负责执行完成; 
(3)、调用:从第一次到以后的多次访问,都是只调用doGet()或doPost()方法; 
(4)、销毁:停止服务器时调用destroy()方法,销毁实例。

2.代码展示 (springboot 和web.xml)

1.Filter

1.1SpringBoot项目中

import org.springframework.stereotype.Component;

import javax.servlet.*;
import java.io.IOException;

/**
 * 函数回调DEMO
 */
@Component
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException{
        //在服务器启动后,初始化作用
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws  ServletException {
        //执行拦截的动作,具体的拦截逻辑写在这里
        //doFilter:每一次请求被拦截资源时,会执行。执行多次
        System.out.println("MyFilter被执行了....");

        //放行
        try {
            filterChain.doFilter(servletRequest,servletResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void destroy() {
        //服务器关闭后,Filter对象被销毁。
    }
}

2.1 web.xml项目中

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        version="4.0">
    <!-- 过滤器配置 -->
    <filter>
        <filter-name>enCodingFilter</filter-name>
        <filter-class>com.wzy.filter.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>enCodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

import javax.servlet.*;
import java.io.IOException;

/**
 * 函数回调DEMO
 */
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException{
        //在服务器启动后,初始化作用
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws  ServletException {
        //执行拦截的动作,具体的拦截逻辑写在这里
        //doFilter:每一次请求被拦截资源时,会执行。执行多次
        System.out.println("MyFilter被执行了....");

        //放行
        try {
            filterChain.doFilter(servletRequest,servletResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void destroy() {
        //服务器关闭后,Filter对象被销毁。
    }
}

2.Listener

2.1 SpringBoot项目中(页面请求监听)

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class DemoMain {

    public static void main(String[] arg){
        SpringApplication.run(DemoMain.class,arg);
    }
}

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
/**
 * 监听demo
 */
@WebListener
public class MyServletRequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {

        System.out.println("---------------------------->请求销毁");
    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {

        System.out.println("---------------------------->请求创建");
    }
}

2.2 web.xml项目中(用户计数)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        version="4.0">
    <listener>
        <listener-class>MyHttpSessionListener</listener-class>
    </listener>

    <listener>
        <listener-class>MyServletContextListener</listener-class>
    </listener>
</web-app>

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;


public class MyServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext sc = servletContextEvent.getServletContext();
        sc.setAttribute("peopleNum", 0);//初始化用户人数0
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * 用户监听DEMO
 */
public class MyHttpSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("httpsession被创建");
        countPersion( httpSessionEvent.getSession().getServletContext(), true);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("httpsession被销毁");
        countPersion(httpSessionEvent.getSession().getServletContext(), false);
    }


    /**
     * 改变用户人数
     * @param sc
     * @param isAdd
     */
    public void countPersion(ServletContext sc, boolean isAdd) {
        // 为了防止多线程并发问题加锁
        synchronized (sc) {
            // 获得当前的在线人数
            Integer count = (Integer) sc.getAttribute("peopleNum");
            if(isAdd) {//判断新增还是销毁
                sc.setAttribute("peopleNum", ++count);
            } else  {
                sc.setAttribute("peopleNum", --count);
            }
        }
    }
}

2.3 补充

1.ServletContextListener -- 监听servletContext对象的创建以及销毁

1.1 contextInitialized(ServletContextEvent sce)   -- 创建时执行

1.2 contextDestroyed(ServletContextEvent sce)  -- 销毁时执行

2.ServletContextAttributeListener -- 监听servletContext对象中属性的改变

2.1 attributeAdded(ServletContextAttributeEvent scae) -- 添加属性时执行

2.2 attributeRemoved(ServletContextAttributeEvent scae) -- 删除属性时执行

2.3 attributeReplaced(ServletContextAttributeEvent scae) -- 修改属性时执行

3.HttpSessionListener -- 监听session对象的创建以及销毁

3.2 sessionCreated(HttpSessionEvent se)   -- 创建时执行

3.2 sessionDestroyed(HttpSessionEvent se) -- 销毁时执行

4.HttpSessionAttributeListener --监听session对象中属性的改变

4.1 attributeAdded(HttpSessionBindingEvent se) -- 添加属性时执行

4.2 attributeRemoved(HttpSessionBindingEvent se) -- 删除属性时执行

4.3 attributeReplaced(HttpSessionBindingEvent se) -- 修改属性时执行

5.ServletRequestListener -- 监听request对象的创建以及销毁

5.1 requestInitialized(ServletRequestEvent sre) -- 创建时执行

5.2 requestDestroyed(ServletRequestEvent sre) -- 销毁时执行

6.ServletRequestAttributeListener --监听request对象中属性的改变

6.1 attributeAdded(ServletRequestAttributeEvent srae) -- 添加属性时执行

6.2 attributeRemoved(ServletRequestAttributeEvent srae) -- 删除属性时执行

6.3 attributeReplaced(ServletRequestAttributeEvent srae) -- 修改属性时执行


3.Interceptor

3.1 SpringBoot项目中

//登陆拦截器
@Configuration
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {

        // 判断当前用户是否已经登陆
        HttpSession session = request.getSession();
        User loginUser = (User)session.getAttribute("loginUser");

        if ( loginUser == null ) {
            String path = session.getServletContext().getContextPath();
            response.sendRedirect(path + "/login");
            return false;
        } else {
            return true;
        }
    }

    /**
     * 在Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
    }

    /**
     * 在完成视图渲染之后,执行此方法。
     */
    @Override
    public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
                                Object handler, Exception ex)throws Exception {
    }
}

2.2 web.xml项目中

<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/login" />
<mvc:exclude-mapping path="/shop/**" />
//该拦截器不对静态资源进行拦截
<bean class="com.wzy.web.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
import org.apache.catalina.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

//登陆拦截器
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {

        // 判断当前用户是否已经登陆
        HttpSession session = request.getSession();
        User loginUser = (User)session.getAttribute("loginUser");

        if ( loginUser == null ) {
            String path = session.getServletContext().getContextPath();
            response.sendRedirect(path + "/login");
            return false;
        } else {
            return true;
        }
    }

    /**
     * 在Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
    }

    /**
     * 在完成视图渲染之后,执行此方法。
     */
    @Override
    public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
                                Object handler, Exception ex)throws Exception {
    }
}

3 三者区别

标题FilterListenerInterceptor
作用点Web的请求、上下文系统级别的对象、参数等Action、Web的一些请求
实现函数回调事件监听动态代理
应用场景控制应用编码、防止未登录就进入界面等用来统计当前在线人数、消除过期session等拦截未登录用户
技术支持Servlet提供支持Servlet提供支持Spring提供支持
对应接口Filter接口ServletContextListener接口、HttpSessionListener接口同时继承于EventListenerHandlerInterceptor接口、HandlerInterceptorAdapter抽象类
级别分类系统系统非系统

4.总结

根据上面的内容,我们可以看得出在一个web项目启动后这些“神器”都有着莫大的重要用途,一个好的web项目会去监控,计数,统计等