springboot使用quartz解决调用不到spring注入service的问题

@

前言

在很多刚使用quartz的小伙伴的体验中,如果说没有碰到这个问题的话,那可能就是还没有往深入的走,也或许有其他的解决方案。

然后wangwang我呢,也找了很久的资料才找到的。然后跟自己的项目需求相结合就成了这个亚子。

后面会放参考博客内容的:(本次为简单参考为主,不做过多讲解)
在这里插入图片描述


一、先图解一下本次文件内容

在这里插入图片描述


二、放代码....

MyJobFactory.java

package com.bj.quartz.config;

import groovy.util.logging.Slf4j;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class MyJobFactory extends SpringBeanJobFactory
        implements ApplicationContextAware {

    @Autowired
    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }

}

QuartzConfiguration.java

package com.bj.quartz.config;

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;
import java.util.Properties;

@Configuration
public class QuartzConfiguration {

    @Autowired
    private MyJobFactory myJobFactory;

    //创建调度器工厂
    @Bean(name = "SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
        factoryBean.setJobFactory(myJobFactory);
        return factoryBean;
    }


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

配置完这些之后,其实就可以了,你就可以通过控制scheduler去生成jobDetail,trigger之类的。并且不用担心spring管理的容器无法注入进来的问题

可能有些人说,这么就这么一点点呢,当然咯quartz的内容往往不止这一些,还有一些持久化的策略之类的,甚至可以提供搭建一个定时任务的控制平台。只不过暂时我这个就只有这些,能开机就使用的定时任务。

接下来的就是我本次需求的两个重点测试:1、定时任务自动停止,2、定时任务中参数改变策略

不需要的小伙伴也可以不看。。。。


三、测试代码

0、创建定时任务

initQuartz.java

这个是写的一个自启动的时候就编译一个定时任务规则的类

package com.bj.quartz.init;

import com.bj.quartz.service.TScheduleTriggerParamService;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;


@Component
public class initQuartz implements ApplicationRunner {
    //job1的定时任务
    @Value("${jobName1}")
    private String jobName;
    @Value("${groupName1}")
    private String groupName;
    @Value("${cron1}")
    private String cron;

    //job2的定时任务
    @Value("${jobName2}")
    private String jobName2;
    @Value("${groupName2}")
    private String groupName2;
    @Value("${cron2}")
    private String cron2;

    @Autowired
    private Scheduler scheduler;

    private static final Logger logger = LoggerFactory.getLogger(initQuartz.class);


    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        logger.info("================quartz启动成功==============");
        //创建job1
        addQuartz(jobName,groupName,cron);
        //创建job2
        addQuartz(jobName2,groupName2,cron2);

    }

    public void addQuartz(String jobName, String jobGroup, String cron){
        try {
        //JobName+JobGroup=Primary Key
        //根据jobName和jobGroup生成TriggerKey
        TriggerKey triggerKey =
                TriggerKey.triggerKey(jobName, jobGroup);
        //根据TriggerKey到Scheduler调度器中获取触发器
        CronTrigger cronTrigger = (CronTrigger)
                scheduler.getTrigger(triggerKey);

        System.out.println("创建调度器");
        //创建任务详情
        JobDetail jobDetail=
                JobBuilder.newJob((Class<? extends Job>) Class.forName(jobName))
                        .withIdentity(jobName,jobGroup)
                        .build();

        //往Job任务中传递参数
        JobDataMap jobDataMap = jobDetail.getJobDataMap();

        //创建表达式调度器
        CronScheduleBuilder cronSchedule =
                CronScheduleBuilder.cronSchedule(cron);

        //创建Trigger
        cronTrigger= TriggerBuilder.newTrigger()
                .withIdentity(jobName, jobGroup)
                .withSchedule(cronSchedule)
                .build();

        //将jobDetail和Trigger注入到scheduler调度器中
        scheduler.scheduleJob(jobDetail,cronTrigger);
    }catch (Exception e){
        e.printStackTrace();
    }
    }



}

1、定时任务自动停止

任务类
Myjob1.java

package com.bj.quartz.job;

import com.bj.util.ControllerUtil;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class Myjob1 implements Job {

    @Value("${jobName1}")
    private String jobName;
    @Value("${groupName1}")
    private String groupName;
    @Value("${cron1}")
    private String cron;


    @Autowired
    private Scheduler scheduler;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        //任务主体
        taskBody(jobExecutionContext);
    }

    /**
     * 任务主体
     */
    private void taskBody(JobExecutionContext jobExecutionContext){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //获取任务详情中的dataMap集合
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        System.out.println("这是我的myjob1111111定时任务"+sdf.format(new Date()));
        System.out.println("本方法的一个参数有:"+jobDataMap.size());
        System.out.println("job:"+jobDataMap.get("job")+"level"+jobDataMap.get("level"));
        System.out.println("-------------------------------");

        String BockStartTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        long timeSize=0;
        try {
            /*
            * 拿当前时间和规定时间相比较
            * */
            timeSize = this.compareTime2(BockStartTime, "20200402172430");
        } catch (ParseException e) {
            e.printStackTrace();
        }

        /*
        * 如果大于0则代表任务该停下来
        * */
        if(timeSize>0){
            System.err.println("stop job 任务!!!");
            //调用停止定时任务的方法
            this.stopQuary(jobName,groupName);
        }
    }

    /**
     * 关闭quary定时任务
     */
    private void stopQuary(String jobName, String groupName){
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName);
        try {
            /*
            *停止触发器
            * */
            scheduler.pauseTrigger(triggerKey);
            /*
             *移除触发器
             * */
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(JobKey.jobKey(jobName, groupName));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
	/**
	 * TODO 取两个时间的差
	 * @param day1
	 * @param day2
	 * @return 秒
	 * @throws ParseException
	 */
	public  long compareTime2(String day1, String day2)
			throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		Date rjsj = df.parse(day1);
		Date dksj = df.parse(day2);
		long stateTimeLong = rjsj.getTime();
		long endTimeLong = dksj.getTime();
		long day = (stateTimeLong - endTimeLong) / 1000L;
		return day;
	}


}

2、定时任务中参数改变策略

Myjob2.java

package com.bj.quartz.job;

import com.bj.entity.TScheduleTriggerParam;
import com.bj.quartz.service.TScheduleTriggerParamService;
import com.bj.quartz.util.paramMap;
import groovy.util.logging.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;


@Component
@Slf4j
public class Myjob2 implements Job {

    @Autowired
    private  TScheduleTriggerParamService tScheduleTriggerParamService;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        //任务主体
        taskBody(jobExecutionContext);
    }
    private void taskBody(JobExecutionContext jobExecutionContext){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //获取任务详情中的dataMap集合
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        //更新params里面的值
        List<TScheduleTriggerParam> params =
                tScheduleTriggerParamService.queryScheduleParamLst(1);
        for (TScheduleTriggerParam param : params) {
            jobDataMap.put(param.getName(),param.getValue());
        }
        System.err.println("这是我的myjob定时任务"+sdf.format(new Date()));
        System.err.println("本方法的一个参数有:"+jobDataMap.size());
        System.err.println("name:"+jobDataMap.get("name")+"score"+jobDataMap.get("score"));
        System.out.println("-------------------------------");
        //我自己提供的一个Map值
        HashMap jobMap1 = paramMap.getJobMap1();
        System.out.println("自己建的map:"+jobMap1.get("hh"));
    }
}

这个我就得唠唠嗑了,参数的设置可能有三种方式:
1、使用一个静态常量的map类,然后每次调用修改参数的service的时候同时把map类中的数据重新替换掉,
2、使用redis进行存储,如果是多集群的话,
3、每次使用job任务的时候都到数据库去查询一下参数并且更替掉。

根据自身情况来吧。。


后言

不过说实话,如果是需要深入了解的还是得看看官方文档之类的。
像w3c中的quartz。

还有我看到的比较详细的:触发器介绍
本次参考后解决问题的博客:Springboot整合quartz框架(附代码)

我是wangwang,感谢能看到这里。
在这里插入图片描述

欢迎在评论区进行评论。

posted @ 2020-04-03 16:52  陌陌卡上  阅读(2216)  评论(0编辑  收藏  举报