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

简介:

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

主要思路:

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

项目结构如下:

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

1. 任务调度接口


package com.yanek.easytask.core;

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

}
AI 代码解读



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;
	}

}
AI 代码解读


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;

	}
	


}
AI 代码解读


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;
	}

}
AI 代码解读



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();
	}
}
AI 代码解读


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";
}
AI 代码解读




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();
	}
}
AI 代码解读


配置文件:

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>
AI 代码解读


几点说明:

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");
	}

}
AI 代码解读



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


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


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




目录
打赏
0
0
0
4
27
分享
相关文章
5 分钟复刻你的声音,一键实现 GPT-Sovits 模型部署
想象一下,只需简单几步操作,就能生成逼真的语音效果,无论是为客户服务还是为游戏角色配音,都能轻松实现。GPT-Sovits 模型,其高效的语音生成能力为实现自然、流畅的语音交互提供了强有力的技术支持。本文将详细介绍如何利用函数计算平台部署 GPT-Sovits 模型,以构建一个高效、可扩展的 AI 语音交互系统。通过这一部署方案,开发者和企业能够快速集成语音合成功能,实现从文本到语音的无缝转换,进而推动智能语音应用的创新和发展。
1557 11
淘宝商品类目API的获取与应用探索
淘宝商品类目API是淘宝开放平台提供的关键服务,允许开发者获取淘宝商品的类目信息,包括根类目、子类目及属性信息。本文介绍API的获取方法、应用场景及使用技巧,帮助电商从业者和开发者更好地利用类目数据,提升商品管理、搜索推荐及数据分析等能力。
545 1
云上智能供应链:重塑物流与供应链管理的未来图景
云上智能供应链作为供应链管理领域的创新实践,正以其独特的优势和潜力引领着供应链管理的未来发展。通过数字化、智能化和集成化的手段,云上智能供应链不仅提升了供应链的整体效能和竞争力,还为企业带来了更多的商业价值和市场机遇。我们有理由相信,在未来的日子里,云上智能供应链将成为推动企业转型升级和实现可持续发展的重要力量。
1686 0
实战 | 使用Spring Boot + Quartz 实现分布式定时任务平台
本文将从项目实战出发来介绍分布式定时任务的实现。在某些应用场景下要求任务必须具备高可用性和可扩展性,单台服务器不能满足业务需求,这时就需要使用Quartz实现分布式定时任务。
实战 | 使用Spring Boot + Quartz  实现分布式定时任务平台
什么是防火墙?详解三种常见的防火墙及各自的优缺点
什么是防火墙?详解三种常见的防火墙及各自的优缺点
1069 2
Redis - Redisson lock和tryLock原理解析
Redis - Redisson lock和tryLock原理解析
689 0
Spring Boot | 集成MapStruct实现不同类型Java对象间的自动转换
MapStruct是一个开源的代码生成器,极大地简化了从一种Java对象到另一种Java对象的转换过程。 MapStruct常用注解
1500 0
Spring Boot | 集成MapStruct实现不同类型Java对象间的自动转换
常见代码复杂度解析
代码质量评价维度,很多都是些主观性的评价维度,需要有专门的人员去查看评判代码,对于审核的人员代码能力要求比较高,而且有时候往往不同的人审核会得出不同的结论,会有争议。然而也有些对代码客观的分析方式可以帮助我们识别代码质量,节省大量人力去分析代码。比如代码复杂度的分析。
3620 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问