Spring boot 集成Quartz的使用(解决quartz的job无法注入spring对象的问题)

本文介绍如何在SpringBoot项目中整合Quartz实现定时任务。包括添加Maven依赖、自定义JobFactory、配置Quartz、实现任务管理等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring Boot 整合 Quartz 实现定时任务

1,添加Maven依赖

	<dependency>
	      <groupId>org.quartz-scheduler</groupId>
	      <artifactId>quartz</artifactId>
	      <version>2.2.1</version>
	  </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

2,新建一个MyJobFactory

这里我们需要注意 我注入了一个 自定义的JobFactory ,然后 把其设置为SchedulerFactoryBean 的 JobFactory。其目的是因为我在具体的Job 中 需要Spring 注入一些Service。
所以我们要自定义一个jobfactory, 让其在具体job 类实例化时 使用Spring 的API 来进行依赖注入。

MyJobFactory 具体实现:

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 MyJobFactory extends AdaptableJobFactory {     
    @Autowired  
    private AutowireCapableBeanFactory capableBeanFactory;  
  
    @Override  
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {  
        // 调用父类的方法  
        Object jobInstance = super.createJobInstance(bundle);  
        // 进行注入  
        capableBeanFactory.autowireBean(jobInstance);  
        return jobInstance;  
    }  
}

3,新建一个QuartzConfig

添加 QuartzConfig 类 来声明相关Bean

import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;


@Configuration
public class QuartzConfig {
    @Autowired
    private MyJobFactory myJobFactory;


    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setJobFactory(myJobFactory);
        System.out.println("myJobFactory:"+myJobFactory);
        return schedulerFactoryBean;
    }
    
    


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

4,新建一个QuartzManager

在其他类中调用本类中的addJob方法进行任务添加

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
/**
 * 
 * @author QQ:1535512395
 *
 */
public class QuartzManager {
	
	@Autowired
	private  Scheduler scheduler;
	
	/**
	 * 功能: 添加一个定时任务
	 * 
	 * @param jobName
	 *            任务名
	 * @param jobGroupName
	 *            任务组名
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 * @param jobClass
	 *            任务的类类型 eg:TimedMassJob.class
	 * @param cron
	 *            时间设置 表达式,参考quartz说明文档
	 * @param objects
	 *            可变参数需要进行传参的值
	 */
	public  void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
			Class jobClass, String cron, Object... objects) {
		try {
	
			// 任务名,任务组,任务执行类
			JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
			System.out.println("jobDetail.getKey:"+jobDetail.getKey());
			// 触发器
			if (objects != null) {
				for (int i = 0; i < objects.length; i++) {
					// 该数据可以通过Job中的JobDataMap dataMap =
					// context.getJobDetail().getJobDataMap();来进行参数传递值
					jobDetail.getJobDataMap().put("data" + (i + 1), objects[i]);
				}
			}
			TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
			// 触发器名,触发器组
			triggerBuilder.withIdentity(triggerName, triggerGroupName);
			triggerBuilder.startNow();
			// 触发器时间设定
			triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
			// 创建Trigger对象
			CronTrigger trigger = (CronTrigger) triggerBuilder.build();
			// 调度容器设置JobDetail和Trigger
			scheduler.scheduleJob(jobDetail, trigger);
			// 启动
			if (!scheduler.isShutdown()) {
				scheduler.start();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	
	}

	/**
	 * 功能:修改一个任务的触发时间
	 * 
	 * @param jobName
	 * @param jobGroupName
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 * @param cron
	 *            时间设置,参考quartz说明文档
	 */
	public  void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
			String cron) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			if (trigger == null) {
				return;
			}
			String oldTime = trigger.getCronExpression();
			if (!oldTime.equalsIgnoreCase(cron)) {
				// 触发器
				TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
				// 触发器名,触发器组
				triggerBuilder.withIdentity(triggerName, triggerGroupName);
				triggerBuilder.startNow();
				// 触发器时间设定
				triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
				// 创建Trigger对象
				trigger = (CronTrigger) triggerBuilder.build();
				// 方式一 :修改一个任务的触发时间
				scheduler.rescheduleJob(triggerKey, trigger);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 功能: 移除一个任务
	 * 
	 * @param jobName
	 * @param jobGroupName
	 * @param triggerName
	 * @param triggerGroupName
	 */
	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));
			
			System.out.println("removeJob:"+JobKey.jobKey(jobName));
			
		} 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,工具类,日期转换cron表达式时间格式

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

public class QuartzCronDateUtils {
	/***
	 * 功能描述:日期转换cron表达式时间格式
	 * 
	 * @param date
	 * @param dateFormat
	 *            : e.g:yyyy-MM-dd HH:mm:ss
	 * @return
	 */
	public static String formatDateByPattern(Date date, String dateFormat) {
		SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
		String formatTimeStr = null;
		if (date != null) {
			formatTimeStr = sdf.format(date);
		}
		return formatTimeStr;
	}

	/***
	 * convert Date to cron ,eg. "14 01 17 22 07 ? 2017"
	 * 
	 * @param date:时间点
	 * @return
	 */
	public static String getCron(java.util.Date date) {
		String dateFormat = "ss mm HH dd MM ? yyyy";
		return formatDateByPattern(date, dateFormat);
	}
	
	public static void main(String[] args) {
		QuartzCronDateUtils s = new QuartzCronDateUtils();
		s.getCron(new Date());
		System.out.println(s.getCron(new Date()));
	}
}

6,监听器

自定义一个监听类,Quartz的job在项目重启时,job都失效了,把每次启动的job都存放在数据库,然后项目启动时监听器读取数据库的job,然后添加job。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.quartz.Job;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.yj.until.QuartzManager;

/**
 * 容器监听器
 * @author QQ 1535512395
 */
public class QuartzJobListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent arg0) {
        /***处理获取数据库的job表,然后遍历循环每个加到job中 ***/
        QuartzManager quartzManager = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(QuartzManager.class);

        //此处就不写获取数据库了,模拟一个集合遍历的数据  
        List<Map<String,Object>> listMap=new ArrayList<>();
        Map<String, Object> map1=new HashMap<String, Object>();
        map1.put("jobClass","com.yj.quartzjob.QuartzJob");
        map1.put("jobName","job1");
        map1.put("jobGroupName","job1");
        map1.put("jobTime","0/5 * * * * ? ");
        listMap.add(map1);

        for (Map<String, Object> map : listMap) {
            try {
                quartzManager.addJob((Class<? extends Job>)(Class.forName((String)map1.get("jobClass")).newInstance().getClass()),(String)map.get("jobName"), (String)map.get("jobGroupName"),(String)map.get("jobTime"));
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
        System.out.println("QuartzJobListener 启动了");
    }
    public void contextDestroyed(ServletContextEvent arg0) {
    }

}

7,具体测试实例调用,不会再抛空指针异常

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;



@Component
public class HelpCutoffTimeJobNew implements Job {
	
	@Autowired
	private SharesMapper sharesMapper;
	
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		// TODO Auto-generated method stub
		String jobName = context.getJobDetail().getKey().toString().substring(8);
		System.out.println(jobName+"问题结算定时任务开启..");
		
		//更新job的执行状态
		sharesMapper.updateJobStatus(jobName);
		
        System.out.println(jobName+"问题结算定时任务结束..");
	}

}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值