springboot中使用quartz进行定时任务操作

场景:使用定时任务进行结算操作,需要跨服务。
技术:定时任务有很多种,因为数据量较小,不涉及到分布式操作,所以不准备用很重的框架。但是希望定时任务能手动开关,所以springboot自带的定时任务就不合适了。最终决定使用quartz。

quartz介绍:

job:接口,里面有一个execute方法需要实现。其中参数JobExecutionContext封装了一些跟job有关的信息。

JobDetail:Use a JobKey with the given name and group to identify the JobDetail
就是说name一样group不一样也不算同一个定时任务。比job多了一个参数group。

Trigger:Use a TriggerKey with the given name and group to identify the Trigger
同样是通过name和group进行唯一标识,但是如果TriggerBuilder在构建trigger时没有使用withIdentity(name,group),则使用通用的trigger。

Scheduler:调度容器,Job与Trigger都需要在容器中注册,被容器统一管理。scheduler中有job的一些基础操作,比如启动暂停删除等。

quartz引入springboot:

引入包

       
            org.quartz-scheduler
            quartz
            2.2.1
        
        
            org.springframework
            spring-context-support
             

启动时tomcat信息


2018-11-22 11:26:57 localhost-startStop-1 INFO Scheduler meta-data: Quartz Scheduler (v2.2.1) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 5 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

quartz存放的方式有很多,我这里为了方便直接存在了内存中,也可以存在数据库。
这里把配置文件直接复制到resource下面就可以了,springboot自动读取配置信息。

# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
#
#
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 5
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 5000

# 默认存储在内存中
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

#持久化,数据源的链接方式
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX

#org.quartz.jobStore.tablePrefix = QRTZ_

#org.quartz.jobStore.dataSource = qzDS

#org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver

#org.quartz.dataSource.qzDS.URL =

#org.quartz.dataSource.qzDS.user = 

#org.quartz.dataSource.qzDS.password = 

#org.quartz.dataSource.qzDS.maxConnections = 10

这里记录一个坑,在job实现类中使用@Autowired注入services进行数据库操作或者别的,就报空指针异常。就是说jobinstance没有被spring代理到,需要在JobFactory中使用AutowireCapableBeanFactory 进行手动注入

@Component
public class JobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

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

配置信息:

@Configuration
public class SchedulerConfig {

	@Autowired   
	private JobFactory jobFactory;
	
    @Bean(name="SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
    	SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setJobFactory(jobFactory);
        factory.setQuartzProperties(quartzProperties());
        return factory;

    }

    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        //在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    /*
     * quartz初始化监听器
     */
    @Bean
    public QuartzInitializerListener executorListener() {
       return new QuartzInitializerListener();
    }

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

}

使用@RestContorller进行定时任务的开启暂停等操作。

@RestController
@RequestMapping(value="/job")
public class JobController 
{
	
	
	//加入Qulifier注解,通过名称注入bean
	@Autowired @Qualifier("Scheduler")
	private Scheduler scheduler;	

	@PostMapping(value="/addjob")
	public void addjob(@RequestBody Map paraMap) throws Exception
	{			
		addJob(paraMap.get("jobClassName"), paraMap.get("jobGroupName"), paraMap.get("cronExpression"));
	}
	
	public void addJob(String jobClassName, String jobGroupName, String cronExpression)throws Exception{
        
        // 启动调度器  
		scheduler.start(); 
		
		//构建job信息
		JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName, jobGroupName).build();
		
		//表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
            .withSchedule(scheduleBuilder).build();
        
        try {
        	scheduler.scheduleJob(jobDetail, trigger);
            
        } catch (SchedulerException e) {
            System.out.println("创建定时任务失败"+e);
            throw new Exception("创建定时任务失败");
        }
	}
 

	@PostMapping(value="/pausejob")
	public void pausejob(@RequestBody Map paraMap) throws Exception
	{			 
		jobPause(paraMap.get("jobClassName"), paraMap.get("jobGroupName"));
	}
	
	public void jobPause(String jobClassName, String jobGroupName) throws Exception
	{	
		scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
	}
	

	@PostMapping(value="/resumejob")
	public void resumejob(@RequestBody Map paraMap) throws Exception
	{			
		jobresume(paraMap.get("jobClassName"), paraMap.get("jobGroupName"));
	}
	
	public void jobresume(String jobClassName, String jobGroupName) throws Exception
	{
		scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
	}
	
	
	@PostMapping(value="/reschedulejob")
	public void rescheduleJob(@RequestBody Map paraMap) throws Exception
	{			
		jobreschedule(paraMap.get("jobClassName"), paraMap.get("jobGroupName"), paraMap.get("cronExpression"));
	}
	
	public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception
	{				
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
			// 表达式调度构建器
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

			// 按新的trigger重新设置job执行
			scheduler.rescheduleJob(triggerKey, trigger);
		} catch (SchedulerException e) {
			System.out.println("更新定时任务失败"+e);
			throw new Exception("更新定时任务失败");
		}
	}
	
	
	@PostMapping(value="/deletejob")
	public void deletejob(@RequestBody Map paraMap) throws Exception
	{			
		jobdelete(paraMap.get("jobClassName"), paraMap.get("jobGroupName"));
	}
	
	public void jobdelete(String jobClassName, String jobGroupName) throws Exception
	{		
		scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
		scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
		scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));				
	}
	
	@PostMapping(value="/getalljob")
	public List getalljob() throws Exception
	{			
		return getAllJobs();
	}
	public List getAllJobs(){
        try {                    
        	List list = new ArrayList();
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    String jobName = jobKey.getName();
                    String jobGroup = jobKey.getGroup();
                    //get job's trigger
                    List triggers = (List) scheduler.getTriggersOfJob(jobKey);
                    Date nextFireTime = triggers.get(0).getNextFireTime();
                    list.add(("[jobName] : " + jobName + " [groupName] : "
                        + jobGroup + " - " + nextFireTime));
                    
                }
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
		return null;
    }
	
	
	public static BaseJob getClass(String classname) throws Exception 
	{
		Class class1 = Class.forName(classname);
		return (BaseJob)class1.newInstance();
	}
	
	
}
import org.quartz.Job;

public interface BaseJob extends Job {

}

你可能感兴趣的:(源码分析,电子商务,spring,cloud,spring,boot)