(1) 前言
前几天, manager 问道一个问题: 能不能实现类似于 cron 的后台管理方式. 问题解决后, 想对这几个问题进行一下简单的总结. 以便抛砖引玉! 首先简单的提及一下 cron.
Cron, 计划任务, 是任务在约定的时间执行已经计划好的工作, 这是表面的意思. 在 Linux 中, 我们经常用到 cron 服务器来完成这项工作. cron 服务器可以根据配置文件约定的时间来执行特定的作务. 比如我们可以在配置文件中约定每天早上 4 点, 对 http 服务器重新启动, 这就是一个计划任务.
在 java 应用中一种类似的模式就是应用启动时后台线程的运行, 定时的触发某些任务的运行. 目前, 这种自启动的后台线程, 有两种常见的模式: 一种是 listener, 一种是 servlet
(2)listener
listener 方式是比较常用的. 实际上, servelet API 提供了大量监听器来监听 web 应用的内部事件, 从而允许当 Web 应用内部事件发生时而回调监听器的方法, 常见的事件有: Web 应用被启动, Web 应用被停止, 用 session 开始, 用户 session 结束, 用户请求到达等.
其中 ServletContextListener 用于 Web 应用的启动和关闭. 对于我们刚刚提及的需求, 我们需要在 Web 应用启动的时候就开始启动后台的服务线程.
ServletContextListener 有两个常用的方法:
void contextInitialized(ServletContextEvent sce)
这个方法在 Container 初始化整个 Web 应用时调用, 运行在该 Web 应用中 servlet 和 filter 初始化之前
void contextDestroyed(ServletContextEvent sce)
这个方法在 Container 卸载整个 Web 应用时调用, 运行在该 Web 应用中 servlet 和 filter 的 destroy() 方法之后
例子:
首先定义一个后台的服务线程
- public class run implements Runnable{
- @Override
- public void run() {
- while(true){
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("you mother call you to go home to eat......")
- }
- }
- }
定义一个 listener 类
- package com.cims;
- import javax.servlet.ServletContextEvent;
- import javax.servlet.ServletContextListener;
- public class MyListener implements ServletContextListener {
- public void contextDestroyed(ServletContextEvent e) {
- }
- public void contextInitialized(ServletContextEvent e) {
- System.out.println("------------web start-------");
- new Thread(new run()).start();
- }
- }
最后需要在 Web.xml 进行一下配置:
启动项目, 你就会发现你妈妈喊你回家吃饭....
(3)servlet
无意中, 尽然惊讶地发现 servlet 也有这样的功能, 这得益于 load-on-startup 属性, 后面将对该属性进行一些简单解析.
服务线程仍然保持不变, 写一个 servlet(集成 HttpServlet)
- package com.cims;
- import java.io.IOException;
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class MyServlet extends HttpServlet{
- private static final long serialVersionUID = 1L;
- public MyServlet(){
- }
- public void init(){
- new Thread(new run()).start();
- }
- public void doGet(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)
- throws ServletException, IOException{
- }
- public void destory(){
- }
- }
- }
最后需要在 Web.xml 进行一下配置:
启动项目, 你同样会发现你妈妈喊你回家吃饭....
1.load-on-startup 解析
1)load-on-startup 元素标记容器是否在启动的时候就加载这个 servlet(实例化并调用其 init() 方法).
2) 它的值必须是一个整数, 表示 servlet 应该被载入的顺序
3) 当值为 0 或者大于 0 时, 表示容器在应用启动时就加载并初始化这个 servlet;
4) 当值小于 0 或者没有指定时, 可以由 server 容器自行决定何时 load 该 servlet.
5) 正数的值越小, 该 servlet 的优先级越高, 应用启动时就越先加载.
6) 当值相同时, 容器就会自己选择顺序来加载.
2. 两种回家吃饭方式不同
Web 应用的启动好比你正在 start 的一个游戏, listener 好比在你 start 之前你妈妈就喊你回家吃饭了; servlet 方式好比你已经 start 了, 准备打 boss 时, 你妈妈喊你回家吃饭. 原因在于 ServletContextListener 的 contextInitialized 方法运行在 servlet 之前.
下面来看一后台启动的打印截图, 你就会发现!
第一种方式:
也就是说 listener 在 Web 应用起来之前已经开始 start 了
第二种方式:
servlet 必须在 Web 应用完全启动完毕之后才开始运行了!
来源: http://www.bubuko.com/infodetail-2876632.html