Springboot1.5学习12——Spring Boot定时任务支持(Quartz)

使用quartz步骤很简单,概括来说,分为三步;

1)job - 任务 - 你要做什么事?

2)Trigger - 触发器 - 你什么时候去做?

3)Scheduler - 任务调度 - 你什么时候需要去做什么事?

例如:

public class QuartzMain {
	public static void main(String[] args) throws Exception {
		// 1.创建 Job 对象: 你要做什么事?
		JobDetail job = JobBuilder.newJob(QuartzDemo .class).build();

		/**
		* 简单的 trigger 触发时间: 通过 Quartz 提供一个方法来完成简单的重复
		调用 cron
		* Trigger: 按照 Cron 的表达式来给定触发的时间
		*/
		// 2.创建 Trigger 对象: 在什么时间做?
		// Trigger trigger =TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build();
		Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();

		// 3.创建 Scheduler 对象: 在什么时间做什么事?
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		scheduler.scheduleJob(job, trigger);
		//启动
		scheduler.start();
	}
}

注意:QuartzDemo 就是我们自定义的job任务

/**
* 定义任务类
* * *
/
public class QuartzDemo implements Job {
	/**
	* 任务被触发时所执行的方法
	*/
	public void execute(JobExecutionContext arg0) throws
		JobExecutionException {
		System.out.println("Execute...."+new Date());
	}
}

1. boot整合quartz操作步骤

1.1 引入依赖

咱们需要引入三个坐标,如下;

<!-- Quartz 坐标 -->
<dependency>
	<groupId>org.quartz-scheduler</groupId>
	<artifactId>quartz</artifactId>
	<version>2.2.1</version>
	<exclusions>
		<exclusion>
			<artifactId>slf4j-api</artifactId>
			<groupId>org.slf4j</groupId>
		</exclusion>
	</exclusions>
</dependency>
<!-- 添加 Scheduled 坐标 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Spring tx 坐标 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-tx</artifactId>
</dependency>

1.2 定义Job任务类

/**Job类
 * @author Administrator
 *
 */
public class MyTask implements Job{

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		System.out.println("任务被执行:" + new Date());
	}
	
}

1.3 定义quartz配置类

package com.bjc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

import com.bjc.scheduled.MyTask;

/**quartz的配置类
 * @author Administrator
 *
 */
@Configuration
public class Quartzconfig {
	/**
	 * 1. 创建Job对象
	 * */
	@Bean
	public JobDetailFactoryBean jobDetailFactoryBean() {
		JobDetailFactoryBean factory = new JobDetailFactoryBean();
		// 关联Job任务类
		factory.setJobClass(MyTask.class);
		return factory;
	}
	
	/**
	 *     2. 创建简单的trigger对象
	 * */
	@Bean
	public SimpleTriggerFactoryBean simpleFactory(JobDetailFactoryBean factory) {
		SimpleTriggerFactoryBean simple = new SimpleTriggerFactoryBean();
		// 2.1 关联JobDetail对象
		simple.setJobDetail(factory.getObject());
		
		// 2.2 设置触发时间  参数表示一个执行的毫秒数
		simple.setRepeatInterval(2000);
		
		// 可选操作
		// 设置重复次数
		simple.setRepeatCount(10);
		return simple;
	}
	
	/**
	 *    3. 创建scheduler对象
	 * */
	@Bean
	public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean triggerFactory) {
		SchedulerFactoryBean factory = new SchedulerFactoryBean();
		// 1. 关联trigger
		factory.setTriggers(triggerFactory.getObject());
		
		return factory;
	}
	
}

1.4 开启定时任务——@EnableScheduling

在启动类上加上注解@EnableScheduling

如图:

运行启动类,定时任务就启动了。

2. 使用cron定时器

上例中使用的是简单的定时器,要实现cron定时器很简单

1)将配置对象的第二步替换成下面的代码即可,例如;

@Bean
public CronTriggerFactoryBean cronTrigger(JobDetailFactoryBean factory) {
	CronTriggerFactoryBean cron = new CronTriggerFactoryBean();
	// 2.1 关联jobDetail
	cron.setJobDetail(factory.getObject());
	// 2.2 设置触发时间
	cron.setCronExpression("0/2 * * * * ?");
	
	return cron;
}

2)将第三步中的参数替换成CronTriggerFactoryBean

运行程序,定时器正常运行

3. Job类对象注入

我们编写一个service类,在任务类注入该service,如图:

运行,发现报了空指针异常,

这是为什么了?为什么这里service没有注入进去了?这是因为在我们的quartz配置对象中,在setJobClass实例化我们的job任务的时候,使用的是一个适配器类AdaptableJobFactory,在这里有一个方法

protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
	return bundle.getJobDetail().getJobClass().newInstance();
}

我们可以看到,这个方法很简单,就是拿我们传递过来的字节码通过反射的机制创建的对象,这也就意味着,现在我们的任务类并没有被spring管理,也就是说spring的IOC容器并没有管理我们的任务类,所以就无法完成注入了,所以导致null异常的出现。因为spring的注入要求注入的对象与被注入的对象均在springIOC容器中存在。那么,我们怎么将我们的人物类交给spring容器管理了?我们可以自定义一个适配器工厂类,继承AdaptableJobFactory,重写createJobInstance方法,然后使用AutowireCapableBeanFactory将创建的对象对象手动注入到spring容器中,例如:

package com.bjc.scheduled;

import javax.annotation.Resource;

import org.quartz.Job;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

// 加上@Component注解,让该适配器对象实例化
@Component("myAdaptableJobFactory")
public class MyAdaptableJobFactory extends AdaptableJobFactory{
	
	// 该对象可以将一个对象添加到Spring的IOC容器中,并且完成该对象的属性注入
	@Resource
	private AutowireCapableBeanFactory autowireCapableBeanFactory;
	
	/**
	 *  该方法需要将实例化的任务对象手动的添加到IOC容器中,并完成对象的注入
	 */
	@Override
	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
		Job newInstance = bundle.getJobDetail().getJobClass().newInstance();
		// 将创建的对象添加到SpringIOC容器中,并完成属性注入
		autowireCapableBeanFactory.autowireBean(newInstance);
		// 返回对象
		return newInstance;
	}
	
}

重写了适配器工厂类,怎么使用了?SchedulerFactoryBean对象允许重新设置一个工厂类,例如:

/**
 *    3. 创建scheduler对象
 * */
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean triggerFactory,MyAdaptableJobFactory myAdaptableJobFactory) {
	SchedulerFactoryBean factory = new SchedulerFactoryBean();
	// 1. 关联trigger
	factory.setTriggers(triggerFactory.getObject());
	// 2. 重新设置工厂类
	factory.setJobFactory(myAdaptableJobFactory);
	return factory;
}

注意:schedulerFactoryBean方法新增一个参数,参数就是我们自定义的适配器工厂类,然后通过setJobFactory将该参数对象设置进去。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值