spring 5.x 系列第22篇 —— spring 定时任务 (代码配置方式)

一、项目说明

1.1 项目结构

关于任务的调度配置定义在 ServletConfig 中,为方便观察定时执行的情况,项目以 web 的方式构建。

https://github.com/heibaiying

1.2 基本依赖

导入基本依赖:

<properties>
    <spring-base-version>5.1.3.RELEASE</spring-base-version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring-base-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring-base-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring-base-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring-base-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring-base-version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

二、Spring Scheduling

2.1 创建定时任务

@Component
public class Task {

    /**
     * 基于间隔的触发器,其中间隔是从上一个任务的  完成时间  开始计算, 时间单位值以毫秒为单位。
     */
    @Scheduled(fixedDelay = 5000, initialDelay = 1000)
    public void methodA() {
        Thread thread = Thread.currentThread();
        System.out.println(String.format("线程名称:%s ; 线程 ID:%s ; 调用方法:%s ; 调用时间:%s",
                thread.getName(), thread.getId(), "methodA 方法执行", LocalDateTime.now()));
    }

    /**
     * 基于间隔的触发器,其中间隔是从上一个任务的  开始时间  开始测量的。
     */
    @Scheduled(fixedRate = 5000)
    @Async
    public void methodB() throws InterruptedException {
        Thread thread = Thread.currentThread();
        System.out.println(String.format("线程名称:%s ; 线程 ID:%s ; 调用方法:%s ; 调用时间:%s",
                thread.getName(), thread.getId(), "methodB 方法执行", LocalDateTime.now()));
        Thread.sleep(10 * 1000);
    }

    @Scheduled(cron = "0/10 * * * * ?")
    public void methodC() {
        Thread thread = Thread.currentThread();
        System.out.println(String.format("线程名称:%s ; 线程 ID:%s ; 调用方法:%s ; 调用时间:%s",
                thread.getName(), thread.getId(), "methodC 方法执行", LocalDateTime.now()));
    }
}

2.2 配置定时任务

@Configuration
@EnableWebMvc
@EnableScheduling  //启用 Spring 的计划任务执行功能
@EnableAsync       //启用 Spring 的异步方法执行功能
@ComponentScan(basePackages = {"com.heibaiying.task"})
public class ServletConfig implements WebMvcConfigurer, AsyncConfigurer, SchedulingConfigurer {

    private ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

    // 任务执行器线程池配置
    @Override
    public Executor getAsyncExecutor() {
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.initialize();
        return executor;
    }

    // 这个方法可以监听到异步程序发生的错误
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable ex, Method method, Object... params) {
                System.out.println(method.getName() + "发生错误:" + ex.getMessage());
            }
        };
    }

    // 如果程序结束,需要关闭线程池 不然程序无法完全退出 只能 kill 才能完全退出
    @PreDestroy
    public void destroy() {
        if (executor != null) {
            executor.shutdown();
        }
    }

    // 调度程序线程池配置
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    // 如果程序结束,需要关闭线程池
    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(50);
    }
}

关于调度程序线程池作用说明

如上 methodA 、 methodB 、methodC 三个方法,其中 methodB 是耗时方法,如果不声明调度程序线程池则 methodB 会阻塞 methodA 、methodC 方法的执行 因为调度程序是单线程的。

关于任务执行线程池作用说明

按照上面的例子,如果我们声明 methodB 是按照 fixedRate=5000 方法执行的 ,理论上不管任务耗时多久,任务都应该是每 5 秒执行一次,但是实际上任务是被加入执行队列,并不会立即被执行,因为默认执行任务是单线程的。这个时候需要开启@EnableAsync 注解并指定方法是 @Async 异步的,并且配置执行任务线程池 (如果不配置就使用默认的线程池配置)。

源码GitHub地址:https://github.com/heibaiying/spring-samples-for-all

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
org.springframework.scheduling.quartz.CronTriggerBean是Spring框架中的一个定时任务配置类,可以用来设置基于Cron表达式的定时任务。具体使用方法如下: 1. 配置依赖项 在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> ``` 其中,${spring.version}和${quartz.version}分别为Spring框架和Quartz的版本号。 2. 创建定时任务类 创建一个类,实现org.quartz.Job接口,该接口只有一个方法execute(JobExecutionContext context),用来执行定时任务。 ``` public class MyJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 定时任务执行的逻辑代码 } } ``` 3. 配置定时任务Spring配置文件中配置CronTriggerBean,同时指定定时任务类和Cron表达式。 ``` <bean id="myJob" class="com.example.MyJob" /> <bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="myJob" /> <property name="cronExpression" value="0 0/1 * * * ?" /> </bean> ``` 其中,myJob为定时任务类的Bean ID,myCronTrigger为CronTriggerBean的Bean ID,cronExpression为Cron表达式,表示每分钟执行一次任务。 4. 配置SchedulerFactoryBean 最后,在Spring配置文件中配置SchedulerFactoryBean,将CronTriggerBean添加到调度器中。 ``` <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="myCronTrigger" /> </list> </property> </bean> ``` 至此,基于Cron表达式的定时任务配置完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值