SpringBoot的出现给我们带来了很多方便,基本上可以基于注解解决掉所有的配置,但是正因为它的迅速迭代,相关文档跟不上,所以有很多坑需要我们去踩,下面将给大家介绍Spinigboot2.0版本对接Quartz任务。
首先我们来了解一下spring常用的任务框架:
1.Spring Schedule
2.Quartz
Spring Schedule是Spring自带的任务框架,简单说他就是一个简化版本的Quartz,但是正因为它有个 与Springboot的集成非常简单,
@SpringBootApplication @ComponentScan(basePackages = {"com.hik.tool","com.hik.dealexcel"}) @EnableCaching @EnableScheduling public class ProjectApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(ProjectApplication.class, args); } }
只需要在springboot的启动类上加上
@EnableScheduling
然后写一个任务执行类,其中cron表示任务执行的时间表示式
@Component public class ScheduledTask { @Scheduled(cron = "0 11 15 * * *") public void reportCurrentTimeCron() throws InterruptedException { System.out.println("任务执行!"); } }
这样就可以完成一个简单的定时任务,不需要依赖其他包,不需要任何配置,是不是很简单,但是这个定时其有个问题,据一位大佬的博客说,一旦某个任务在执行过程中抛出异常,则整个定时器生命周期就结束,以后永远不会再执行定时器任务,但是Quartz就不一样,上次任务出错不会影响下次任务的执行,所以我还是选择了quartz,那么我们开始进入今天正题。
springboot在2.0版本之前,还没有出quartz的starter,所以集成起来相对麻烦点,需要引入多个jar包,然后做相关配置,但是2.0后,只需要引入starter就可以了,以下就是相关步骤(quartz的用法分为内存版本和数据库版本,这里主要讲解内存版本,springboot官方文档里面有讲到直接在application配置文件中如何切换成数据库版本,已经数据库相关信息的配置,总体比之前使用非starter简单很多):
1.引入starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
2.编写任务类继承QuartzJobBean类,实现excuteInternal方法,方法中写自己需要定时执行的
public class UploadTask extends QuartzJobBean { @Resource private TencentYunService tencentYunService; @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("任务开始"); try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任务结束"); } }
3.创建一个配置类,分别制定具体任务类和触发的规则,我们可以和之前的xml配置对应起来看,
uploadTaskDetail指定了具体需要执行的类,只不过具体的方法就是我们需要实现的excuteInternal
uploadTaskTrigger指定了触发的规则
@Configuration public class QuartzConfig { @Bean public JobDetail uploadTaskDetail() { return JobBuilder.newJob(UploadTask.class).withIdentity("uploadTask").storeDurably().build(); } @Bean public Trigger uploadTaskTrigger() { CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?"); return TriggerBuilder.newTrigger().forJob(uploadTaskDetail()) .withIdentity("uploadTask") .withSchedule(scheduleBuilder) .build(); } }
<bean id="cleanupStatusTaskMethod" class= "org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="cleanupStatusTask"/> <property name="targetMethod" value="cleanupStatus"/> <property name="concurrent" value="false"/> </bean> <bean id="cleanupStatusTrigger" class= "org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="cleanupStatusTaskMethod"/> <property name="startDelay" value="300000"/> <property name="repeatInterval" value="60000"/> </bean>
如此一个Quartz集成Springboot就完成了,是不是很简单,在集成的过程中遇到了一个坑,我们看到在xml配置时我们配置了concurrent为false,这个意思是是否并发执行,系统默认为true,即第一个任务还未执行完整,第二个任务如果到了执行时间,则会立马开启新线程执行任务,这样如果我们是从数据库读取信息,两次重复读取可能出现重复执行任务的情况,所以我们需要将这个值设置为false,这样第二个任务会往后推迟,只有在第一个任务执行完成后才会执行第二个任务。
我们只需要在任务类上加入disallowconcurrentExeution就可以了
@DisallowConcurrentExecution public class UploadTask extends QuartzJobBean { @Resource private TencentYunService tencentYunService; @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("任务开始"); try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任务结束"); } }
我们可以看一下效果,我们规定了任务每5s执行一次,而线程等待6秒,如果是并发执行会导致任务开始和任务结束杂乱出现
但是如果我们加上如上注解,那么只会成对先后出现开始和结束
这里只是简单讲解了一下quartz和springboot的集成方法,还有很多内容我们可以去探索,例如job间参数传递,可以使用上述job的biulderd的usingJobData等,以上就是全部内容,如果有不当的地方请帮忙指正,谢谢!