记录一下Spring Boot 创建一个动态时间的定时器

Spring Boot 创建一个动态时间的定时器

  • 背景
  • 创建步骤

背景

  最近做一个小项目的时候需要用到动态发定时通知的功能,本人小菜鸡,找了半天也没找到合适又便捷的解决办法,刚开始写业务的时候觉得就是一行@Scheduled(cron=" ")应该就可以解决的事情,业务写完了来调用 的时候才傻眼了,这个注解方式只能写死并且对应的函数不能带参数,老惨了。

创建步骤

  废话就不多说了,直接上步骤:

  • 创建任务工厂
    这一步的作用是构造一个任务对象。
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class TaskJobFactory extends AdaptableJobFactory {
    @Autowired
    AutowireCapableBeanFactory capableBeanFactory;

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


  • 创建配置类+配置文件
import com.gongfeng.workbeeprj.system.management09.quartz.management.job.TaskJobFactory;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.io.IOException;

@Configuration
public class QuartzConfigurer {

    @Autowired
    TaskJobFactory jobFactory;

    @Bean(name = "SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        //获取配置属性
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        //在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        //创建SchedulerFactoryBean
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setQuartzProperties(propertiesFactoryBean.getObject());
        factory.setJobFactory(jobFactory);
        return factory;
    }

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

quartz.properties文件内容如下:


#quartz集群配置
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceid=AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount = 100
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority = 5
  • 创建任务管理类
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class QuartzJobManager {
    private static final Logger logger = LoggerFactory.getLogger(QuartzJobManager.class);

    private static QuartzJobManager jobUtil;

    @Autowired
    private Scheduler scheduler;

    public QuartzJobManager() {
        jobUtil = this;
    }

    public static QuartzJobManager getInstance() {
        return QuartzJobManager.jobUtil;
    }
  /**
     * 添加通知任务
     * 此处jobName不能相同
     * @param clazz
     * @param jobName
     * @param jobGroupName
     * @param cronExpression
     * @param argMap
     */

    public void addMessageSendJob(Class clazz, String jobName, String jobGroupName, String cronExpression, Map<String, Object> argMap){
        try {
            // 启动调度器
            scheduler.start();
            //构建job信息
            JobDetail jobDetail = JobBuilder.newJob(((Job) clazz.newInstance()).getClass()).withIdentity(jobName, jobGroupName).build();
            //表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(scheduleBuilder).build();
            //获得JobDataMap,写入数据
            if (argMap != null) {
                trigger.getJobDataMap().putAll(argMap);
            }
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 编写任务类
@Component
public class TaskMessageSendJob implements Job {

    @Resource
    public MessageSendService messageSendService;  // 自定义的业务类

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        String taskName = context.getJobDetail().getKey().getName(); // 获取任务名
        Map<String, Object> map = context.getTrigger().getJobDataMap(); // 获取构建任务时的参数列表
        String cron= (String) map.get("cron"); // 获取cron表达式(执行时间)
        // 任务内容开始
        List<String> customerList= (List<String>) map.get("customerList");
        String content= (String) map.get("content");
        messageSendService.sendMessage(customerList,cron,content);
        // 任务内容结束
    }
}
  • 编写Service用于调用定时器
@Service
@Transactional
public class TaskMessageSendService {
    @Autowired
    private QuartzJobManager quartzJobManager;

    /**
     * 定时发送消息
     * 其实这个方法就是用来给定时任务装参数的,具体装配过程参考上一个类
     * @param cron
     * @param customerList
     * @param content
     */
    public void execute(String cron, List<String> customerList, String content) {
        Map<String,Object> map=new HashMap<>();
        map.put("cron",cron);  // cron字符串
        map.put("customerList",customerList);
        map.put("content",content);
        // TaskMessageSendJob是自己创建的job类,具体见上一个类
        quartzJobManager.addMessageSendJob(TaskMessageSendJob.class,"MessageSend"+(new Date()).getTime(),"MessageSend",cron,map);
    }
}
  • 调用定时任务
	@Resource
    private TaskMessageSendService taskMessageSendService;
	
    /**
     * 获取项目后发送消息
     * @param projectList
     * @param time
     * @param content
     * @return
     */
    private CommonResult sendMessageFromProject(List<MessageProject> projectList,String time,String content){
    	// 获取cron字符串
        String cronTime=ConvertTimeToCron(time);
        if(cronTime==null||cronTime=="")
            return new CommonResult(400,"时间格式不正确,\"yyyy-MM-dd HH:mm\"");
        Set<String> customerSet=new HashSet<>();
        if(projectList.size()>0){
            for (MessageProject project : projectList) {
                List<String> memberList = messageSendDao.getCustomerByProject(project.getProjectId());
                for (String str : memberList) {
                    customerSet.add(str);
                }
            }
        }
        List<String> customerList=new ArrayList<>(customerSet);
        CommonResult commonResult=null;
        try {
       		// 设置定时任务
            taskMessageSendService.execute(cronTime,customerList,content);
            commonResult=new CommonResult(200,"定时消息设置成功!");
        }catch (Exception e){
            commonResult=new CommonResult(400,"定时通知设置异常!");
        }
        return commonResult;
    }
	 /**
     * 将时间字符串转为cron字符串
     * @param time
     * @return
     */
    private String ConvertTimeToCron(String time){
        if(!isValidDate(time)) return null;
        StringBuilder str=new StringBuilder();
        // time 是yyyy-MM-dd HH:mm格式的
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
            str.append("0 ");//秒
            String[] strings1=time.split(":");
            str.append(strings1[1]+" "); // 分
            String[] strings2=strings1[0].split(" ");
            str.append(strings2[1]+" "); // 时
            String[] strings3=strings2[0].split("-");
            str.append(strings3[2]+" ");// 日
            str.append(strings3[1]+" ");// 月
            str.append(" ? ");
            str.append(strings3[0]);// 年
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
        return str.toString();
    }


    /**
     * 判断字符串是否是时间格式
     * @param str
     * @return
     */
    public boolean isValidDate(String str) {
        boolean convertSuccess=true;
        // 指定日期格式为四位年/两位月份/两位日期,注意yyyy/MM/dd区分大小写;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
         // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
            convertSuccess=false;
        }
        return convertSuccess;
    }
  • 通过rest接口调用定时任务
    记录一下Spring Boot 创建一个动态时间的定时器_第1张图片
    在这里插入图片描述
    大功告成!!!

你可能感兴趣的:(SpringBoot,JAVA,quartz,spring,boot)