好久没写博客了,一个懒字让我停顿了这么久。。进入正题
需求:可自由增加、修改、删除定时任务,项目启动事需要执行一次定时任务
- 这里我用的是quartz-2.2.1.jar,spring是3.2版本
- 对于定时任务quartz我的了解也不多,有很多都是代码的搬运以及调整,对于quartz这一块,我只知道怎么用,还需要进一步学习,慢慢来吧。
- 在这之前,要考虑自己需要什么东西,其一:quartz的xml配置文件,其二:一个定时任务执行类,其三:既然是可自有增加修改删除,还需要一个管理类。一共是两个类+一个配置文件。
xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-lazy-init="true">
<!-- 这个类就是需要做定时任务的类-->
<bean id="MyJob" class="cn.com.yt.service.MyJob"> </bean>
<!-- 定义调用对象和调用对象的方法,id是JobDetail的名字 -->
<bean id="jobtask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 调用的类 -->
<property name="targetObject" ref="myJob" />
<!-- 调用类中的方法 -->
<property name="targetMethod" value="doSomething" />
<!-- 是否并发 防止锁死 -->
<property name ="concurrent" value ="false" />
</bean>
<!-- 这是普通的定义触发时间,可以设置多个定时任务 -->
<!-- <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean "> -->
<!-- <property name="jobDetail" ref="jobtask" /> -->
<!-- cron表达式 -->
<!-- <property name="cronExpression" value="0/1 * * * * ?" /> -->
<!-- </bean> -->
<!-- 这里设置的是项目启动执行一次定时任务 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="jobtask" />
<!-- 启动延迟,毫秒 -->
<property name="startDelay" value="5000" />
<!-- 重复次数 0即只执行一次-->
<property name="repeatCount" value="0" />
</bean>
<!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序
将quartz加入到了spring中后,ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化
lazy-init="false" 立退加载, 表示spring启动时,立刻进行实例化。
(lazy-init 设置只对scop属性为singleton的bean起作用)
lazy-init="true" 延迟加载 ,设置为lazy的bean将不会在ApplicationContext启动时提前被实例化,而是在第一次向容器通过getBean索取bean时实例化的。
如果没有这个配置的话,项目启动则不会执行定时任务
-->
<bean id="startQuertz" lazy-init="true" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>
定时任务管理类
这个类写的不好,很多变量其实可以当做公共变量来用
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
public class QuartzManager {
private Logger logger = Logger.getLogger(QuartzManager.class);
private StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
private Scheduler scheduler ;
/**
* @Description: 添加一个定时任务
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass, String cron) {
try {
scheduler = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail= JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown()) {
logger.info("创建quartz任务成功:任务组名:" + jobGroupName +",任务名:"+jobName + ",触发器组名:"+
triggerGroupName + ",触发器名:" + triggerName + ",cron:" + cron);
scheduler.start();
}
} catch (Exception e) {
logger.error("创建quartz任务失败:任务组名:" + jobGroupName +",任务名:"+jobName + ",触发器组名:" +
triggerGroupName + ",触发器名:" + triggerName+ ",cron:" + cron);
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务的触发时间
*
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置
*/
public void modifyJobTime(String jobName,
String jobGroupName, String triggerName, String triggerGroupName, String cron) {
try {
scheduler = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
scheduler.rescheduleJob(triggerKey, trigger);
logger.info("修改quartz任务成功:任务组名:" + jobGroupName +",任务名:"+jobName + ",触发器组名:"+
triggerGroupName + ",触发器名:" + triggerName + ",cron:" + cron);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class<? extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
*
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
scheduler = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
scheduler.pauseTrigger(triggerKey);// 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
logger.info("移除任务:[jobName]:" + jobName + ",[jobGroupName]" + jobGroupName );
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public void startJobs() {
try {
scheduler = schedulerFactory.getScheduler();
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 判断定时任务是否存在
* @param name 任务名
* @return 如果存在任务返回true
*
* triggerState状态
* BLOCKED 阻塞
* COMPLETE 完成
* COMPLETE 出错
* ERROR 不存在
* NORMAL 正常
* PAUSED 暂停
*
*/
public boolean exist(String name,String group){
try {
scheduler = schedulerFactory.getScheduler();
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group));
for(JobKey jobKey : jobKeys){
if(jobKey.getName().equals(name)){
TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
TriggerState triggerState = scheduler.getTriggerState(triggerKey);
System.out.println(triggerState);
logger.info("任务存在:[jobname]:" + name);
return true;
}
}
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logger.info("任务不存在:[jobname]:" + name);
return false;
}
/**
* 获取到所有运行中的job
*/
@SuppressWarnings("unchecked")
public void getAllJobs(){
try {
scheduler = schedulerFactory.getScheduler();
for(String groupName : scheduler.getJobGroupNames()){
for(JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))){
String jobName = jobKey.getName();
String jobGroup = jobKey.getGroup();
List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
//下一次执行时间
Date nextFireTime = triggers.get(0).getNextFireTime();
System.out.println("运行中任务:[jobName]:" + jobName + ",[groupName]:" + jobGroup + "-" + nextFireTime);
}
}
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
}
任务执行类
在这里是用户将执行任务的时间添加到了数据库中,项目启动时执行一次此类,从而添加一个定时任务到系统中。Myjob2和MyJob3是两个不同的任务类。这里要注意一点,Myjob类已经添加到了配置文件中,但是Myjob2和Myjob3并没有,所有这两个来要实现org.quartz.Job
接口。
/**
* job服务类
* 项目启动时从数据库中查找可执行任务
*/
public class MyJob{
private Logger logger = Logger.getLogger(MyJob.class);
public void doSomething(){
CocAndZfkService service = (CocAndZfkService) ContextUtil.getBean("CocAndZfkService");
List<TblAutoImport> allPath = service.getAllPath();
List<TblInventoryThan> allJob = service.getAllJob();
QuartzManager quartzManager = new QuartzManager();
int count = 0;
for (TblAutoImport tblAutoImport : allPath) {
String name = tblAutoImport.getOperator() + tblAutoImport.getId();
String[] split = tblAutoImport.getAutoTime().split(":");
String cron = split[2] + " " + split[1] + " " + split[0] + " * * ?";
quartzManager.addJob(name, name, name, name, MyJob2.class, cron);
count++;
}
for(TblInventoryThan tblInventoryThan : allJob){
String name = tblInventoryThan.getOperator() + tblInventoryThan.getId();
String[] split = tblInventoryThan.getAutoTime().split(":");
String cron = split[2] + " " + split[1] + " " + split[0] + " * * ?";
quartzManager.addJob(name, name, name, name, MyJob3.class, cron);
count++;
}
logger.info("定时任务启动:共添加了" + count + "条定时任务");
}
}
使用quartz中的疑惑,还未解决
当你的定时任务启动后,你会发现你无法调用spring上下文中的内容,会什么都得不到,上网查找了一些资料,说quartz启动后,是在另外一个独立的线程中运行,所以得不到spring上下文中的东西,例如用户的一些信息。百度了好些方法,还是得不到,望看到文章的大佬能指点一二,万分谢谢。