SpringBoot+Dubbo+Quartz (三) - 整合 Quartz

一、准备工作

1.maven的 pom.xml中添加依赖

<dependency>
	<groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.0</version>
</dependency>

2.创建quartz内部的11张表

  • 从maven仓库中找到自己要用的版本的 quzrtz jar包,拷贝一份出来,解压;
jar -xvf quartz-2.3.0.jar
  • 打开解压包,建表语句在 org/quartz/impl/jdbcjobstore 目录下
    quartz 建表语句位置

3.配置

3.1 配置文件
org.quartz.scheduler.instanceName = TestSchedulerDev
org.quartz.scheduler.instanceId = AUTO

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 100
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
org.quartz.jobStore.dataSource = myDS


org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://172.xx.x.xxx:3306/tmp?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = root
org.quartz.dataSource.myDS.maxConnections = 20

3.2 配置类
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.sql.DataSource;
import java.io.IOException;

/**
 * @author 
 * @create 2020-06-16 4:16 PM
 */
@Configuration
public class SchedulerConfig implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private JobFactory jobFactory;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("任务已经启动..."+event.getSource());
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        //创建SchedulerFactoryBean
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setJobFactory(jobFactory);
        factory.setWaitForJobsToCompleteOnShutdown(true);//这样当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown。
        factory.setOverwriteExistingJobs(false);
        factory.setStartupDelay(1);
        factory.setConfigLocation(new ClassPathResource("/quartz.properties"));
        return factory;
    }

    /*
     * 通过SchedulerFactoryBean获取Scheduler的实例
     */
    @Bean(name="scheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

    @Bean
    public QuartzInitializerListener executorListener() {
        return new QuartzInitializerListener();
    }
}

/**
 * 创建job 实例工厂,解决spring注入问题,如果使用默认会导致spring的@Autowired 无法注入问题*/

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

4.封装job执行的类

@Service
public class QuartzManager {


    @Autowired
    @Qualifier("scheduler")
    private Scheduler scheduler;

    /** 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名*/
    public void addJob(String jobName, Class jobClass, String time , JobDataMap jobDataMap) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName)
                    .setJobData(jobDataMap)
                    .requestRecovery(false)
                    .storeDurably(true)
                    .build();

            CronTrigger cronTrigger = (CronTrigger)TriggerBuilder.newTrigger()
                    .withIdentity(jobName)
                    .withSchedule(CronScheduleBuilder.cronSchedule(time))
                    .build();

            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**添加一个定时任务*/
    public void addJob(String jobName, String jobGroupName,
                       String triggerName, String triggerGroupName, Class jobClass,
                       String time,JobDataMap jobDataMap) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName,jobGroupName)
                    .setJobData(jobDataMap)
                    .requestRecovery(false)
                    .storeDurably(true)
                    .build();

            CronTrigger cronTrigger = (CronTrigger)TriggerBuilder.newTrigger()
                    .withIdentity(triggerName,triggerGroupName)
                    .withSchedule(CronScheduleBuilder.cronSchedule(time))
                    .build();

            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void updateJob(String jobName, String jobGroupName,
                          String triggerName, String triggerGroupName, Class jobClass,
                          String time,JobDataMap jobDataMap) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if(trigger == null){
                // 新建job
                addJob(jobName,jobGroupName,jobName,jobGroupName,jobClass,time,jobDataMap);
            }else{
                String oldTime = trigger.getCronExpression();
                if(!oldTime.equalsIgnoreCase(time)) {
                    // 触发器
                    TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                    // 触发器名,触发器组
                    triggerBuilder.withIdentity(triggerName, triggerGroupName);
                    triggerBuilder.startNow();
                    // 触发器时间设定
                    triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(time));
                    // 创建Trigger对象
                    trigger = (CronTrigger) triggerBuilder.build();
                    // 方式一 :修改一个任务的触发时间
                    scheduler.rescheduleJob(triggerKey, trigger);
                }
            }
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /** 移除一个任务 */
    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);
        }
    }

    /** 根据分组删除任务*/
    public void removeJobByJobGroup(String jobGroupName){
        try{
            GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroupName);
            Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
            List<JobKey> jobkeyList = new ArrayList<JobKey>();
            jobkeyList.addAll(jobkeySet);

            // 停止触发器
            scheduler.deleteJobs(jobkeyList);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /** 功能:启动所有定时任务 */
    public void startJobs() {
        try {
            scheduler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /** 功能:关闭所有定时任务*/
    public void shutdownJobs() {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

5. 对外发布dubbo接口,提供远程添加/修改/删除job的服务

public interface JmeterJobService {
    /*  新增 */
    void addJob(String operator,Integer cronId,String cronExpression);

    /* 修改 */
    void updateJob(String operator, Integer cronId,String cronExpression);

    /* 删除 */
    void deleteJob(Integer cronId);

    /**  根据组名称批量删除   */
    void removeJobByJobGroup(String jobGroupName);
}
package com.byxf.tmp.executor.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.byxf.common.util.SpringBeanUtil;
import com.byxf.tmp.executor.quartz.QuartzManager;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;


/** @create 2020-06-17 12:56 AM
 */
@Component
@Service(version = "1.0.0",timeout = 4000,retries = -1,interfaceClass = JmeterJobService.class)
public class JmeterJobServiceImpl implements  Job,JmeterJobService{

    private Logger logger = LoggerFactory.getLogger(JmeterJobServiceImpl.class);

    @Autowired
    private QuartzManager quartzManager;

    @Autowired
    private JmeterCronRelationInnerService relationInnerService;


    @Autowired
    private JmeterExecuteService jmeterExecuteService;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
//        JobDataMap data=context.getTrigger().getJobDataMap();
        JobDataMap data=context.getJobDetail().getJobDataMap();
        Integer cronId = Integer.valueOf(String.valueOf(data.get("cronId")));
        String operator = String.valueOf(data.get("operator"));
        List<TmpJmeterCasePo> poList = relationInnerService.getJmeterCaseByCronId(cronId);
        List<Integer> jmeterIdList = new ArrayList<Integer>();
        for(TmpJmeterCasePo po : poList){
            jmeterIdList.add(po.getId());
        }
        //开始调用执行方法
    	jmeterExecuteService.executeBatch(jmeterIdList,operator,"3");
    }
    @Override
    public void addJob(String operator,Integer cronId,String cronExpression) {
        String idName = "jmeter-"+"-"+cronId;
        String groupName = "jmeter-"+"-"+cronId;
        logger.info(">>>>>>新增job任务,{},{},{},{}",idName,groupName,cronExpression,this.getClass());
        try {
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("operator", operator);
            jobDataMap.put("cronId", cronId);
            jobDataMap.put("cronExpression", cronExpression);
            quartzManager.addJob(idName,groupName,idName,groupName,this.getClass(),cronExpression,jobDataMap);
        }catch (Exception e){
            logger.error("调度任务" + idName + "启动异常", e);
        }

    }

    @Override
    public void updateJob(String operator, Integer cronId,String cronExpression) {

        String idName = "jmeter-"+cronId;
        String groupName = "jmeter-"+cronId;
        logger.info(">>>>>>新增job任务,{},{},{},{}",idName,groupName,cronExpression,this.getClass());
        try {
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("operator", operator);
            jobDataMap.put("cronId", cronId);
            jobDataMap.put("cronExpression", cronExpression);
            quartzManager.updateJob(idName,groupName,idName,groupName,this.getClass(),cronExpression,jobDataMap);
        }catch (Exception e){
            logger.error("调度任务" + idName + "更新异常", e);
        }
    }

    @Override
    public void deleteJob(Integer cronId) {
        String idName = "jmeter-"+cronId;
        logger.info(">>>>>>删除job任务,{}",idName);
        try {
            SchedulerFactoryBean schedulerFactoryBean = SpringBeanUtil.getContext().getBean(SchedulerFactoryBean.class);
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.unscheduleJob(new TriggerKey(idName));
            scheduler.deleteJob(new JobKey(idName));
        }catch (SchedulerException e){
            logger.error("调度任务" + idName + "删除异常", e);
        }
    }


    public void removeJobByJobGroup(String jobGroupName) {
        quartzManager.removeJobByJobGroup(jobGroupName);
    }

}

【tips】
在这里插入图片描述
此处对外发布dubbo接口的时候,如果是实现了多个接口,需要指定对外暴露的是那个接口(决定着这个服务对外提供哪个接口的方法让消费者端调用)如果不指定,默认暴露出去的是第一个实现的接口。如果只靠调整实现接口的顺序还是容易出错,因此需要用 interfaceClass 属性指定一个接口。

6. 消费者端调用dubbo服务,操作job。

    @Reference(version = "1.0.0")
    private JmeterJobService jmeterJobService;
    
    @RequestMapping("jobExecute")
    @ResponseBody
    public Object jobExecute(HttpServletRequest request,TmpJmeterCronConfigPo cronConfigPo, String jmeterIds) throws Exception {// @RequestParam(value = "jmeterIdArray[]") List<Integer>jmeterIdArray

        String[] jmeterIdArr = jmeterIds.split(",");
        List list =Arrays.asList(jmeterIdArr);
        List<Integer>  jmeterIdList = new ArrayList<Integer>();
        for(Object o : list){
            Integer jmeterId = Integer.valueOf(o.toString());
            jmeterIdList.add(jmeterId);
        }
        String cronExpression = cronConfigPo.getCronExpression();
       try{
           String operator = clientUserUtil.getUserInfoFromSession(request).getPersonName();
           jmeterCronService.insert(jmeterIdList,cronConfigPo,operator);
           TmpJmeterCronConfigPo lastCronConfigPo = jmeterCronService.getLastPo();
           jmeterJobService.updateJob(operator,lastCronConfigPo.getId(),cronExpression);
           return success("定时任务添加成功");
       }catch (Exception e){
        logger.error(e.getMessage());
       return error("500", "定时任务添加异常");
       }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值