spring+quartz动态添加、修改、删除任务(包括按照cron表达式执行和间隔时间执行)

功能要求

1.实现项目启动时在启动所有没有过期的任务
2.页面添加、修改、删除任务功能
3.页面功能包含设定任务的开始时间、结束时间、是否暂停功能(暂停功能的实现是直接删除任务,启用时在添加任务)

版本

spring 5.0.5 quartz 2.3.0

1.spring-quartz.xml


<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"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xmlns:task="http://www.springframework.org/schema/task"
       xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	    http://www.springframework.org/schema/beans/spring-beans.xsd
	    http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/tx
	    http://www.springframework.org/schema/tx/spring-tx.xsd
	    http://www.springframework.org/schema/task
	    http://www.springframework.org/schema/task/spring-task.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">
	 


    
    









    






    








    







	<bean id="jobFactory" class="com.lx.dpis.risk.scheduler.JobFactory">bean>
	<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobFactory" ref="jobFactory">property>
	bean>
beans>

2.项目启动后开启所有可以执行的任务

public class RiskOjectScheduler implements ApplicationListener<ContextRefreshedEvent> {

	@Autowired
	private RiskCheckTaskDao rctDao;

	@Autowired
	private QuartzManager qm;
	
	
	public static final String DEFAULT_JOBGROUPNAME = "risk_jobGroupName";
	public static final String DEFAULT_TRIGGERGROUPNAME = "risk_triggerGroupName";

	// //@PostConstruct
	// public void initJobs() {
	// try {
	// @SuppressWarnings("unchecked")
	// List taskList = rctDao.findAll(null);
	// for (RiskCheckTask rct : taskList) {
	// qm.addJob(rct.getRcTaskId(), DEFAULT_JOBGROUPNAME, DEFAULT_TRIGGERNAME,
	// DEFAULT_TRIGGERGROUPNAME,
	// MyJob.class, rct.getCornExp(), rct.getRcTaskId());
	// }
	// } catch (Exception e) {
	// e.printStackTrace();
	// }
	// }

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		if (event.getApplicationContext().getParent() == null) {

			// root application context 没有parent,他就是老大.
			// 需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。
			List<RiskCheckTask> taskList = rctDao.findByProperty(new String[] { "executeFlag","status" }, new String[] { "1","1" });
			if (taskList != null && taskList.size() > 0) {
				for (RiskCheckTask rct : taskList) {
					Date beginTime = null;
					Date endTime = null;
					String taskId = rct.getRcTaskId();
					int checkStyle  = Integer.valueOf(rct.getCheckCycle());
					String checkStyleMode  = rct.getCheckCycleMode();
					int repeatHour = 0;
					switch (checkStyleMode){
						case "HOUR": repeatHour = checkStyle;break;
						case "DAY":repeatHour = checkStyle*24;break;
						case "MONTH":repeatHour = checkStyle*30*24;break;
						case "WEEK":repeatHour = checkStyle*7*24;break;
					}
					try {
						beginTime = DateTool.stringToDateByFormat(rct.getTaskBeginTime(), "yyyy-MM-dd HH:mm:ss");
						endTime = DateTool.stringToDateByFormat(rct.getTaskEndTime(), "yyyy-MM-dd HH:mm:ss");
					} catch (Exception e) {
						e.printStackTrace();
					}
					//List riskInfoList = rctDao.getRiskTaskRel(taskId);
					qm.addJobByInterval(rct.getRcTaskId(), DEFAULT_JOBGROUPNAME, rct.getRcTaskId(), DEFAULT_TRIGGERGROUPNAME,
							RiskJob.class, taskId,repeatHour,beginTime,endTime);
				}
			}
		}
	}
}

3.任务管理类包括按照cron表达式和时间间隔的方法

@Component
public class QuartzManager {

	@Autowired
	private Scheduler scheduler;
	
	/**
	 * 获取定时器调度实例
	 * 
	 * @return 实例对象
	 */
	/*public static QuartzManager getInstance() {
		if (null == instance) {
			synchronized (QuartzManager.class) {
				if (null == instance) {
					instance = new QuartzManager();
				}
			}
		}
		return instance;
	}*/

	/**
	 * 功能: 添加一个定时任务
	 * 
	 * @param jobName
	 *            任务名
	 * @param jobGroupName
	 *            任务组名
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 * @param jobClass
	 *            任务的类类型 eg:TimedMassJob.class
	 * @param cron
	 *            时间设置 表达式,参考quartz说明文档
	 */
	public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
			Class<? extends Job> jobClass, String cron, Object... objects) {
		
		try {
			//cfb.set
			// 任务名,任务组,任务执行类
			JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
			// 触发器
			if (objects != null) {
				for (int i = 0; i < objects.length; i++) {
					jobDetail.getJobDataMap().put("data" + (i + 1), objects[i]);
				}
			}
			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);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 以時間間隔的方式添加任務
	 * @param jobName
	 * @param jobGroupName
	 * @param triggerName
	 * @param triggerGroupName
	 * @param jobClass
	 * @param objects
	 */
	public void addJobByInterval(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
			Class<? extends Job> jobClass, Object... objects) {
		
		try {
			// 任务名,任务组,任务执行类
			JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
			// 触发器
			if (objects != null) {
				for (int i = 0; i < objects.length; i++) {
					jobDetail.getJobDataMap().put("data" + (i + 1), objects[i]);
				}
			}
			TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
			// 触发器名,触发器组
			triggerBuilder.withIdentity(triggerName, triggerGroupName);
			triggerBuilder.startNow();
			// 触发器时间设定
			triggerBuilder.withSchedule(SimpleScheduleBuilder.repeatHourlyForever((int)objects[1]));
			//triggerBuilder.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever((int)objects[1]));
			// 创建Trigger对象
			SimpleTriggerImpl trigger =  (SimpleTriggerImpl) triggerBuilder.build();
			trigger.setStartTime((Date)objects[2]);
			trigger.setEndTime((Date)objects[3]);
			// 调度容器设置JobDetail和Trigger
			scheduler.scheduleJob(jobDetail, trigger);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 功能:修改一个任务的触发时间
	 * 
	 * @param jobName
	 * @param jobGroupName
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 * @param cron
	 *            时间设置,参考quartz说明文档
	 */
	public void modifyJobTimeByInterval(String jobName, String jobGroupName, String triggerName, String triggerGroupName,Object... objects) {
		try {
			int repeatHour=(int) objects[1];
			Date beginTime = (Date) objects[2],endTime=(Date) objects[3];
			TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
			SimpleTriggerImpl trigger = (SimpleTriggerImpl) scheduler.getTrigger(triggerKey);
			if (trigger == null) {
				return;
			}
			long repeatMi = repeatHour*60*60*1000;
			//long repeatMi = repeatHour*1000;
			Date oldBeginTime  = trigger.getStartTime();trigger.getStartTime();
			Date oldEndTime = trigger.getEndTime();
			long oldRepeatHour = trigger.getRepeatInterval();
			if(repeatMi!=oldRepeatHour||!(beginTime.equals(oldBeginTime))||!(endTime.equals(oldEndTime))){
				// 触发器
				TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
				// 触发器名,触发器组
				triggerBuilder.withIdentity(triggerName, triggerGroupName);
				triggerBuilder.startNow();
				// 触发器时间设定
				//triggerBuilder.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever((int)objects[1]));
				triggerBuilder.withSchedule(SimpleScheduleBuilder.repeatHourlyForever((int) objects[1]));
				// 创建Trigger对象
				trigger = (SimpleTriggerImpl) triggerBuilder.build();
				trigger.setStartTime((Date)objects[2]);
				trigger.setEndTime((Date)objects[3]);
				// 方式一 :修改一个任务的触发时间
				scheduler.rescheduleJob(triggerKey, trigger);
			}
			
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName,String cron) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			if (trigger == null) {
				return;
			}
			String oldTime = trigger.getCronExpression();
			if (!oldTime.equalsIgnoreCase(cron)) {
				// 触发器
				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);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 功能: 移除一个任务
	 * 
	 * @param jobName
	 * @param jobGroupName
	 * @param triggerName
	 * @param triggerGroupName
	 */
	public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
			// 停止触发器
			scheduler.pauseTrigger(triggerKey);
			// 移除触发器
			scheduler.unscheduleJob(triggerKey);
			// 删除任务
			scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * @Description:暂停一个任务
	 * @param jobName
	 * @param jobGroupName
	 */
	public void pauseJob(String jobName, String jobGroupName) {
		JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
		try {
			scheduler.pauseJob(jobKey);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @Description:恢复一个任务
	 * @param jobName
	 * @param jobGroupName
	 * @date 2018年5月17日 上午9:56:09
	 */
	public void resumeJob(String jobName, String jobGroupName) {
		JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
		try {
			scheduler.resumeJob(jobKey);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}




	/**
	 * 
	 * 功能:启动所有定时任务
	 */
	public void startJobs() {
		try {
			if (scheduler.isStarted()) {
				System.out.println("定时器已启动。");
			} else {
				scheduler.start();
			}
		} catch (SchedulerException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * 功能:关闭所有定时任务
	 */
	public void shutdownJobs() {
		try {
			if (!scheduler.isShutdown()) {
				scheduler.shutdown();
			}
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
	
	public static List<String> getRecentTriggerTime(String cron) {
		List<String> list = new ArrayList<String>();
		try {
			CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
			cronTriggerImpl.setCronExpression(cron);
			// 这个是重点,一行代码搞定
			List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 8);
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			for (Date date : dates) {
				list.add(dateFormat.format(date));
			}
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return list;
	}

}

4.在实现Job接口的类中 无法注入bean 比如sessionFactory或者查询数据库的dao

第一种方法 继承AdaptableJobFactory

public class JobFactory extends AdaptableJobFactory{
	@Autowired
	private AutowireCapableBeanFactory capableBeanFactory;

	@Override
	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
		//调用父类的方法
	    Object jobInstance = super.createJobInstance(bundle);
	    //进行注入
	    capableBeanFactory.autowireBean(jobInstance);
	    return jobInstance;
	}

}

第二种方法 获取spring的ApplicationContext(又分为两种)

网上查询方法未测试

1.applicationContext-quartz.xml




<beans>
    <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="applicationContextSchedulerContextKey" value="applicationContextKey"/>
        <property name="configLocation" value="classpath:quartz.properties"/>
    bean>
beans>

2.对应的job任务获取ApplicationContext

public class QuartzJobBean implements Job {


	/* (non-Javadoc)
	 * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
	 */
	@Override
	public void execute(JobExecutionContext jobContext) throws JobExecutionException {
		
		
		String jobId = jobContext.getJobDetail().getDescription();
		String serviceId = jobContext.getTrigger().getDescription();
		

		ApplicationContext applicationContext=null;
		try {
			applicationContext=getApplicationContext(jobContext);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		WebServiceService webServiceService = (WebServiceService) applicationContext.getBean("webServiceService");
		WebServicePOJO  webService = webServiceService.getWebService(serviceId);
		ScheduleService.schedule(webService.getNameSpace(), webService.getServiceName(), webService.getWsdlURL(), webService.getMethod());
	}
	
	private static final String APPLICATION_CONTEXT_KEY = "applicationContextKey";
	private ApplicationContext getApplicationContext(JobExecutionContext context) throws Exception {
			ApplicationContext appCtx = null;
			appCtx = (ApplicationContext) context.getScheduler().getContext().get(APPLICATION_CONTEXT_KEY);
			if (appCtx == null) {
				throw new JobExecutionException("No application context available in scheduler context for key \"" + APPLICATION_CONTEXT_KEY + "\"");
			}
			return appCtx;
	}


}

详细查看https://www.tuicool.com/articles/jyuEbi

//在定时任务里面获取sessionFactory,然后OpenSession,执行完成后关闭:
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();  
SessionFactory factory=wac.getBean(SessionFactory.class);
Session session=factory.openSession();
Query query = session.createQuery("from User");
List<User> userlist=query.list();
session.close();

5.Job实现类(业务逻辑)

public class RiskJob implements Job {
	
	@Autowired
	private SessionFactory sf;//此处使用@Autowired注入需要用到配置文件JobFactory类
	
	public static final String DEFAULT_JOBGROUPNAME = "risk_jobGroupName";
	public static final String DEFAULT_TRIGGERGROUPNAME = "risk_triggerGroupName";
	
	//Job实现类 此处需要使用openSession,使用getCurrentSession会报错Could not obtain transaction-synchronized Session for current thread
	//原因是因为从定时任务调用时会启动一个新的线程,而Hibernate和Spring集成Session是绑定到thread上面的。
	public Session getSession() {
		return sf.openSession();
	}
	
	@SuppressWarnings({ "rawtypes",  "unchecked" })
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		System.err.println("任務運行開始-------- start --------");
		Session session = this.getSession();
		try {
			String taskId = (String) context.getJobDetail().getJobDataMap().get("data1");
			Date scheduledFireTime = context.getScheduledFireTime();
			Date nextFireTime = context.getNextFireTime();
			StringBuffer sql = new StringBuffer(
					"SELECT rct.rc_task_id AS rcTaskId, rct.RC_TASK_NAME AS rcTaskName, rct.EXECUTOR_NO AS executorNo, rct.EXECUTOR AS executor, rct.cronExp, rct.TASK_BEGIN_TIME AS taskBeginTime, rct.TASK_END_TIME AS taskEndTime, rto.RISK_OBJECT_ID AS riskObjectId FROM dp_risk_check_task rct, dp_rc_task_obj_rel rto, dp_risk_object ro WHERE rct.RC_TASK_ID = rto.RC_TASK_ID AND rto.RISK_OBJECT_ID = ro.id AND ro.ISVALID='1' AND ro.STATUS='1' AND rct.STATUS = '1' AND rto.STATUS = '1' ");
			if (StringUtils.isNotEmpty(taskId)) {
				sql.append(" and rct.rc_task_id ='" + taskId + "'");
			}
			
			Query s = session.createSQLQuery(sql.toString());
			
			s.setResultTransformer(Transformers.aliasToBean(RiskInfo.class));
			List<RiskInfo> list = s.list();
			if(list!=null&&list.size()>0){
				for (RiskInfo ri : list) {
					RiskCheckRecord rr = new RiskCheckRecord();
					rr.setRcRecordId(UUIDUtil.uuid());
					rr.setRcTaskId(ri.getRcTaskId());
					rr.setRiskObjectId(ri.getRiskObjectId());
					rr.setExecutorNo(ri.getExecutorNo());
					rr.setExecutor(ri.getExecutor());
					rr.setBeginTime(DateTool.dateToString(scheduledFireTime, "yyyy-MM-dd HH:mm:ss"));
					rr.setEndTime(DateTool.dateToString(nextFireTime, "yyyy-MM-dd HH:mm:ss"));
					rr.setCheckStatus("0");
					rr.setStatus("1");
					rr.setCreatorNo("sys");
					rr.setCreator("管理員");
					rr.setCreateDate(new Date());
					session.save(rr);
					session.beginTransaction().commit();
				}
			}
			
			//String jobName = context.getJobDetail().getKey().getName();
			//String jobGroup = context.getJobDetail().getKey().getGroup();
			// String triggerName = context.getTrigger().getKey().getName();
			// String triggerGroup = context.getTrigger().getKey().getGroup();

			/*SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH時mm分ss秒");
			System.out.println("任務Key:" + jobName + ".." + jobGroup + " 正在執行,執行時間: "
					+ dateFormat.format(Calendar.getInstance().getTime()));*/

		} catch (Exception e) {
			System.out.println("捕獲異常===" + e);
			e.printStackTrace();
		} finally {
			session.close();
		}
		System.err.println("任務運行結束-------- end --------");

	}
	

}

6.前台管理任务页面(新增,修改,删除任务)

添加任务

//添加任務
		if(StringUtils.equals("1", rct.getExecuteFlag())){
			qm.addJobByInterval(rcTaskId, DEFAULT_JOBGROUPNAME, rcTaskId, DEFAULT_TRIGGERGROUPNAME,
					RiskJob.class,rcTaskId,repeatHour,beginTime,endTime);
		}

修改任务

if(StringUtils.equals(exectueFlagBefore, "1")&&StringUtils.equals(exectueFlagAfter, "0")){
			qm.removeJob(rct.getRcTaskId(), DEFAULT_JOBGROUPNAME, rct.getRcTaskId(), DEFAULT_TRIGGERGROUPNAME);
		}else if(StringUtils.equals(exectueFlagBefore, "0")&&StringUtils.equals(exectueFlagAfter, "1")){
			qm.addJobByInterval(rct.getRcTaskId(), DEFAULT_JOBGROUPNAME, rct.getRcTaskId(), DEFAULT_TRIGGERGROUPNAME,
					RiskJob.class, rct.getRcTaskId(),repeatHour,beginTime,endTime);
		}else if(StringUtils.equals(exectueFlagBefore, exectueFlagAfter)&&StringUtils.equals(exectueFlagBefore, "1")){
			qm.modifyJobTimeByInterval(rct.getRcTaskId(), DEFAULT_JOBGROUPNAME, rct.getRcTaskId(), DEFAULT_TRIGGERGROUPNAME, rct.getRcTaskId(),repeatHour,beginTime,endTime);
		}

添加修改任务后每个任务都会调用Job实现类execute方法

该教程实现本人项目的功能

你可能感兴趣的:(spring+quartz动态添加、修改、删除任务(包括按照cron表达式执行和间隔时间执行))