开发者社区> javaboy2012> 正文

简单封装quartz实现任务调度的配置和管理

简介:
+关注继续查看

在实际的工作和开发过程中,经常遇到有需要定时任务的场景,比如定时发送邮件,定时上传文件,定时下载文件等。当然定时任务的处理也有很多种方式.本文主要写的是对quartz的简单封装,实现方便的调用。

主要思路:

定时任务的类和定时表达式配置在自定义的配置文件中,系统启动时,读取配置文件,加载需要执行的类,并启动quartz服务。

项目结构如下:
b787c8cf45258e2e943b1a425ab477b54c9b3747

主要包括如下类和配置文件:

1. 任务调度接口


package com.yanek.easytask.core;

/**
 * 任务调度接口
 * @author yanek
 *
 */
public interface Task {
	
	/**
	 * 所有都要实现该执行方法,任务被调度时会调用
	 */
	void execute();
	
	/**
	 * 打断执行方法
	 */
	void interrupt();

}



2. 任务配置实体类


package com.yanek.easytask.core;

/**
 * 任务配置实体类
 * @author yanek
 *
 */
public class TaskConfig {
	
	private String name; //任务名称
	private boolean activity = true; //是否被激活
	private String className; //任务执行的类全名
	private String scanPeriod; //任务执行的定时表达式配置
	
	public String getScanPeriod() {
		return scanPeriod;
	}
	public void setScanPeriod(String scanPeriod) {
		this.scanPeriod = scanPeriod;
	}

	
	public String getTaskClass() {
		return TaskClass;
	}
	public void setTaskClass(String taskClass) {
		TaskClass = taskClass;
	}
	private String TaskClass;
	

	public boolean isActivity()
	{
		return activity;
	}


	public void setActivity(boolean activity)
	{
		this.activity = activity;
	}
	

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}
	
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}

}


3. 任务配置xml解析类


package com.yanek.easytask.core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;



/**
 * 任务配置xml解析类
 * @author yanek
 *
 */
public class XmlReader {
	
	//配置文件路径	
	public final static String configFileName = "/conf/taskconfig.xml";


	public static void main(String[] args) {

		XmlReader.getTasks();
	}

	public static List getTasks() {

		List<TaskConfig> tasks = new ArrayList<TaskConfig>();
		
		System.out.println("load task config start...");
		
		File file = new File(Constants.APPLICATION_ROOT_DIR + configFileName);

		if (file.exists() && !file.isDirectory()) {

			try {
				SAXBuilder sx = new SAXBuilder();
				Document doc = sx.build(file);
				Element rootelement = doc.getRootElement();
				
				
					List<Element> childs = rootelement.getChildren();
					for (int i = 0; i < childs.size(); i++) {
						TaskConfig taskConfig = new TaskConfig();
						
						System.out.println("name:"+childs.get(i).getChildText("name"));
						System.out.println("activity:"+childs.get(i).getChildText("activity"));
						System.out.println("scanPeriod:"+childs.get(i).getChildText("scanPeriod"));
						System.out.println("className:"+childs.get(i).getChildText("className"));
						
						taskConfig.setName(childs.get(i).getChildText("name"));
						
						if (childs.get(i).getChildText("activity").equals("true"))
						{
							taskConfig.setActivity(true);
						}
						else
						{
							taskConfig.setActivity(false);
						}
						taskConfig.setScanPeriod(childs.get(i).getChildText("scanPeriod"));
						taskConfig.setTaskClass(childs.get(i).getChildText("className"));
						tasks.add(taskConfig);
				}
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} catch (JDOMException e) {

				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		} else {
			System.out.println("task config file no exist!");

		}
		System.out.println("load task config end !");
		return tasks;

	}
	


}


4.任务工厂类


package com.yanek.easytask.core;

/**
 * 任务工厂类
 * @author yanek
 *
 */
public class TaskFactory {

	 /**
	  * 根据任务配置对象,创建任务类的对象实例,采用反射。
	  * @param config
	  * @return
	  */
	 public static Task createTask(TaskConfig config) {
		String classname = config.getTaskClass();
		Task task = null;
		try {
			task = (Task) Class.forName(classname).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return task;
	}

}



5. 任务适配器:


package com.yanek.easytask.core;

import org.quartz.InterruptableJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.quartz.UnableToInterruptJobException;

public class TaskAdapter implements StatefulJob, InterruptableJob {
	public TaskAdapter() {
	}

	private Task task = null;

	public void execute(JobExecutionContext context)
			throws JobExecutionException {
		Object taskObj = context.getJobDetail().getJobDataMap().get(
				Constants.JOB_NAME);
		System.out.println("job类型:" + taskObj);
		if (taskObj instanceof Task) {
			task = (Task) taskObj;
			task.execute();
		} else {
			System.out.println("未知的job类型:" + taskObj.getClass());
		}
	}


	public void interrupt() throws UnableToInterruptJobException {
		task.interrupt();
	}
}


6. 系统常量类


package com.yanek.easytask.core;

/**
 * 系统常量类
 */
public class Constants
{
	/**
	 * 应用程序根目录
	 */
	public static String APPLICATION_ROOT_DIR = null;
	
	//任务实例名称 
	public static final String JOB_NAME = "TASK_JOB_INSTANTS";
}




7. 系统启动类


package com.yanek.easytask.core;


import java.text.ParseException;
import java.util.List;

import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 调度任务服务程序启动入口
 * 
 * 启动时需要设置-Dappdir参数,应当设置为-Dappdir=..
 * -Dconfig=配置文件文件绝对路径 可选的属性
 * 
 * 任务调度使用Quartz实现
 * 
 */
public class Startup
{

	
	/**
	 * @param args
	 */
	public static void startup() {

		

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

			String appdir = System.getProperty("user.dir");
			
			System.out.println(appdir);

			
			//设置系统变量
			Constants.APPLICATION_ROOT_DIR = appdir;
			
			//System.setProperty("appdir","E:\\work\\task");

			//初始化调度服务器
			initSchedulerServer();
			
			List<TaskConfig> tasks=XmlReader.getTasks();
			
			if(tasks == null || tasks.size() <=0)
				throw new Exception("没有配置任务实例!");
			
			for(int i=0;i<tasks.size();i++)
			{
				TaskConfig tc=tasks.get(i);
				try
				{
					if(tc.isActivity())
					{
						scheduleJob(tc);
						System.out.println("任务实例["+tc.getName()+"]已加入调度.");
					}
					else
					{
						System.out.println(tc.getName()+" 任务实例Activity=false 不进行处理");
					}
				}
				catch(Exception cve)
				{
					//配置错误忽略这个任务
					System.out.println(cve);
				}
			}
			/*启动调度服务器*/
			startScheduleServer();
		}
		catch(Exception ex)
		{
	
			System.out.println("启动出现异常,3秒钟后自动关闭");
			Thread.sleep(1000*3);
			if(server!=null)
				server.shutdown();
			
		}
		
	}
	
	//----------------------任务调度处理----------------------------
	//任务调度服务
	private static Scheduler server = null;
	
	//任务id
	private static int jobID = 0;
	
	private static void initSchedulerServer()
		throws SchedulerException
	{
		if(server == null)
		{
			SchedulerFactory sf = new StdSchedulerFactory();
			server = sf.getScheduler();
		}
	}
	
	/**
	 * 调度一个任务
	 */
	private static void scheduleJob(TaskConfig conf) 
		throws SchedulerException, ParseException
	{
		jobID++;
		
		Task deliveryJob = TaskFactory.createTask(conf);
		
		//将具体的任务实例存储到jobdetail中,这样每次触发jobadapter时,都会调用我们声明的deliveryJob这个实例了。
		String jobName = conf.getName()+"_job"+jobID;
		JobDetail jobAdapter = new JobDetail(jobName,
				"Group", TaskAdapter.class);
		JobDataMap data = new JobDataMap();
		data.put(Constants.JOB_NAME, deliveryJob);
		jobAdapter.setJobDataMap(data);

		//注意下面需要5个参数
		CronTrigger trigger = new CronTrigger("trigger_"+jobID,"Group", 
				jobName, "Group",conf.getScanPeriod());
		server.addJob(jobAdapter, true);
		server.scheduleJob(trigger);	

	}
	
	/**
	 * 启动调度服务
	 * @throws SchedulerException
	 */
	private static void startScheduleServer() throws SchedulerException
	{
		if(server != null)
			server.start();
	}
}


配置文件:

taskconfig.xml



<?xml version="1.0" encoding="UTF-8"?>
<taskconfig>
    	<task>
	    	<name>test1</name>
			<activity>true</activity>
			<scanPeriod>0/5 * * * * ?</scanPeriod>
	    	<className>com.yanek.easytask.demo.TaskA</className>
    	</task>
    	
    	 <task>
	    	<name>test任务2</name>
			<activity>true</activity>
			<scanPeriod>0/5 * * * * ?</scanPeriod>
	    	<className>com.yanek.easytask.demo.TaskDemo</className>
    	</task>
    	

</taskconfig>


几点说明:

1. 上述代码可以封装打包为jar包。然后在其他项目中使用即可。

2. 使用该jar包事先任务开发时,只需要编写一个Task接口的实现类,配置在配置文件中即可。

实例调用如下:


package com.yanek.easytask.demo;

import com.yanek.easytask.core.Task;
import com.yanek.easytask.core.TaskConfig;


public class TaskDemo implements Task {

	
	//唯一构造函数
	public TaskDemo()
	{
		
		
	}

	@Override
	public void execute() {
		System.out.println(" TaskDemo execute");
	}

	@Override
	public void interrupt() {
		System.out.println("TaskDemo interrupt");
	}

}



在配置文件中增加如下配置:


    	 <task>
	    	<name>test任务2</name>
			<activity>true</activity>
			<scanPeriod>0/5 * * * * ?</scanPeriod>
	    	<className>com.yanek.easytask.demo.TaskDemo</className>
    	</task>


启动Startup类即可。运行结果如下:

45dfaaee389c162f6ea0153a6cc5b766a8121332


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
[Quartz笔记]玩转定时调度
简介 Quartz是什么? Quartz是一个特性丰富的、开源的作业调度框架。它可以集成到任何Java应用。 使用它,你可以非常轻松的实现定时任务的调度执行。   Quartz的应用场景 场景1:提醒和告警 场景2:监听事务 场景3:定时作业   Quartz的安装 安装 1.可以直接在官网:http://www.quartz-scheduler.org/ 下载jar包。
783 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
23938 0
Spring Boot集成持久化Quartz定时任务管理和界面展示
前言 本文是对之前的一篇文章Spring+SpringMVC+mybatis+Quartz整合代码部分做的一个修改和补充, 其中最大的变化就是后台框架变成了Spring Boot。
2366 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
17809 0
Spring整合的quartz任务调度的实现方式
一、在web.xml中将配置文件的位置指定好。 Web.xml的配置如下: &lt;?xmlversion="1.0"encoding="UTF-8"?&gt; &lt;web-appversion="2.5"       xmlns="http://java.sun.com/xml/ns/javaee"       xmlns:xsi="http://www.w3.org/20
1110 0
+关注
javaboy2012
学习是一种精神,分享是一种美德
323
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载