首页 > 基础资料 博客日记
JavaWeb中的Listener组件
2023-07-24 20:19:35基础资料围观304次
在我人生中第一次面试中,我挂在了和Listener
相关的题目上。
面试官问,如果你在使用纯Java Web开发的情况下,有什么办法能够在服务器关闭时将内存中的部分数据存入到持久层中。我当时知道肯定有这种组件或者hook方法,但我并不知道是什么。后来面试官告诉我是Listener
。
Servlet API中的Listener主要针对三种对象进行监听:
- ServletContext
- HttpRequest
- HttpSession
监听三种对象的创建和销毁
ServletAPI中提供了监听三种对象创建和销毁的Listener接口,你只需要编写一个类实现这个接口,并让这个类可以被容器发现即可(web.xml
中注册或者使用@WebListener
注解)
ServletContextListener
ServletContextListener
监听ServletContext
的创建和销毁,所以对于一个Web应用程序,我们只需要编写一个这个组件即可实现在容器关闭时做一些事。下面是一个在容器创建时构建一个JDBC数据源,并放到ServletContext
的属性中,然后当容器关闭时再销毁这个数据源的示例:
@WebListener
public class DataSourceListener implements ServletContextListener {
private Logger logger = Logger.getLogger(DataSourceListener.class.getName());
public static final String DATASOURCE_ATTR_NAME = "datasource";
/*
* web应用初始化进程开始时接收到通知
*
* 所有的ServletContextListener都会在任何web应用中的filter和servlet被初始化前接收到context初始化的通知
*
* @params sce - ServletContextEvent,包含正被初始化的ServletContext
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dbconcept");
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setInitialPoolSize(20);
dataSource.setMaxPoolSize(100);
sce.getServletContext().setAttribute(DATASOURCE_ATTR_NAME, dataSource);
logger.info("Datasource is injected correctly!");
} catch (Throwable e) {
throw new IllegalStateException("Init datasource faild!", e);
}
}
/**
* 收到ServletContext即将被关闭的通知
*
* 所有servlet和filter都将在任意一个ServletContextListener接到通知前被销毁
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
C3P0PooledDataSource dataSource = (C3P0PooledDataSource) sce.getServletContext().getAttribute(DATASOURCE_ATTR_NAME);
try {
dataSource.close();
sce.getServletContext().removeAttribute(DATASOURCE_ATTR_NAME);
} catch (SQLException e) {
logger.warning("Exception raised when close dataSource: ");
e.printStackTrace();
}
}
}
注意这两个方法被调用的时机:
- 所有的ServletContextListener都会在任何web应用中的filter和servlet被初始化前接收到context初始化的通知
- 所有servlet和filter都将在任意一个ServletContextListener接到销毁通知前被销毁
HttpSessionListener
可以监测Session的创建与销毁,JavaEE服务器会自动为每一个浏览器分配一个Session,这和你是否使用request.getSession(false)
是无关的。即使你使用request.getSession(false)
,Session还是会被创建,只不过那次调用的返回值是null。
所以,在HttpSessionListener
中,一旦一个新的浏览器访问,sessionCreated
方法就被回调,而当Session超时或invalidate
时,sessionDestroyed
方法就会被回调。也正是因为这个原因,我们在sessionCreated
中大概只能利用session的ID,因为往往此时Session中还没有设置什么属性。
下面是一个实现了HttpSessionListener
的类,它会将一个List注入到ServletContext
中,并且在其中维护当前的所有SessionID。同时,它也实现了ServletContextListener
用于向ServletContext
中初始化List:
@WebListener
public class UserLoginLogoutListener implements javax.servlet.http.HttpSessionListener, ServletContextListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
getSessionIdList(session.getServletContext()).add(session.getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
getSessionIdList(session.getServletContext()).remove(session.getId());
}
private List<String> getSessionIdList(ServletContext context) {
return (List<String>) context.getAttribute("sessionids");
}
@Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("sessionids", new ArrayList<>());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
上一篇:吐血整理Java编程基础入门技术教程,免费送
下一篇:Java基础_运算