文档章节

自动运行任务

罪恶的花生
 罪恶的花生
发布于 2016/04/12 23:07
字数 1917
阅读 175
收藏 22

如何写一个自动运行定时任务程序,我知道有很多人喜欢quartz,我也喜欢,但是我喜欢简单。


当有一个需求时,第一件事就是找方法,比如,我现在需要做一个定时程序,定时触发,定时执行。

因为我的需求很简单,所以我决定使用Timer和TimerTask就可以解决我的需求,于是,我先创建了一个Web项目,

然后,当程序启动时,运行程序自动启动,第一想到的是servlet,

开始撸代码了,

第一个创建HttpServletSysLoad

加入两个仓库,用来存放Timer和TimerTask

public static List<TaskJob> tasks = new ArrayList<TaskJob>();

private static List<Timer> timers = new ArrayList<Timer>();

当然你也可以吧初始化放到:

public SysLoad() {

            tasks = new ArrayList<TaskJob>();

            timers = new ArrayList<Timer>();

    logger.info("建立系统启动自动服务");

}

第二部,在初始化HttpServlet时,自动初始化所有定时任务,

这时候,你需要考虑,是在这里写死方法,还是程序动态生成。

像我这样懒得人,一般都会使用程序动态生成,

找了一个ClassUtil类,通过查找指定包下面所有类的方法来初始化。然后就有了下面的代码。

public void init() throws ServletException {

logger.info("系统启动自动服务");

String startTask = getInitParameter("startTask");

// 启动定时器

if (startTask.equals("true")) {

logger.info("系统开启自动运行服务");

List<Class<?>> jobclasses = ClassUtil.getClasses("cn.wangkai.task.job");

logger.info("获取"+jobclasses.size()+"任务!");

for (Class<?> jobclass : jobclasses) {

try {

TaskJob task = (TaskJob) jobclass.newInstance();

task.getRunTime();

Timer timer = new Timer();

timer.schedule( (TimerTask) task,1000*task.getRunTime(), 1000*task.getRunTime());

tasks.add(task);

timers.add(timer);

logger.info(task.getTaskname()+"开始工作,间隔"+task.getRunTime()+"秒!");

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

}


初始化完毕后,还需要讲初始化的数据在关闭时后reload时销毁,增加如下代码

public void destroy() {

logger.info("正在关闭自动服务");

try{

for (TaskJob task : tasks) {

if(task!=null)tasks.remove(task);

}

}catch(Exception e){

}

try{

for (Timer timer : timers) {

if (timer != null) {

timer.cancel();

}

timers.remove(timer);

}

}catch(Exception e){

}

logger.info("================tasks="+tasks.size()+"=====================");

logger.info("================timers="+timers.size()+"=====================");

super.destroy();

}

第三步加入web.xml

  <servlet>

<servlet-name>SysLoad</servlet-name>

<servlet-class>cn.wangkai.task.taskjob.SysLoad</servlet-class>

<init-param>

<param-name>startTask</param-name>

<param-value>true</param-value>

</init-param>

<init-param>

<param-name>intervalTime</param-name>

<param-value>1</param-value>

</init-param>

<load-on-startup>20</load-on-startup>

</servlet>

剩下就是如何实现TaskJob

第一步创建一个接口,


public interface TaskJob  {

/**

* 获取服务运行描述信息

* @return

*/

public String getMessage();

/**

* 设置服务运行描述信息

* @param message

*/

public void setMessage(String message);

/**

* 得到任务名称

* @return

*/

public String getTaskname() ;

/**

* 设置当前任务名称

* @param taskname

*/

public void setTaskname(String taskname);

/**

* 获取当前任务运行时间

* @return

*/

public int getRunTime() ;

/**

* 设置当前任务运行时间

* @param runTime

*/

public void setRunTime(int runTime);

/**

* 任务是否暂停

* @return

*/

public boolean isRunning() ;

/**

* 设置任务暂停状态

* @param isRunning

*/

public void setRunning(boolean isRunning) ;

}

第二部创建一个实现方法


import java.util.TimerTask;

import java.util.logging.Logger;


import javax.servlet.ServletContext;


import org.apache.commons.lang.math.NumberUtils;


import cn.wangkai.util.ProUtil;

import cn.wangkai.util.StackTraceUtils;



public class TaskJobImp extends TimerTask implements TaskJob {

private static Logger logger = Logger.getAnonymousLogger();

public TaskJobImp(ServletContext context) {

}

//运行描述

private String Message=null;

//程序名称

private String taskname=getClass().getName();

//多长时间,时间秒

private int RunTime=10;

//正常运行

private boolean isRunning = true;

public TaskJobImp() {

}


private ServletContext context;


public void setContext(ServletContext context) {

logger.info(getTaskname()+"任务开始启动!");

this.context = context;

}


public void run() {

if (isRunning()) {

Message = getTaskname()+"上次启动时间\n\t";

try {

Message = Message+"程序运行中....\n\t";

//TODO

Message = Message+"任务启动完成 。\n\t";

} catch (Exception e) {

Message = Message+"出现错误:"+StackTraceUtils.getStackTrace(e);

}finally{

}

logger.info(Message);

}

}


public ServletContext getContext() {

return context;

}


public String getMessage() {

return Message;

}


public void setMessage(String message) {

Message = message;

}


public String getTaskname() {

return taskname;

}


public void setTaskname(String taskname) {

this.taskname = taskname;

}


public int getRunTime() {

RunTime = NumberUtils.toInt(ProUtil.read(getClass().getName()+"_runtime",RunTime+"",true),RunTime);

return RunTime;

}


public void setRunTime(int runTime) {

RunTime = runTime;

}


public boolean isRunning() {

return isRunning;

}


public void setRunning(boolean isRunning) {

this.isRunning = isRunning;

}


    public boolean cancel() {

    logger.info(getTaskname()+"正在退出!");

    return super.cancel();

    }


第四步,我们在cn.wangkai.task.job包中创建一个测试类吧

package cn.wangkai.task.job;



import java.util.logging.Logger;


import cn.wangkai.task.taskjob.TaskJobImp;

import cn.wangkai.util.StackTraceUtils;



public class SampleTask extends TaskJobImp{

private String Message=null;

private static Logger logger = Logger.getAnonymousLogger();

public void run() {

if (isRunning()) {

Message = "\r\n"+getTaskname()+"上次启动时间\r\n";

try {

Message = Message+"程序运行中....\r\n";

//TODO 这里就是你需要实现的代码。

Message = Message+"任务启动完成 。";

} catch (Exception e) {

Message = Message+"出现错误:"+StackTraceUtils.getStackTrace(e);

}finally{

}

logger.info(Message);

}

}

}


好了,代码撸完了,可以睡觉了,

其他工具方法

ClassUtil.java(网上找的,我也懒得写)


public static void main(String[] args) throws Exception {

List<Class<?>> classes = ClassUtil.getClasses("cn.wangkai.task.job");

for (Class<?> clas : classes) {

System.out.println(clas.getName());

}

}


/**

* 取得某个接口下所有实现这个接口的类

*/

public static List<Class<?>> getAllClassByInterface(Class<?> c) {

List<Class<?>> returnClassList = null;


if (c.isInterface()) {

// 获取当前的包名

String packageName = c.getPackage().getName();

// 获取当前包下以及子包下所以的类

List<Class<?>> allClass = getClasses(packageName);

if (allClass != null) {

returnClassList = new ArrayList<Class<?>>();

for (Class<?> classes : allClass) {

// 判断是否是同一个接口

if (c.isAssignableFrom(classes)) {

// 本身不加入进去

if (!c.equals(classes)) {

returnClassList.add(classes);

}

}

}

}

}


return returnClassList;

}


/*

* 取得某一类所在包的所有类名 不含迭代

*/

public static String[] getPackageAllClassName(String classLocation, String packageName) {

// 将packageName分解

String[] packagePathSplit = packageName.split("[.]");

String realClassLocation = classLocation;

int packageLength = packagePathSplit.length;

for (int i = 0; i < packageLength; i++) {

realClassLocation = realClassLocation + File.separator + packagePathSplit[i];

}

File packeageDir = new File(realClassLocation);

if (packeageDir.isDirectory()) {

String[] allClassName = packeageDir.list();

return allClassName;

}

return null;

}


/**

* 从包package中获取所有的Class

* @param pack

* @return

*/

public static List<Class<?>> getClasses(String packageName) {


// 第一个class类的集合

List<Class<?>> classes = new ArrayList<Class<?>>();

// 是否循环迭代

boolean recursive = true;

// 获取包的名字 并进行替换

String packageDirName = packageName.replace('.', '/');

// 定义一个枚举的集合 并进行循环来处理这个目录下的things

Enumeration<URL> dirs;

try {

dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

// 循环迭代下去

while (dirs.hasMoreElements()) {

// 获取下一个元素

URL url = dirs.nextElement();

// 得到协议的名称

String protocol = url.getProtocol();

// 如果是以文件的形式保存在服务器上

if ("file".equals(protocol)) {

// 获取包的物理路径

String filePath = URLDecoder.decode(url.getFile(), "UTF-8");

// 以文件的方式扫描整个包下的文件 并添加到集合中

findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);

} else if ("jar".equals(protocol)) {

// 如果是jar包文件

// 定义一个JarFile

JarFile jar;

try {

// 获取jar

jar = ((JarURLConnection) url.openConnection()).getJarFile();

// 从此jar包 得到一个枚举类

Enumeration<JarEntry> entries = jar.entries();

// 同样的进行循环迭代

while (entries.hasMoreElements()) {

// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件

JarEntry entry = entries.nextElement();

String name = entry.getName();

// 如果是以/开头的

if (name.charAt(0) == '/') {

// 获取后面的字符串

name = name.substring(1);

}

// 如果前半部分和定义的包名相同

if (name.startsWith(packageDirName)) {

int idx = name.lastIndexOf('/');

// 如果以"/"结尾 是一个包

if (idx != -1) {

// 获取包名 把"/"替换成"."

packageName = name.substring(0, idx).replace('/', '.');

}

// 如果可以迭代下去 并且是一个包

if ((idx != -1) || recursive) {

// 如果是一个.class文件 而且不是目录

if (name.endsWith(".class") && !entry.isDirectory()) {

// 去掉后面的".class" 获取真正的类名

String className = name.substring(packageName.length() + 1, name.length() - 6);

try {

// 添加到classes

classes.add(Class.forName(packageName + '.' + className));

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

} catch (IOException e) {

e.printStackTrace();

}


return classes;

}


/**

* 以文件的形式来获取包下的所有Class

* @param packageName

* @param packagePath

* @param recursive

* @param classes

*/

public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,

List<Class<?>> classes) {

// 获取此包的目录 建立一个File

File dir = new File(packagePath);

// 如果不存在或者 也不是目录就直接返回

if (!dir.exists() || !dir.isDirectory()) {

return;

}

// 如果存在 就获取包下的所有文件 包括目录

File[] dirfiles = dir.listFiles(new FileFilter() {

// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)

public boolean accept(File file) {

return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));

}

});

// 循环所有文件

for (File file : dirfiles) {

// 如果是目录 则继续扫描

if (file.isDirectory()) {

findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,

classes);

} else {

// 如果是java类文件 去掉后面的.class 只留下类名

String className = file.getName().substring(0, file.getName().length() - 6);

try {

// 添加到集合中去

classes.add(Class.forName(packageName + '.' + className));

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

}


ProUtil.java 本人原创

详见:http://www.oschina.net/code/snippet_54124_55380


StackTraceUtils.java 很久以前写的,一直在用


import java.io.PrintWriter;

import java.io.StringWriter;

import java.io.Writer;

public class StackTraceUtils {

    /**

     * 将异常堆栈转换为字符串

     * @param aThrowable 异常

     * @return String

     */

    public static String getStackTrace(Throwable aThrowable) {

        final Writer result = new StringWriter();

        final PrintWriter printWriter = new PrintWriter(result);

        aThrowable.printStackTrace(printWriter);

        return result.toString();

      }

}







© 著作权归作者所有

罪恶的花生

罪恶的花生

粉丝 71
博文 47
码字总数 37019
作品 0
杭州
部门经理
私信 提问
定时任务-quartz的使用,实现可页面化管理

定时任务-quartz的使用,实现可页面化管理 使用spring+quartz实现定时任务的页面化管理。主要特点: 1.时间表达式等信息配置在数据库中,从而实现页面化管理。 2.可以手动执行或者停止单个任...

chaun
2015/07/30
1K
0
定时任务调度系统--opencron

opencron:一个功能完善且通用的开源定时任务调度系统,拥有先进可靠的自动化任务管理调度功能,提供可操作的web图形化管理满足多种场景下各种复杂的定时任务调度,同时集成了linux实时监控,we...

benjobs
2017/04/18
27.4K
11
Linux定时任务的使用

Linux下的定时任务,crontab是一个非常有用的命令(大部分的自动完成的工作都需要用到自动执行命令) 这里演示一个非常简单的定时任务设置。(用来做以后所有复杂的自动化工作的前提)。 先写...

熊猫88
2016/01/25
88
0
GCD死锁,及同步、异步、串行和并行队列组合情形

一、概述 1)队列用来存储代码任务,线程用来运行代码任务; 2)main()函数作为程序入口,整个程序默认运行在主线程中,程序代码任务默认存放在主队列中; 3)以下所谓阻塞线程是针对主线程而...

春天里的花骨朵
02/14
0
0
百度Apollo 3.5是如何设计Cyber RT计算框架的?

自百度Apollo自动驾驶平台开源以来,已快速迭代至 3.5 版本,代码行数超过 39 万行,合作伙伴超过 130 家,吸引了来自 97 个国家的超 15000 名开发者。无疑,Apollo 是目前世界范围内最活跃的...

AI科技大本营
02/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

川普给埃尔多安和内堪尼亚胡的信

任性 https://twitter.com/netanyahu/status/1186647558401253377 https://edition.cnn.com/2019/10/16/politics/trump-erdogan-letter/index.htm...

Iridium
20分钟前
10
0
golang-mysql-原生

db.go package mainimport ("database/sql""time"_ "github.com/go-sql-driver/mysql")var (db *sql.DBdsn = "root:123456@tcp(127.0.0.1:3306)/test?charset=u......

李琼涛
49分钟前
5
0
编程作业20191021092341

1编写一个程序,把用分钟表示的时间转换成用小时和分钟表示的时 间。使用#define或const创建一个表示60的符号常量或const变量。通过while 循环让用户重复输入值,直到用户输入小于或等于0的值...

1李嘉焘1
49分钟前
7
0
Netty整合Protobuffer

现在我们都知道,rpc的三要素:IO模型,线程模型,然后就是数据交互模型,即我们说的序列化和反序列化,现在我们来看一下压缩比率最大的二进制序列化方式——Protobuffer,而且该方式是可以跨...

算法之名
54分钟前
18
0
如何用C++实现栈

栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压...

BWH_Steven
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部