springtask定时任务 3种方式【注解、xml、动态接口】

前言

创建定时任务方式以及区别:

  1. 基于注解 @Scheduled -> 修改执行周期后需要重启应用才能生效
  2. 基于xml的方式 【@Configuration + @ImportResource + xml】 需要重启应用才能生效
  3. 基于接口 SchedulingConfigurer -> 从数据库中读取指定时间来动态执行定时任务

项目结构:
在这里插入图片描述


一、基于注解 @Scheduled


/**
 *  <p>静态定时任务(基于注解)</p>
 *
 * @description : @Scheduled 除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。
 *                 缺点: 当我们调整了执行周期的时候,需要重启应用才能生效。 -> 为了达到实时生效的效果,可以使用接口来完成定时任务。
 * @author suqinyi
 * @Date 2022/1/10
 * 注解方式: @EnableScheduling + @Scheduled(cron = "0/10 * * * * ?")
 */
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class AppTask03_annotation {
    
    /**
     * Cron表达式参数分别表示:
     *           秒(0~59) 例如0/5表示每5秒
     *           分(0~59)
     *           时(0~23)
     *           月的某天(0~31) 需计算
     *           月(0~11)
     *           周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)
     */
    
    @Scheduled(cron = "0/10 * * * * ?")
    public void AppTask01() throws Exception {
        System.out.println("注解方式的角度-10秒");
    }
    
}

二、基于xml方式

xml的方式: @Configuration + @ImportResource + xml

01、配置类加载xml

/**
 * 加载调度的配置文件
 */
@Configuration
//@ImportResource(locations={"classpath:appTask01.xml","appTask02.xml"})//加载调度xml
@ImportResource(locations={"classpath:appTask01.xml","appTask02.xml"})//加载调度xml
public class SpringTaskConfig {
}

02、xml调度文件

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
       http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
       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-4.1.xsd">

    <!--声明一个具有一个线程的池,如果定义多个,每个对象将获取同样的运行机会-->
    <task:scheduler id="sch" pool-size="10"/>

    <!--任务的调度类-->
    <bean id="testJob" class="sqy.springtaskdemo.task.AppTask01_xml"/>

    <!--引用线程池-->
    <task:scheduled-tasks scheduler="sch">
        <!--调度任务 5秒-->
        <task:scheduled ref="testJob" method="task01_xml" cron="0/5 * * * * ?"/>
    </task:scheduled-tasks>

</beans>

03、任务的调度类

package sqy.springtaskdemo.task;

/**
 * @author suqinyi
 * @Date 2021/9/12
 * xml的方式:  @Configuration + @ImportResource + xml
 */
public class AppTask01_xml {

    public void task01_xml() throws Exception {
        System.out.println("01xml方式调度==>AppTask01_xml");
    }
}

三、基于接口 SchedulingConfigurer(数据库)

这里采用了mybatis去查下调度信息

数据库如图:

注明:这边只是简单的设计了id和时间-【应该还要有方法名、类路径、等】
(原因:好利用反射机制,执行方法-提高代码优雅性)
在这里插入图片描述

pom依赖

 <!--
            阿里druid连接池
            1.1.23不能使用,大量ERROR问题:
            discard long time none received connection
            原因和方案:https://zhuanlan.zhihu.com/p/368683245
        -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.22</version>
        </dependency>

        <!--mysql依赖85多了ssl-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>
        
        <!-- StringUtils工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>

动态定时任务:

package sqy.springtaskdemo.task;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import sqy.springtaskdemo.mapper.CronMapper;
import sqy.springtaskdemo.pojo.MyCronTask;


import java.util.Date;
import java.util.List;

/**
 * 动态定时任务(基于接口 SchedulingConfigurer)
 * 默认的,SchedulingConfigurer 使用的也是单线程的方式,如果需要配置多线程,则需要指定PoolSize
 *
 * @author suqinyi
 * @Date 2022/1/10
 */
@Configuration
@EnableScheduling
public class DynamicTask implements SchedulingConfigurer {

    @Autowired
    CronMapper cronMapper;


    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        //获取全部的任务-这边简单话值设计了id和时间-【应该还要有方法名、类路径、等(好利用反射机制)】
        List<MyCronTask> cronList = cronMapper.findAll();
        System.out.println("任务总数:" + cronList.size());

        /**
         * scheduledTaskRegistrar -> 目的: 循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容
         * 1.添加任务内容(Runnable)
         * 2.设置执行周期(Trigger)
         *    2.1 从数据库获取执行周期
         *    2.2 表示式合法性校验.
         *    2.3 返回执行周期(Date)
         */
        for (MyCronTask myCronTask : cronList) {
            scheduledTaskRegistrar.addTriggerTask(
                    getRunnable(myCronTask.getCronId()),
                    triggerContext -> {
                        if (StringUtils.isEmpty(cronList.get(0).getCronTime())) {
                            System.out.println("表达式不合法");
                        }
                        Date date = new CronTrigger(myCronTask.getCronTime()).nextExecutionTime(triggerContext);
                        System.out.println("返回执行周期:" + date);
                        return date;
                    }
            );
        }

    }

    private Runnable getRunnable(Integer count) {
        //这边推荐设计数据库存储方法名,根据反射来取出方法java
        // 【例如存入一个为test01的字段,java写一个test01的方法。根据反射来创建出Runnable来执行方法】
        if (count == 1) {
            return new Runnable() {
                @Override
                public void run() {
                    System.out.println("数据库id为1===>任务1");
                }
            };
        }else if (count == 2) {
            return new Runnable() {
                @Override
                public void run() {
                    System.out.println("数据库id为2===>任务2");
                }
            };
        }else {
            return new Runnable() {
                @Override
                public void run() {
                    System.out.println("默认执行");
                }
            };
        }
    }
}

四、运行项目效果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suqinyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值