前几天写了关于DispatcherServlet如何实例化的,今天我们来看一下java web的三大组件:Servlet、Filter、Listener。
不知道小伙伴们对这三个组件是否熟悉呢?感觉自从用了Spring框架后,很多组件都帮我们封装好了,感觉这三个里面,Filter是最常用的,至少我用过几次
Listener简介
Listener表示服务器的事件监听器,用于监听三个域对象的状态(对象、对象的属性)变化,三个域对象分别是ServletContext、HttpSession、HttpServletRequest
Spring中可以使用
ServletListenerRegistrationBean注册器进行注册监听
对于三大域对象,大家是否熟悉呢?改天写一篇关于三大域对象的文章
- ServletContext
ServletContextListener:ServletContextListener负责监听 ServletContext 的创建和销毁,就可以监听服务器的启动和关闭。这样我们就可以在服务器启动和关闭的时候执行一些任务,比如服务器启动之后读取Spring Framework 的配置文件(applicationContext.xml),创建Spring的核心容器,我们的ContextLoaderListener就是实现了ServletContextListener,由
AbstractContextLoaderInitializer进行注册,并初始化Spring的IOC容器的。
ServletContextAttributeListener:监听全局作用域对象共享数据变化时刻。当我向ServletContext域对象中添加修改删除值时,都可以通过监听获取到对应的动作。
- HttpSession
HttpSessionListener:当一个浏览器第一次访问网站的时候,J2EE应用服务器会新建一个HttpSession对象 ,并触发 HttpSession创建事件 ,如果注册了HttpSessionListener事件监听器,则会调用HttpSessionListener事件监听器的 sessionCreated方法。相反,当这个浏览器访问结束超时的时候,J2EE应用服务器会销毁相应的HttpSession对象,触发 HttpSession销毁事件,同时调用所注册HttpSessionListener事件监听器的sessionDestroyed方法
HttpSessionActivationListener:实现了
HttpSessionActivationListener接口的 JavaBean 对象可以感知自己被活化和钝化的事件。当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被钝化之前,web 服务器调用如下方法sessionWillPassivate(HttpSessionBindingEvent event) 方法;当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被活化之后,web 服务器调用该对象的 void sessionDidActive(HttpSessionBindingEvent event)方法。所谓的钝化状态,就是将Session内存中的对象持久化(序列化)到磁盘;活化状态,就是将磁盘上的对象再次恢复到session内存中。
HttpSessionBindingListener:实现BindingListener接口的对象被绑定到session时触发valueBound事件即setAttribute时,解除绑定即session销毁时触发valueUnbound事件。我们绑定到指定session中:session.setAttribute("名字",BindingListener接口实现对象);
HttpSessionAttributeListener:这个与
ServletContextAttributeListener一样功能,监听的是HttpSession域对象中的内容
- HttpServletRequest
ServletRequestListener:这个接口是在每次请求的时候就会执行监听,HttpServletRequest可以直接注入就是使用了ServletRequestListener接口监听了每次请求对象,相关文章:RequestObjectFactory()是怎么捕捉到每次请求的HTTP对象的
ServletRequestAttributeListener:这个与
ServletContextAttributeListener一样的功能,只是监听的是HttpServletRequest域对象中的内容
Filter简介
当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊功能,例如:登录验证、统一编码处理、敏感字符过滤……
鄙人曾经使用Filter进行了ServletRequest包装处理,从而可以使ServletRequest可以多次读取,因为ServletRequest的getInputStream方法只能使用一次,但是我还想在到达Controller之前用拦截器对请求内容进行一次处理,因此我使用过滤器将ServletRequest包装一下。
@WebFilter(urlPatterns = "/*")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestWrapperFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//将ServletRequest封装一下,因为request.getInputStream()方法只能读取一次,所以不能和@requestBody一起使用
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
log.info("WebRqsTypeChangeFilter----->"+new String(requestWrapper.getBody()));
chain.doFilter(requestWrapper, response);
}
}
//也可以使用下面这种方式进行注册过滤器,也可以直接使用@WebFilter注解
@Bean
public FilterRegistrationBean jwtFilter() throws NoSuchAlgorithmException {
FilterRegistrationBean registration = new FilterRegistrationBean<>();
registration.setFilter(new RequestWrapperFilter());
registration.addUrlPatterns("/api/*");
registration.setOrder(2);
return registration;
}
Servlet简介
Servlet(Server Applet)服务器的小程序。是用java编写的一个服务器程序,目的是和浏览器交互并且生成动态的web内容。Servlet狭义上来讲指的是servlet接口,广义上来讲指的是所有实现接口的实现类。
Servlet是指实现了Servlet接口类,Servlet运行于支持java的应用服务器(tomcat,Servlet是tomcat的一个组件)中。从原理上来讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务
Servlet生命周期:从创建到销毁的全过程,共分为三个阶段
- 初始化init方法: 只会执行一次(启动tomcat的时候默认是不执行的,在访问的时候才会执行)
- 服务方法service: 可以执行多次,每次请求会执行
- 销毁方法destory: 只执行一次(停止服务器)
//简单创建一个Servlet
@WebServlet(urlPatterns = "/demo",name = "demo")
public class Demo implements Servlet {
/**
* 最开始被调用,初始化servlet,初始化一次之后不再被调用;因此servlet是一个单例线程不安全的对象。
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 逻辑处理方法,接收响应,处理请求,具体的实现在此方法中
* @param req
* @param res
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
/**
* 调用此方法销毁servlet
*/
@Override
public void destroy() {
}
}
组件调用顺序
三大组件初始化顺序与销毁顺序
初始化:Listener->Filter->Servlet
销毁:Servlet->Filter->Listener