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,感謝能看到這里。
在這里插入圖片描述

歡迎在評論區進行評論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM