IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot 07 如何实现任务调度及常见问题 -> 正文阅读

[Java知识库]SpringBoot 07 如何实现任务调度及常见问题


定时调度是指在无人值守的时候,系统可以在某一时刻执行某些特定的功能而采用的一种机制。本文总结三种实现任务调度的方法


1.使用@Scheduled 实现调度

本方法主要通过@EnableScheduling和?@Scheduled两个注解实现调度, 两个注解并不是springboot增加的注解,而是springframwork的注解,由spring-context包提供

实现方式如下:

  • 启动主类不需要做其他特殊处理直接使用@SpringBootApplication即可,并不需要其他注解
  • 调度类ScheduledTaskService 首先是一个bean,然后在方法上使用@EnableScheduling开启任务调度
  • 使用@Scheduled标注配置调度任务方法,其中支持三个属性fixedRate? 、fixedDelay 、cron?
@SpringBootApplication
public class SchedulerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchedulerApplication.class, args);
    }
}

1.fixedRate是按照一定的速率执行

? ? ? ?此调度是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行

@Component
@EnableScheduling
public class ScheduledTaskService {

    private static final SimpleDateFormat dataFormat = new SimpleDateFormat("HH:mm:ss");

    @Scheduled(fixedRate = 5000)
    //@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)  //使用timeUnit设置时间单位
    public void reportCurrentTime() throws InterruptedException {
        System.out.println("间隔5秒执行:" + dataFormat.format(new Date()));
        Thread.sleep(6000);
        System.out.println("间隔5秒结束:" + dataFormat.format(new Date()));
    }
}
启动SpringBoot查看执行结果:可见先前的任务结束后不会再等间隔

间隔5秒执行:19:55:00
间隔5秒结束:19:55:06
间隔5秒执行:19:55:06
间隔5秒结束:19:55:12
间隔5秒执行:19:55:12
间隔5秒结束:19:55:18

2.fixedDelay控制方法执行的间隔时间

? ? ? 此调度方式是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次

@Component
@EnableScheduling
public class ScheduledTaskService {

    private static final SimpleDateFormat dataFormat = new SimpleDateFormat("HH:mm:ss");


    //@Scheduled(fixedDelay = 5000)
    @Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS)  //可以使用timeUnit设置时间单位
    public void reportCurrentTime2() throws InterruptedException {
        System.out.println("间隔5秒执行:" + dataFormat.format(new Date()));
        Thread.sleep(6000);
        System.out.println("间隔5秒结束:" + dataFormat.format(new Date()));
    }
}
启动SpringBoot查看执行结果:上一次执行5秒后才会执行

间隔5秒执行:20:00:55
间隔5秒结束:20:01:01

间隔5秒执行:20:01:06
间隔5秒结束:20:01:12

间隔5秒执行:20:01:17
间隔5秒结束:20:01:23

3. 使用cron表达式定制任务

执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起, 调度代码如下

@Component
@EnableScheduling
public class ScheduledTaskService {

    @Scheduled(cron = "0/3 * * * * ?")
    public void fixTimeExecution() {
        System.out.println("指定时间执行:" + dataFormat.format(new Date()));
    }

}
启动SpringBoot查看执行结果:执行间隔是每3秒打印一次

指定时间执行:20:06:30
指定时间执行:20:06:33
指定时间执行:20:06:36
指定时间执行:20:06:39
指定时间执行:20:06:42
指定时间执行:20:06:45

其中 cron表达式,如* * * * * *由六个空格分隔的时间和日期字段组成,每个字段都有自己的有效值范围:

 ┌───────────── second (0-59)
 │ ┌───────────── minute (0 - 59)
 │ │ ┌───────────── hour (0 - 23)
 │ │ │ ┌───────────── day of the month (1 - 31)
 │ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC)
 │ │ │ │ │ ┌───────────── day of the week (0 - 7)
 │ │ │ │ │ │          (0 or 7 is Sunday, or MON-SUN)
 │ │ │ │ │ │
 * * * * * *
  • @Scheduled cron只支持6位,分别是:秒、分、时、日、月、周
  • @Scheduled cron不支持第7位“年”,即不支持配置这样的格式,例如“0/1 * * * * ? 2099”?
  • @Scheduled(cron = "-")? ?当配置为“-” 时,表示不启动不启动任务,从corn的属性标注可以看到此信息
  • @Scheduled(cron = "${myjob.cron}")? 方式从配置文件中获取表达式配置,从corn的属性标注可以看到此信息
 * <p>The special value {@link #CRON_DISABLED "-"} indicates a disabled cron
	 * trigger, primarily meant for externally specified values resolved by a
	 * <code>${...}</code> placeholder.
	 * @return an expression that can be parsed to a cron schedule
	 * @see org.springframework.scheduling.support.CronExpression#parse(String)
	 */
	String cron() default "";

2.使用XML 实现Scheduler任务

实现方式如下:

  • 使用在XML文件中定义JobDetailFactoryBean等信息,
  • 使用@ImportResource注解将XML配置的Bean加载到容器中,

? ? ? 一般低版本的Spring项目中调度都配置到XML中,所以当将spring项目迁移成springboot项目的时候使用此方法是比较省事比较快捷的方式,

@ImportResource(locations= {"classpath:spring-job.xml"})
@SpringBootApplication
public class SchedulerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchedulerApplication.class, args);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd" default-lazy-init="false">

    <bean id="autoCancelProduct" class="com.boot.basic.scheduled.AutoCancelProduct">

    </bean>


    <bean id="autoCancelProductDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="name" value="autoCancelProductDetail"/>
        <property name="group" value="Order_Trigger_Group"/>
        <property name="targetObject" ref="autoCancelProduct"/>
        <property name="targetMethod" value="executeJob"/>
        <property name="concurrent" value="false"/>
    </bean>

    <bean id="autoCancelProductTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="name" value="autoCancelProductTrigger"/>
        <property name="group" value="Order_Trigger_Group"/>
        <property name="jobDetail" ref="autoCancelProductDetail"/>
        <property name="cronExpression" value="* 0/2 * * * ? 2099"/>
    </bean>

    <bean id="cancelSchedue" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="autoCancelProductTrigger"/>
            </list>
        </property>
    </bean>

</beans>

3.使用@Configuration实现Scheduler

实现方式

  • Spring3.0 通过定义@Configuration来替换xml ?所以job, jobdetail,jobtrigger,schedule等四个对象都可以通过java类实现定义,参考源码如下
@Configuration
public class AutoOrderProductConfig {

    @Bean("autoOrderPorduct")
    public AutoOrderProduct getAutoOrderProduct() {
        return new AutoOrderProduct();
    }

    @Bean("jobDetail")
    public MethodInvokingJobDetailFactoryBean getMethodInvokingJobDetailFactoryBean(AutoOrderProduct autoOrderProduct) {
        MethodInvokingJobDetailFactoryBean factoryBean = new MethodInvokingJobDetailFactoryBean();
        factoryBean.setTargetObject(autoOrderProduct);
        factoryBean.setTargetMethod("executeJob");
        factoryBean.setConcurrent(false);
        return factoryBean;
    }

    @Bean("jobTrigger")
    public CronTriggerFactoryBean cronTriggerFactoryBean() {
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setName("jobTrigger");
        cronTriggerFactoryBean.setGroup("Order_Trigger_Group");
        cronTriggerFactoryBean.setCronExpression("0/2 * * * * ?");
        cronTriggerFactoryBean.setJobDetail(SpringUtil.getBean("jobDetail"));
        return cronTriggerFactoryBean;
    }

    @Bean("myScheduler")
    public SchedulerFactoryBean getSchedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setTriggers((CronTriggerImpl)SpringUtil.getBean("jobTrigger"));
        return schedulerFactoryBean;
    }

}


4.参考测试代码

源码地址:springboot/basic at master · PNZBEIJINGL/springboot · GitHub


5.常见问题?

1.CronTriggerImpl cannot be cast to class [Lorg.quartz.Trigger

一般是由于范型转换引起的,详细查看下面文章

链接:ClassCastException: XXX are in unnamed module of loader ‘app‘异常分析

2.@Scheduled注解不起作用

  • spring的注解@Scheduled 需要写在实现方法上任务方法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定一个proxytargetclass的某个值为true),不能指向任何的参数;
  • 如果该方法需要与应用程序上下文的其他对象进行交互,通常是通过依赖注入来实现;
  • 实现类上要有组件的注解@Component。

3.@Scheduled配置cron报错IllegalStateException

Caused by: java.lang.IllegalStateException: Encountered invalid @Scheduled method 'doexec': Cron expression must consist of 6 fields (found 7 in "1 0 * * * ? 2022")
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.processScheduled(ScheduledAnnotationBeanPostProcessor.java:462)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.postProcessAfterInitialization(ScheduledAnnotationBeanPostProcessor.java:332)

从报错信息看@Scheduled初始化的时候表达式1 0 * * * ? 2022不正确, 原因是@Scheduled中cron配置只支持6位, 不支持第7位年配置, 所以不能限制某年调度。如果想暂时不适用调度可以配置“-”

? ?

? ?上一篇:SpringBoot 06 集成Nacos配置中心以及常见问题

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-27 10:57:09  更:2022-02-27 10:58:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:33:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码