执行一个简单的任务
springboot中实现定时任务有多种方式,我们这里使用spring-boot-starter-quartz
引入依赖
compile group: 'org.springframework.boot', name: 'spring-boot-starter-quartz', version: '2.4.2'
定义一个job
public class CovidDaliyDataJob extends QuartzJobBean {
@Autowired
CovidService covidService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
covidService.saveDailyData();
}
}
这里定时任务的内容为从新冠疫情数据统计网站获取每日的统计数据
@Component
public class CovidServiceImpl implements CovidService {
Logger logger = LoggerFactory.getLogger(CovidServiceImpl.class);
@Value("${covid.daily.data.api}")
private String covidDaliyDataApi;
@Autowired
CovidRepository covidRepository;
@Autowired
RestTemplate restTemplate;
@Override
public void saveDailyData() {
Covid[] dailyList= restTemplate.getForObject(covidDaliyDataApi,Covid[].class);
logger.info("COVID daily data size ===>>>>>[{}]",dailyList.length);
}
}
先将job存储类型配置为内存中。
spring.quartz.job-store-type=memory
covid.daily.data.api=https://api.covidtracking.com/v1/states/current.json
QuartzConfig配置
@Configuration
public class QuartzConfig {
@Bean
public JobDetail jobDetail() {
return JobBuilder.newJob().ofType(CovidDaliyDataJob.class)
.storeDurably()
.withIdentity("Covid_Daily_Data_Job_Detail")
.withDescription("获取每日的各个国家新冠病毒统计数据JobDetail")
.build();
}
@Bean
public Trigger trigger(JobDetail job) {
return TriggerBuilder.newTrigger().forJob(job)
.withIdentity("Covid_Daily_Data_Quartz_Trigger")
.withDescription("获取每日的各个国家新冠病毒统计数据触发器")
.withSchedule(simpleSchedule().repeatForever().withIntervalInSeconds(10))
.build();
}
}
因为springboot已经自动配置了SchedulerFactoryBean,我们可以不再配置Scheduler这样一个最简单的定时任务就可以执行了,为了便于测试这里设置10秒执行一次定时任务。
20:32:09.285 [quartzScheduler_Worker-6] DEBUG org.springframework.web.client.RestTemplate.debug - Accept=[application/json, application/*+json]
20:32:10.973 [quartzScheduler_Worker-6] DEBUG org.springframework.web.client.RestTemplate.debug - Response 200 OK
20:32:11.430 [quartzScheduler_Worker-6] DEBUG org.springframework.web.client.RestTemplate.debug - Reading to [com.example.springboot.model.Covid[]]
20:32:12.380 [quartzScheduler_Worker-6] INFO com.example.springboot.service.impl.CovidServiceImpl.saveDailyData - COVID daily data size ===>>>>>[56]
20:32:19.293 [quartzScheduler_Worker-7] DEBUG org.springframework.web.client.RestTemplate.debug - HTTP GET https://api.covidtracking.com/v1/states/current.json
20:32:19.294 [quartzScheduler_Worker-7] DEBUG org.springframework.web.client.RestTemplate.debug - Accept=[application/json, application/*+json]
20:32:20.484 [quartzScheduler_Worker-7] DEBUG org.springframework.web.client.RestTemplate.debug - Response 200 OK
20:32:20.918 [quartzScheduler_Worker-7] DEBUG org.springframework.web.client.RestTemplate.debug - Reading to [com.example.springboot.model.Covid[]]
20:32:21.833 [quartzScheduler_Worker-7] INFO com.example.springboot.service.impl.CovidServiceImpl.saveDailyData - COVID daily data size ===>>>>>[56]
20:32:29.293 [quartzScheduler_Worker-8] DEBUG org.springframework.web.client.RestTemplate.debug - HTTP GET https://api.covidtracking.com/v1/states/current.json
20:32:29.293 [quartzScheduler_Worker-8] DEBUG org.springframework.web.client.RestTemplate.debug - Accept=[application/json, application/*+json]
20:32:30.373 [quartzScheduler_Worker-8] DEBUG org.springframework.web.client.RestTemplate.debug - Response 200 OK
20:32:30.608 [quartzScheduler_Worker-8] DEBUG org.springframework.web.client.RestTemplate.debug - Reading to [com.example.springboot.model.Covid[]]
20:32:31.104 [quartzScheduler_Worker-8] INFO com.example.springboot.service.impl.CovidServiceImpl.saveDailyData - COVID daily data size ===>>>>>[56]
从控制台可以看出定时任务已经执行了。
在上面的例子中,创建jobdetail和trriger也可以使用FactoryBean的形式
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(CovidDaliyDataJob.class);
jobDetailFactory.setName("Covid_Daily_Data_Job_Detail");
jobDetailFactory.setDescription("获取每日的各个国家新冠病毒统计数据JobDetail");
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(job);
trigger.setName("Covid_Daily_Data_Quartz_Trigger");
trigger.setDescription("获取每日的各个国家新冠病毒统计数据触发器");
trigger.setRepeatInterval(10);
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
return trigger;
}
//corn 表达式触发器
@Bean
public CronTriggerFactoryBean trigger(JobDetail job) {
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(job);
trigger.setName("Covid_Daily_Data_Quartz_Trigger");
trigger.setDescription("获取每日的各个国家新冠病毒统计数据触发器");
trigger.setCronExpression("30 10 1 * * ?");
return trigger;
}
将任务信息存储到数据中
quartz 任务默认存在内存中,要存储到数据库中,只需要配置spring.quartz.job-store-type=jdbc,启动spring应用,因为我这里使用的spring data jpa 会自动创建响应的表,也可以自己手动创建
配置自定义调动工厂bean,连接不同的数据源
我们可能需要将定时任务的表单独放在一个schema中,这样我们可以单独配置个quartz数据源。配置quartz.properties,设置定时任务的其他一些属性
spring.quartz.jdbc.initialize-schema=always
spring.datasource.quartz.jdbc-url=jdbc:mysql://127.0.0.1:3306/zlennon?serverTimezone=UTC&useSSL=false
spring.datasource.quartz.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.quartz.username=root
spring.datasource.quartz.password=123456
@Bean
@QuartzDataSource
@ConfigurationProperties(prefix = "spring.datasource.quartz")
public DataSource quartzDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
schedulerFactory.setJobFactory(new SpringBeanJobFactory());
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
schedulerFactory.setDataSource(quartzDataSource);
return schedulerFactory;
}