文档章节

自动运行任务

罪恶的花生
 罪恶的花生
发布于 2016/04/12 23:07
字数 1917
阅读 162
收藏 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
博文 46
码字总数 36703
作品 0
杭州
部门经理
私信 提问
定时任务-quartz的使用,实现可页面化管理

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

chaun
2015/07/30
0
0
Linux定时任务的使用

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

熊猫88
2016/01/25
77
0
定时任务调度系统--opencron

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

benjobs
2017/04/18
12.4K
9
第四十章:基于SpringBoot & Quartz完成定时任务分布式多节点负载持久化

在上一章【第三十九章:基于SpringBoot & Quartz完成定时任务分布式单节点持久化】中我们已经完成了任务的持久化,当我们创建一个任务时任务会被定时任务框架自动持久化到数据库,我们采用的...

恒宇少年
2017/11/12
0
0
benjobs/OpenCron

opencron 一个功能完善真正通用的linux定时任务调度定系统,满足多种场景下各种复杂的定时任务调度,同时集成了linux实时监控,webssh,提供一个方便管理定时任务的平台. 你是否有定时执行任务计...

benjobs
2016/11/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

排序--二分插入排序

二分插入排序是对直接插入排序的一个优化,在排序--直接插入排序中已经分析过直接插入排序的最坏时间复杂度是平方级别的,二分插入排序则是通过二分查找对寻找插入位置进行了优化,在找到插入...

FAT_mt
13分钟前
0
0
Quora点赞过万!麻省理工5.0GPA十条学习技巧

美国版知乎Quora上有个问题是:顶尖学生如何学习。排名第一的答案已经赢得13.5K次点赞,我们翻译出来分享给大家。 MIT normally does not rank its students. So if you hear that someone g...

乔老哥
26分钟前
0
0
IOC的学习(1)

1.IOC理论概要 java中,一个对象A怎么才能调用对象B? 当一个对象的构建,需要多个其他对象时,对象和对象有复杂的构建关系。spring帮助我们维系对象的依赖关系,降低系统的实现成本,前提是...

杨健-YJ
38分钟前
6
0
Spring 的 getBean 方法源码解析

文本将从以下几个方面介绍 相关文章 FactoryBean 接口 BeanFactory 接口 BeanFactory 接口 和 FactoryBean 接口的区别 getBean 方法的源码解析 Spring 循环依赖的解决方式 相关文章 Spring 中...

TSMYK
41分钟前
4
0
PTA-基础编程题目集-7-14 求整数段和

给定两个整数A和B,输出从A到B的所有整数以及这些数的和。 输入格式: 输入在一行中给出2个整数A和B,其中−100≤A≤B≤100,其间以空格分隔。 输出格式: 首先顺序输出从A到B的所有整数,每...

niithub
47分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部