自动运行任务
自动运行任务
罪恶的花生 发表于2年前
自动运行任务
  • 发表于 2年前
  • 阅读 148
  • 收藏 22
  • 点赞 1
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

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

如何写一个自动运行定时任务程序,我知道有很多人喜欢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();

      }

}







标签: 自动运行任务
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
罪恶的花生
粉丝 70
博文 46
码字总数 36703
×
罪恶的花生
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: