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 三者区别
| 标题 | Filter | Listener | Interceptor |
|---|---|---|---|
| 作用点 | Web的请求、上下文 | 系统级别的对象、参数等 | Action、Web的一些请求 |
| 实现 | 函数回调 | 事件监听 | 动态代理 |
| 应用场景 | 控制应用编码、防止未登录就进入界面等 | 用来统计当前在线人数、消除过期session等 | 拦截未登录用户 |
| 技术支持 | Servlet提供支持 | Servlet提供支持 | Spring提供支持 |
| 对应接口 | Filter接口 | ServletContextListener接口、HttpSessionListener接口同时继承于EventListener | HandlerInterceptor接口、HandlerInterceptorAdapter抽象类 |
| 级别分类 | 系统 | 系统 | 非系统 |
4.总结
根据上面的内容,我们可以看得出在一个web项目启动后这些“神器”都有着莫大的重要用途,一个好的web项目会去监控,计数,统计等