Quartz异步定时任务

一、开发概述 😐
1.它是由OpenSymphony提供的、开源的、java编写的强大任务调度框架
2.几乎可以集成到任何规模的运用程序中,如简单的控制台程序,复杂的大规模分布式电子商务系统
3.可用于创建简单的或复杂的计划任务
4.包含很多企业级功能,如支持JTA和集群等
本篇文章,主要从Quartz框架核心组件,Quartz基本运行原理,Quartz核心概念和Quartz基本功能实现(代码)等方面来介绍Quartz。
二 、Quartz原理 😐
在这里插入图片描述
(一)Quartz关键组件 😐
Quartz比较关键的两个核心组件分别为Job和Trigger

job–表示任务是什么
trigger–表示何时触发任务
(二)Quartz几个关键概念 😐
1.IJob

public interface IJob
    {
        void Execute(JobExecutionContext context);
    }

在Quartz中,所有的job任务,必须实现该接口

public class MyJob : IJob
    {
        public void Execute(JobExecutionContext context)
        {
            Console.WriteLine("Quartz基本功能测试。");
        }
    }

2.JobDetail

JobDetail,顾名思义,就是表示关于每个Job的相关信息,它主要包括两个核心组件,即Job Task和JobData Map

3.Trigger

Trigger,表示触发器,根据配置规则来触发执行计划调度job,它主要包括两个核心组件,即SimpleTrigger和CronTrigger

4.IJobStore

IJobStore,表述任务存储器,主要存储job和trigger相关信息。

5.ISchedulerFactory

ISchedulerFactory,表示任务计划工厂,用来管理任务计划IScheduler。

6.IScheduler

IScheduler,表述任务计划,它相当于一个容器,具体job和job相关trigger就能够被注入其中,从而实现任务计划调度。其主要常用的方法:

Start --启动执行计划
Shutdowm --关闭执行计划
接口Code:
(三)核心UML图 😐 在这里插入图片描述
三、代码实现

本示例,我们将使用.net 控制台程序,基于VS2017来使用Quartz建立一个任务:

任务要求:要求在控制台每隔2秒输出:Quartz基本功能测试。

1.首先使用Nuget下载Quartz

本示例使用的Quartz版本为1.0.3

2.按照如下步骤操作在这里插入图片描述
代码: 😐
① .创建QUartzConfig配置类

/**
 * @Author: ycw
 * @Description: TODO
 * @DateTime: 2021/9/13 13:14
 **/
@Configuration
@EnableScheduling
public class QuartzConfig {

    @Autowired
    private JobFactory jobFactory;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        schedulerFactoryBean.setJobFactory(jobFactory);
        return schedulerFactoryBean;
    }

    // 创建schedule
    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }
}

② .QuartzController

/**
 * @Author: ycw
 * @Description: TODO
 * @DateTime: 2021/9/13 14:01
 **/
@RestController
@Slf4j
@CrossOrigin(allowCredentials = "true")
@RequestMapping("/quartz")
public class QuartzController {
@Autowired
private IQuartzService iQuartzService;

    @ApiOperation(value = "定时发邮件")
    @RecordLog(value = "定时发送邮件",operateType = 2)
    @GetMapping("/senMail")
    public R startQuartz(String cron) {
         iQuartzService.startJob(cron, "zz", "zz");
        //参数 第一个是cron表达式 每五秒一次 第二个是job名称 第三个是所在组名称
//        iQuartzService.startJob("*/5 * * * * ? ", "zz", "zz");
        return R.ok();
    }
}

③ .自定义IQuartzService


/**
 * @Author: ycw
 * @Description: TODO
 * @DateTime: 2021/9/13 13:18
 **/
public interface IQuartzService {
    Boolean startJob(String time, String jobName, String group);

    /****
     * 暂停一个任务
     * @param triggerName
     * @param triggerGroupName
     */
    void pauseJob(String triggerName, String triggerGroupName);
    /****
     * 暂停重启一个定时器任务
     * @param triggerName
     * @param triggerGroupName
     */
    void resumeJob(String triggerName, String triggerGroupName);

    /****
     * 删除一个定时器任务,删除了,重启就没什么用了
     * @param triggerName
     * @param triggerGroupName
     */
    void deleteJob(String triggerName, String triggerGroupName);

    /***
     * 根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用
     */
    void doJob(String triggerName, String triggerGroupName);

    /***
     * 开启定时器,这时才可以开始所有的任务,默认是开启的
     */
    void startAllJob();

    /**
     * 关闭定时器,则所有任务不能执行和创建
     */
    void shutdown();
}

④ .实现类IQuartServiceImpl

package cn.cnic.service.impl;

import cn.cnic.job.SendEmailJob;
import cn.cnic.service.IQuartzService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author: ycw
 * @Description: TODO
 * @DateTime: 2021/9/13 13:20
 **/
@Service
@Slf4j
public class IQuartServiceImpl implements IQuartzService{
    @Autowired
    private Scheduler scheduler;
    @Override
    public Boolean startJob(String time, String jobName, String group) {
        Boolean jobResult = false;
        try {
            // 创建jobDetail实例,绑定Job实现类
            // 指明job的名称,所在组的名称,以及绑定job类
            JobDetail jobDetail = JobBuilder.newJob(SendEmailJob.class).withIdentity(jobName, group).build();//设置Job的名字和组
            //corn表达式  每x秒执行一次
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time);
            //设置定时任务的时间触发规则
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, group).withSchedule(scheduleBuilder).build();
//            System.out.println(scheduler.getSchedulerName()+"-------------------------------");
            // 把作业和触发器注册到任务调度中, 启动调度
            scheduler.scheduleJob(jobDetail, cronTrigger);

            jobResult = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jobResult;
    }


    /****
     * 暂停一个任务
     * @param triggerName
     * @param triggerGroupName
     */
    @Override
    public void pauseJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = new JobKey(triggerName, triggerGroupName);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail == null) {
                return;
            }
            System.out.println("开始暂停一个定时器");
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /****
     * 暂停重启一个定时器任务
     * @param triggerName
     * @param triggerGroupName
     */
    @Override
    public void resumeJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = new JobKey(triggerName, triggerGroupName);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail == null) {
                return;
            }
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /****
     * 删除一个定时器任务,删除了,重启就没什么用了
     * @param triggerName
     * @param triggerGroupName
     */
    @Override
    public void deleteJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = new JobKey(triggerName, triggerGroupName);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail == null) {
                return;
            }
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /***
     * 根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用
     */
    @Override
    public void doJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(triggerName, triggerGroupName);
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /***
     * 开启定时器,这时才可以开始所有的任务,默认是开启的
     */
    @Override
    public void startAllJob() {
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭定时器,则所有任务不能执行和创建
     */
    @Override
    public void shutdown() {
        try {
            scheduler.shutdown();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

⑥ .建立一个job包,存放自定义任务。
继承jJobFactory

/**
 * @Author: ycw
 * @Description: TODO
 * @DateTime: 2021/9/13 13:15
 **/
@Component
public class JobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;
    //生成一个job实例
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        //进行注入
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

实现Job接口自定义任务实现类


/**
 * @Author: ycw
 * @Description: TODO
 * @DateTime: 2021/9/13 13:16
 **/
@Slf4j
public class SendEmailJob implements Job {
    // 设置固定的日期格式
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    // 将 yml 中的自定义配置注入到这里
    @Value("${file.save-file-path}")
    private String saveFilePath;

    // 将 yml 中的发件人注入到这里
    @Value("${spring.mail.username}")
    private String fromEmail;

    //注入spring发送邮件的对象
    @Autowired
    private ISendEmailService iSendEmailService;
    @Autowired
    private CImageMapper cImageMapper;
    @Autowired
    private CCustomerMapper cCustomerMapper;
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException{
        //取当前年月
        String date = sdf.format(new Date());
        String year = DateUtil.getTimeStr(date,1);
        String month = DateUtil.getTimeStr(date,2);
        //查询当前年月的数据
        QueryWrapper<CImage> cImageQueryWrapper = new QueryWrapper<>();
        cImageQueryWrapper.eq("year",year).eq("month",month);
        List<CImage> cImageList = null;
        try {
            cImageList = cImageMapper.selectList(cImageQueryWrapper);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("当月无数据!");
        }
        if(!CollectionUtils.isEmpty(cImageList)) {
            Map<String, Object> map = new HashMap<>();
            for (CImage cImage : cImageList) {
                //根据id取出邮件
                QueryWrapper<CCustomer> cCustomerQueryWrapper = new QueryWrapper<>();
                cCustomerQueryWrapper.eq("id", cImage.getCustomerId());
                CCustomer cCustomer = cCustomerMapper.selectOne(cCustomerQueryWrapper);
                String email = cCustomer.getEmail();
                map.put(email, cImage.getFileName());
                System.out.println("map:"+map);
            }
            Boolean isSend = iSendEmailService.sendAttachmentMail(map);
            System.out.println(isSend);
            if (!isSend){
                throw new ExException(2001,"发送失败!");
            }
        }throw new ExException(2001,"邮件发送失败!");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用多台负载均衡服务器来进行quartz定时任务的部署和管理时,我们可以采用以下的一些方案和策略。 首先,为了实现负载均衡,我们可以使用负载均衡器(Load Balancer)来将请求均匀地分发到多台quartz定时任务服务器上。负载均衡器可以根据不同的算法,如轮询、最少连接、源IP等,将任务请求分发到相应的服务器,实现资源的平衡利用。 其次,为了保证任务的高可用性和容错性,我们可以将quartz定时任务服务器设置为多节点集群(Cluster)。各个节点之间通过集群管理协议来协调任务的调度和执行,实现任务的弹性扩展和容灾备份。当某个节点出现故障时,其他节点可以接管故障节点的任务,确保任务的持续执行。 另外,为了确保数据的一致性和可靠性,我们可以采用分布式数据库来存储和管理quartz定时任务的相关数据。通过将任务数据分布在多个数据库实例上,并采用数据同步和故障恢复策略,可以避免单点故障和数据丢失的风险。 此外,为了方便任务的监控和管理,我们可以借助一些监控工具和平台来对多台负载均衡服务器上的quartz定时任务进行实时监控和性能分析。通过查看任务的执行情况、日志输出和运行指标,可以及时发现并解决任务执行异常和性能瓶颈问题。 最后,为了提升任务的执行效率和响应速度,我们可以采用异步执行和任务分片的方式来并行执行quartz定时任务。通过将任务拆分成多个子任务,并由多个执行器同时执行,可以减少任务的等待时间和执行时间,提高任务的整体处理能力。 综上所述,通过使用负载均衡器、集群管理、分布式数据库、监控工具和异步执行等技术手段,我们可以实现quartz定时任务在多台负载均衡服务器上的高效部署和管理。这将为我们提供一个稳定、可靠和高性能的定时任务管理平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值