在Web容器启动时,就需要为让程序为我们做点事儿,比如需要启动一个后台线程开始扫描某个用户的在线时长或者我们需要初始化数据库连接等等.通常有两种方式可以解决,这就是我们今天的主题.
- 使用自定义的Servlet类,通过设置LoadOnStartUp属性值
- 使用ServletContextListener监听器
Servlet的LoadOnStartUp属性设置
@WebServlet(name = "LoginServlet",urlPatterns = {"/login"},loadOnStartup = -1)
public class LoginServlet extends HttpServlet {
//具体的Servlet编写(init,destroy,post,get方法)
}
loadOnStartUp的属性值决定了每一个Servlet的实例化时机,在<类比servlet请求处理和java多线程处理>中已经说明每一个Servlet只会实例化一次,那么Servlet什么时候进行实例化呢?
每个Servlet的运行都遵行如下的生命周期.
- 创建Servlet类的实例(何时创建?)
- Web容器执行Servlet类的init方法,对Servlet进行初始化.
- Web容器对其进行初始化之后,Servlet实例一直存在内存中,等待用户的请求和相应.如果用户客户端时get请求,则调用Servlet类的doGet方法,否则执行doPost方法.
- Web容器停止运行时,则销毁Servlet类,执行Servlet类的destroy方法.
回答刚才的问题:Web容器什么时候初始化Servlet类?
@WebServlet(name = "LoginServlet",urlPatterns = {"/login"},loadOnStartup = -1)
public class LoginServlet extends HttpServlet {
public LoginServlet(){
super();
System.out.println("构造方法:" + this.getClass().getSimpleName());
}
@Override
public void init() throws ServletException {
super.init();
System.out.println("初始化:" + this.getClass().getSimpleName());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//post 请求业务处理
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Get请求业务处理
}
@Override
public void destroy() {
super.destroy();
System.out.println("销毁:" + this.getClass().getSimpleName());
}
}
1.如果loadOnStartup的值为负数,则当用户请求该Servlet时,Servlet进行初始化.当第一个用户请求时,执行的结果如下.
1.构造方法:LoginServlet
2.init:LoginServlet
3.Post/Get业务处理
当第二个用户请求时,执行的结果如下:
1.Post/Get业务处理
当Web容器停止时,执行的结果如下.
执行 destroy方法,销毁:LoginServlet
2.如果loadOnStartup的值为正数或者0,则Web容器启动时,Servlet就进行初始化.执行的结果如下.
1.构造方法:LoginServlet
2.init:LoginServlet
当用户请求时,执行结果如下.
1.Post/Get业务处理
当Web容器停止时,执行的记过如下.
执行destroy方法,销毁:LoginServlet
因此可以编写一个Servlet,设置他的loadOnStartup属性值为正数或者0,在Web容器启动的时候,就实例化该Servlet,并且执行该Servlet的init方法.
如下代码,在Web容器启动之后,启动后台线程,则每隔一秒钟,执行一次业务逻辑代码.
@Override
public void init() throws ServletException {
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
//业务逻辑
}
}).start();
}
ServletContextListener监听器编写
编写自定义的ServletContextListener监听器,则必须使得自定义的监听器实现ServletContextListener接口.而该接口的定义如下:
public interface ServletContextListener extends EventListener {
public void contextInitialized(ServletContextEvent sce);
public void contextDestroyed(ServletContextEvent sce);
}
当Web容器启动时,则开始执行ServletContextListener监听器的contextInitialized方法.而在Web容器停止运行时,执行监听器的contextDestroyed方法.我们如果想在Web容器启动后,做点事儿的话,可以将业务逻辑写在该方法中.
@WebListener
public class ConnectionInitListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
//业务逻辑
//例如初始化数据库连接等
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("web context 销毁");
}
}
扩展
- Spring配置
- Spring mvc配置
Spring 配置
我们在Web项目中使用Spring框架的时候,需要在web.xml文件中,进行配置.而让Tomcat或者其他Web容器在一开始运行的时候,就要感知到Spring框架,并且进行一系列类的初始化工作,我们自然而然就联想到今天的主题,在Web容器启动之后,做点事儿,在这里是Web容器配合Spring框架做事儿.
因此在我们实际的项目开发中,如果在web项目中需要使用Spring框架,首先要在web.xml文件中,配置ServletContextListener监听器.Spring框架使用的是ContextLoaderListener监听器,而该监听器正是一个自定义的监听器,它实现了ServletContextListener监听器,负责在web项目中,结合Spring框架的初始化工作.
Spring mvc配置
Spring mvc的使用一个Servlet作为整个框架的入口.并且设置该Servlet的loadOnStartup属性为1,使得Web容器启动的时候,该Servlet就要进行初始化,从而使得Spring mvc相关的类和配置得到相应的初始化和实例化.正如我们今天主题的第一部分,Web容器启动后,做点事儿,可以通过设置Servlet的loadOnStartup属性,从而达到我们的目的.