ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springboot2.x玩转quartz

2021-09-18 11:30:47  阅读:210  来源: 互联网

标签:quartz String public springboot2 玩转 org import throws uniqueNameId


介绍springboot2.x整合quartz,并给出一个基本的jdbc持久化的cron示例。

maven依赖:

        <!--spring boot集成quartz-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
         <!--quartz依赖c3p0作为jdbc持久化数据库连接池-->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

springboot配置yaml:

#数据源配置
spring:
  quartz:
    #相关属性配置
    properties:
      org:
        quartz:
          dataSource:
            quartzDS:
              driver: com.mysql.cj.jdbc.Driver
              URL: jdbc:mysql://192.168.1.105:3306/smart-bar-dev?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
              user: root
              password: 你的密码
          scheduler:
            instanceName: clusteredScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: QRTZ_
            useProperties: false
            dataSource: quartzDS
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true
      #数据库方式
      job-store-type: jdbc
        #初始化表结构
        jdbc:
          initialize-schema: always #每次启动都初始化数据库,3种模式(ALWAYS、EMBEDDED、NEVER)

一切顺利,你启动之后可以看到数据库表已经生成(initialize-schema: never此时可以关闭了):
在这里插入图片描述
接下来开始写代码cron示例:
JobService是job的基本操作,代码:

import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springblade.modules.quartz.job.DateTimeJob;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author hsj
 * @description:job的基本操作
 * @date 2021/9/17 18:36
 */
@Component
@Slf4j
public class JobService {

	//加入Qulifier注解,通过名称注入bean
	@Resource
	private Scheduler schedulerQuartz;
	//GROUP组
	private final static String TRIGGER_IDENTITY = "QuartzTaskServiceTrigger";

	/**
	 * @Description:添加job
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/17 18:38
	 */
	//CronTrigger
	public void addCronJob(String msg, String cron,String uniqueNameId) throws Exception {

		// 启动调度器
		schedulerQuartz.start();

		//构建job信息
		JobDetail jobDetail = JobBuilder.newJob(DateTimeJob.class)//PrintTimeJob我们的业务类
			.withIdentity(uniqueNameId,TRIGGER_IDENTITY)
			//每个JobDetail内都有一个Map,包含了关联到这个Job的数据,在Job类中可以通过context获取
			.usingJobData("msg", msg)//关联键值对
			.storeDurably()//即使没有Trigger关联时,也不需要删除该JobDetail
			.build();

		//表达式调度构建器(即任务执行的时间)
		//按新的cronExpression表达式构建一个新的trigger
		CronTrigger trigger = TriggerBuilder.newTrigger()
			.forJob(jobDetail)//关联上述的JobDetail
			.withIdentity(uniqueNameId,TRIGGER_IDENTITY)
			.withSchedule(CronScheduleBuilder.cronSchedule(cron))// "0/1 * * * * ?"
			.build();

		try {
			schedulerQuartz.scheduleJob(jobDetail, trigger);

		} catch (SchedulerException e) {
			log.info("创建定时任务失败" + e);
			throw new Exception("创建定时任务失败");
		}
	}

	/**
	 * @Description:暂停job
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/17 18:38
	 */
	public void jobPause(String uniqueNameId) throws Exception {
		schedulerQuartz.pauseJob(JobKey.jobKey(uniqueNameId,TRIGGER_IDENTITY));
	}

	/**
	 * @Description:恢复job
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/17 18:38
	 */
	public void jobresume(String uniqueNameId) throws Exception {
		schedulerQuartz.resumeJob(JobKey.jobKey(uniqueNameId,TRIGGER_IDENTITY));
	}


	/**
	 * @Description:更新job
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/17 18:38
	 */
	public void jobreschedule(String cron,String uniqueNameId) throws Exception {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(uniqueNameId,TRIGGER_IDENTITY);
			// 表达式调度构建器
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);

			CronTrigger trigger = (CronTrigger) schedulerQuartz.getTrigger(triggerKey);

			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

			// 按新的trigger重新设置job执行
			schedulerQuartz.rescheduleJob(triggerKey, trigger);
		} catch (SchedulerException e) {
			log.info("更新定时任务失败" + e);
			throw new Exception("更新定时任务失败");
		}
	}


	/**
	 * @Description:删除job
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/17 18:39
	 */
	public void jobdelete(String uniqueNameId) throws Exception {
		schedulerQuartz.pauseTrigger(TriggerKey.triggerKey(uniqueNameId,TRIGGER_IDENTITY));
		schedulerQuartz.unscheduleJob(TriggerKey.triggerKey(uniqueNameId,TRIGGER_IDENTITY));
		schedulerQuartz.deleteJob(JobKey.jobKey(uniqueNameId,TRIGGER_IDENTITY));
	}

}

JobController接口:


import lombok.extern.slf4j.Slf4j;
import org.springblade.modules.quartz.service.JobService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author hsj
 * @description:
 * @date 2021/9/17 17:39
 */
@Slf4j
@RestController
@RequestMapping(value = "blade-quartz-job")
public class JobController {

	@Resource
	private JobService jobService;
	/**
	 * 添加任务
	 *
	 * @throws Exception
	 */
	@PostMapping(value = "/addjob")
	public void addjob(@RequestParam(value = "msg") String msg, @RequestParam(value = "cron") String cron,@RequestParam(value = "uniqueNameId") String uniqueNameId) throws Exception {
		jobService.addCronJob(msg, cron ,uniqueNameId);
	}
	/**
	 * 暂停任务
	 *
	 * @throws Exception
	 */
	@PostMapping(value = "/pausejob")
	public void pausejob(@RequestParam(value = "uniqueNameId") String uniqueNameId) throws Exception {
		jobService.jobPause(uniqueNameId);
	}
	/**
	 * 恢复任务
	 * @throws Exception
	 */
	@PostMapping(value = "/resumejob")
	public void resumejob(@RequestParam(value = "uniqueNameId") String uniqueNameId) throws Exception {
		jobService.jobresume(uniqueNameId);
	}
	/**
	 * 更新任务
	 *
	 * @param cron
	 * @throws Exception
	 */
	@PostMapping(value = "/reschedulejob")
	public void rescheduleJob(@RequestParam(value = "cron") String cron,@RequestParam(value = "uniqueNameId") String uniqueNameId) throws Exception {
		jobService.jobreschedule(cron,uniqueNameId);
	}
	/**
	 * 删除任务
	 * 删除操作前应该暂停该任务的触发器,并且停止该任务的执行
	 *
	 * @throws Exception
	 */
	@PostMapping(value = "/deletejob")
	public void deletejob(@RequestParam(value = "uniqueNameId") String uniqueNameId) throws Exception {
		jobService.jobdelete(uniqueNameId);
	}

}



基本的服务有了,下面开始示例(一个定时控制继电器操作demo):
JobMessage,业务对象


import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author hsj
 * @description:
 * @date 2021/9/18 9:14
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class JobMessage {
	//0表示区间需要通电,1表示区间需要断电
	private int type;
	//0表示开始时间,1表示结束时间
	private int timeType;
	//设备型号:host_model
	private int hostModel;
	//设备id->deviceId
	private long deviceId;
	//继电器0~8
	private int electricRelay;

	@Override
	public String toString() {
		return JSON.toJSONString(this);
	}

	public static JobMessage parseFromString(String jobMessage){
		return JSON.parseObject(jobMessage,JobMessage.class);
	}
}

JobDetail相关的业务代码:


import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springblade.common.constant.CommonConstant;
import org.springblade.common.utils.SpringUtils;
import org.springblade.modules.quartz.msg.JobMessage;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * @author hsj
 * @description:JobDetail相关的业务代码
 * @date 2021/9/17 17:45
 */
@Slf4j
public class DateTimeJob extends QuartzJobBean {

	/**
	 * @Description:定制执行器执行时间点job
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/18 10:45
	 */
	@Override
	protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		ThreadPoolTaskExecutor threadPoolTaskExecutor = SpringUtils.getBean(ThreadPoolTaskExecutor.class);
		//不要阻塞quartz线程池执行后面的任务
		threadPoolTaskExecutor.execute(()->{
			//获取JobDetail中关联的数据
			String jobMessageStr = (String) jobExecutionContext.getJobDetail().getJobDataMap().get("msg");
			JobMessage jobMessage = JobMessage.parseFromString(jobMessageStr);
			log.info("获取JobDetail中关联的数据:{}",jobMessage.toString());
            //执行业务逻辑
			doBussiness(jobMessage);
		});
	}

	/**
	 * @Description:执行业务逻辑
	 * @author HeShengjin 2356899074@qq.com
	 * @date 2021/9/18 10:44
	 */
	private void doBussiness(JobMessage jobMessage) {
		//区间需要通电,start就是通电操作,end就是断电操作
		if (CommonConstant.JobMessage.TYPE_0 == jobMessage.getType()){
			//start控制主机继电器通电
			if(CommonConstant.JobMessage.TIMETYPE_0 == jobMessage.getTimeType()){
				log.info("区间需要通电,start就是通电操作,end就是断电操作-->start控制主机继电器通电,deviceId={},hostModel={},electricRelay={}"
					, jobMessage.getDeviceId(), jobMessage.getHostModel(), jobMessage.getElectricRelay());
				//TODO
			}
			//end控制主机继电器断电
			else{
				log.info("区间需要通电,start就是通电操作,end就是断电操作-->end控制主机继电器断电,deviceId={},hostModel={},electricRelay={}"
					, jobMessage.getDeviceId(), jobMessage.getHostModel(), jobMessage.getElectricRelay());
				//TODO
			}
		}
		//区间需要断电,start就是断电操作,end就是通电操作
		else {
			//start控制主机继电器断电
			if(CommonConstant.JobMessage.TIMETYPE_0 == jobMessage.getTimeType()){
				log.info("区间需要断电,start就是断电操作,end就是通电操作-->start控制主机继电器断电,deviceId={},hostModel={},electricRelay={}"
					, jobMessage.getDeviceId(), jobMessage.getHostModel(), jobMessage.getElectricRelay());
				//TODO
			}
			//end控制主机继电器通电
			else{
				log.info("区间需要断电,start就是断电操作,end就是通电操作-->end控制主机继电器通电,deviceId={},hostModel={},electricRelay={}"
					, jobMessage.getDeviceId(), jobMessage.getHostModel(), jobMessage.getElectricRelay());
				//TODO
			}
		}
	}
}

测试一下:


import lombok.extern.slf4j.Slf4j;
import org.springblade.api.DeviceCtl;
import org.springblade.api.nettyadapter.HostModel;
import org.springblade.common.constant.CommonConstant;
import org.springblade.common.utils.CronExpressionUtils;
import org.springblade.modules.quartz.msg.JobMessage;
import org.springblade.modules.quartz.service.JobService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author hsj
 * @description:测试quartz启动执行
 * @date 2021/9/17 10:53
 */
@Slf4j
@Component
public class MyCommand  implements CommandLineRunner {

	@Resource
	private JobService jobService;

	@Override
	public void run(String... args) throws Exception {
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~实例说明前提:区间需要通电~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		//当添加一条规则(规则有数据库唯一主键ID:1123598821738675201):比如每天10:02:02~18:05:50之间需要通电
		
		//其实是说: 每天10:02:02通电(继电器控制)
		//          每天18:05:50断电(继电器控制)

		String uniqueNameIdStart = "1123598821738675201-start";//数据库唯一主键ID-start保证唯一
		String uniqueNameIdEnd = "1123598821738675201-end";//数据库唯一主键ID-end保证唯一
		//每天10点02分02秒执行一次任务
		//"02 02 10 * * ?"
		String cronStart = CronExpressionUtils.conversionHmsCron("10:02:02");
		//每天18点05分50秒执行一次任务
		//"50 05 18 * * ?"
		String cronEnd = CronExpressionUtils.conversionHmsCron("18:05:50");

		//添加执行任务
		//每天10:02:02通电(继电器控制)...
		jobService.addCronJob(
			JobMessage.builder()
				.type(CommonConstant.JobMessage.TYPE_0)//区间需要通电
				.timeType(CommonConstant.JobMessage.TIMETYPE_0)//开始时间
				.hostModel(HostModel.YOUREN_IO_444)//实际数据根据deviceId从主机表blade_iot_device_host.host_model获取
			    .deviceId(1437253753398898700L)//实际的deviceId
			    .electricRelay(DeviceCtl.Number.number0)//第一个继电器
				.build()
			    .toString(),
			cronStart,
			uniqueNameIdStart);
		//添加执行任务
		//每天18:05:50断电(继电器控制)...
		jobService.addCronJob(
			JobMessage.builder()
				.type(CommonConstant.JobMessage.TYPE_0)//区间需要通电
				.timeType(CommonConstant.JobMessage.TIMETYPE_1)//结束时间
				.hostModel(HostModel.YOUREN_IO_444)//实际数据根据deviceId从主机表blade_iot_device_host.host_model获取
				.deviceId(1437253753398898700L)//实际的deviceId
				.electricRelay(DeviceCtl.Number.number0)//第一个继电器
				.build()
				.toString(),
			cronEnd,
			uniqueNameIdEnd);

		//根据uniqueNameId暂停任务
//		jobService.jobPause(uniqueNameIdStart);
//		jobService.jobPause(uniqueNameIdEnd);

		//根据uniqueNameId恢复已暂停任务
//		jobService.jobresume(uniqueNameIdStart);
//		jobService.jobresume(uniqueNameIdEnd);

		//根据uniqueNameId更新任务执行时间cron->cronNew
		//更新到每天11:02:02通电(继电器控制)
//		String cronStartNew = CronExpressionUtils.conversionHmsCron("11:02:02");
//		jobService.jobreschedule(cronStartNew,uniqueNameIdStart);

		//根据uniqueNameId删除任务(规则删除时候请务必删除定时任务)
//		jobService.jobdelete(uniqueNameIdStart);
//		jobService.jobdelete(uniqueNameIdEnd);
	}
}

附录:
ThreadPoolTaskExecutor是spring框架的线程池
SpringUtils是一个工具,获取spring容器Bean对象。


import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * spring工具类 方便在非spring管理环境中获取bean
 * @author Dylan
 */
@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
    /**
     * Spring应用上下文环境
     */
    private static ConfigurableListableBeanFactory beanFactory;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringUtils.beanFactory = beanFactory;
    }

    /**
     * 获取对象
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws BeansException
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 获取类型为requiredType的对象
     * @param clz
     * @return
     * @throws BeansException
     */
    public static <T> T getBean(Class<T> clz) throws BeansException {
        return beanFactory.getBean(clz);
    }

    /**
     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
     * @param name
     * @return boolean
     */
    public static boolean containsBean(String name) {
        return beanFactory.containsBean(name);
    }

    /**
     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
     * @param name
     * @return boolean
     * @throws NoSuchBeanDefinitionException
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.isSingleton(name);
    }

    /**
     * @param name
     * @return Class 注册对象的类型
     * @throws NoSuchBeanDefinitionException
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getType(name);
    }

    /**
     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
     * @param name
     * @return
     * @throws NoSuchBeanDefinitionException
     */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getAliases(name);
    }

    /**
     * 获取aop代理对象
     * @param invoker
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getAopProxy(T invoker) {
        return (T) AopContext.currentProxy();
    }
}

标签:quartz,String,public,springboot2,玩转,org,import,throws,uniqueNameId
来源: https://blog.csdn.net/HSJ0170/article/details/120363783

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有