1、本篇博客的背景和目的
目前我本人正在学习SpringFramework的知识,这也是这个专栏的主题。我前面的几篇博文中,简单的认识了一下SpringFramework,记录了SpringFramework的环境搭建,记录了SpringIOC如何加载配置文件,记录了SpringIOC三种Bean对象的实例化方法。还记录了SpringIOC手动装配(注入)的方法之一:set方法注入。还有另外三个不太常用的SpringIOC手动注入的方法。其实目前大部分都使用的是自动注入的方法,手动注入使用的不多。就算是使用手动注入的方法,使用的主流也是:set方法注入。自动注入的方法主要是使用两个注解,@Autowired注解或者是@Resource注解。两个注解我都记录到了。还记录了如何使用SpringIOC扫描器,SpringIOC中Bean对象的作用域和生命周期。本篇博客记录一下SpringTask的概念和简单使用。
2、我的上一篇博文
3、定时任务的概念和实现工具
定时任务比较容易理解,简单的说就是定时发送邮件,发送短信等。比如中国联通在每月的10号给你发送上个月的账单信息。
下面先粘贴两张图:
在我们实际工作中,开发定时任务还是一个比较常见的需求, 在JAVA中,开发定时任务主要有三种解决方案:
可以使用JDK自带的Timer,可以使用第三方的组件 Quartz,可以使用Spring Task
Timer是JDK自带的,比较简单,也不复杂,但是太简单了,复杂一点的定时规则无法满足,很少用;
Quartz功能很强大,但是太强大了,比较重;
Spring Task就用的比较多了,功能适中,也不算很重,是Spring家族的,兼容性好;
我们使用SpringTask开发定时任务,那就需要配置;配置的话就有两种配置方式:使用XML配置文件配置,或者使用注解配置;
4、使用XML配置文件实现定时任务——讲解思路
首先需要我们引入依赖,主要引入下面图片中的依赖:
我们先在XML文件里面配置好扫描器和扫描范围,前面我详细记录过,如下图所示:
后面所有的类都要放在扫描范围之内的。
然后我们就要写一个定时任务的类,就像是一个Service类一样,把我们想要定时处理的业务逻辑写在这个类的方法里面;这个类也要交给SpringIOC容器管理;定时任务类代码如下所示:
但是这里还要多说一下,我们既然要使用XML的配置方式,那么还需要对XML文件的文件头做一下修改,加上定时任务需要的文件头;如下图所示:
然后对于我们上面已经建好的定时任务类,还要在XML文件中写一些标签配置一下定时任务,如下图所示:
最后,我们在Main方法中进行必要的测试:
5、使用XML配置文件实现定时任务——我的实现代码
先看一下我的代码的结构,如下图所示:
主要的任务类是TaskJob和TaskJob02。TaskJob类是为了实现XML配置文件实现定时任务而写的,TaskJob02是为了使用注解方式实现定时任务而写的。下面先主要使用TaskJob类。
首先是我的POM文件,代码如下(主要就是Spring的核心依赖):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dcy</groupId>
<artifactId>spring_task1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!-- Spring的核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
</dependencies>
</project>
然后是我们的定时任务类,里面有定时任务的方法,也就是实现定时任务的业务处理逻辑,代码如下所示:
package com.dcy.job;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component //这个注解的意思就是 将我们的这个类交给我们的IOC容器进行实例化
public class TaskJob {
public void job1(){
System.out.println("任务1"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
public void job2(){
System.out.println("任务2"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
在定时任务类上面使用了@Component注解,交给了SpringIOC容器管理。类里面有两个方法,就是处理定时任务的业务逻辑的方法。
其次,还需要最重要的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:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<!--
上面的文件头,包含了定时任务Task命名空间,扫描器和开启注解注入需要的命名空间,
-->
<!-- 开启自动化装备(注入),也就是注解注入 @Autowired或者@Resource-->
<!-- 好处就是我们不需要在手动写 property标签,不需要使用set方法或者是构造器方法
去手动写类里面的参数关系
-->
<context:annotation-config/>
<!-- 开启SpringIOC的自动扫描,设置扫描包的范围 一般都是根目录范围下的所有
这个时候我们就可以使用 @Controller,@Service注解了
此时还没有在Main方法的类上面使用 @SpringBootApplication注解
-->
<context:component-scan base-package="com.dcy"></context:component-scan>
<!-- 下面我们定义 定时任务的规则-->
<task:scheduled-tasks>
<!-- 这个是每两秒执行一次-->
<task:scheduled ref="taskJob" method="job1" cron="0/2 * * * * ?"/>
<!-- 这个是每5秒执行一次-->
<task:scheduled ref="taskJob" method="job2" cron="0/5 * * * * ?"/>
</task:scheduled-tasks>
</beans>
首先,我们相比于前面的几篇博客中的代码,加上了与定时任务有关的文件头内容,也就是含有task的地址链接。然后先开启了注解注入。下面又配置了扫描器和它的范围。
最后,最重要的是在XML配置文件中配置定时任务的规则:什么是定时任务的规则呢?为什么要配置呢?我们这样想,定时任务简单的理解就是按照一定的规律定期的做某一件事情。某一件事情就是我们在定时任务类方法中的业务逻辑代码。一定的规律定期去做怎么表达呢?SpringTask是通过在XML中进行配置来实现的。
首先需要一个<task:scheduled-tasks>标签,所有任务类的规则配置都放在这个标签里面。每一个规则都对应着一个<task:scheduled>标签。其中的ref属性值是XML文件中某个任务类对应bean标签的id属性值,我们这里使用的是注解的方式,所以id属性值默认就是类名首字母小写后的字符串。method属性值表示这个规律对应任务类中的业务逻辑处理的方法名。cron属性值就表示这个任务定时多久执行一次或者在那些特定的时间执行。cron属性值的赋予是有语法的,就像是正则表达式一样,叫做Cron表达式。这个表达式的书写语法我在后面会记录到。
我上面XML配置代码中的规则就是注释里面描述的那样的。
终于,我们进行最后的在Main方法中测试,代码如下所示:
package com.dcy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext factory=new ClassPathXmlApplicationContext("spring.xml");
}
}
执行结果如下所示:
6、使用注解的方式实现定时任务——我的代码实现
POM文件跟上面是一样的,这里我就不粘贴了。
然后是任务类,也就是TaskJob02类,代码如下所示:
package com.dcy.job;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class TaskJob02 {
@Scheduled(cron = "0/2 * * * * ?")
public void job1(){
System.out.println("任务1"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
@Scheduled(cron = "0/5 * * * * ?")
public void job2(){
System.out.println("任务2"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
还是使用@Component注解,将人物类交给SpringIOC容器管理。然后在每一个执行任务逻辑的方法上面都加上了@Scheduled注解,这个注解其实就表示了XML配置方法里面的<task:scheduled-tasks>标签和<task:scheduled>标签。@Scheduled标签里面还有一个cron属性,这个属性的功能完全相当于是<task:scheduled>标签的cron属性。
还需要有XML配置文件的辅助,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:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<!--
上面的文件头,包含了定时任务Task命名空间,扫描器和开启注解注入需要的命名空间,
-->
<!-- 开启自动化装备(注入),也就是注解注入 @Autowired或者@Resource-->
<!-- 好处就是我们不需要在手动写 property标签,不需要使用set方法或者是构造器方法
去手动写类里面的参数关系
-->
<context:annotation-config/>
<!-- 开启SpringIOC的自动扫描,设置扫描包的范围 一般都是根目录范围下的所有
这个时候我们就可以使用 @Controller,@Service注解了
此时还没有在Main方法的类上面使用 @SpringBootApplication注解
-->
<context:component-scan base-package="com.dcy"></context:component-scan>
<!-- 配置定时任务的驱动,开启这个配置,Spring才能够识别@Scheduled注解 -->
<task:annotation-driven></task:annotation-driven>
</beans>
文件头需要加上与task有关的链接;需要开启自动注解注入;需要配置扫描器的范围。以上都是常规的。
重要的一点:我们要告诉SpringIOC,我们使用了@Scheduled这个注解,使用注解的方式配置了定时任务的规则,让Spring可以识别@Scheduled注解。起告诉作用的就是 <task:annotation-driven></task:annotation-driven>标签。
最后可以进行Main方法测试,这里我就不测试了,还是加载读取配置文件就可以了。
7、Cron表达式的规则
定时任务有一个关键, 就是 cron(定时任务)属性的值, 那是一个表达式,写法是什么呢?
这个表达式被称为 Cron表达式:
这个表达式由至少6个(甚至是7个)由空格分隔的时间元素组成,从左到右,这些元素的定义如下:
1、秒(0-59) 2、分钟(0-59)3、小时(0-23)4、天(1-31)5、月份(1-12)
6、星期中的日期(1-7)7、年份(1970-2099)
如果有多个秒或者说是有多个小时,那么这一位可以使用逗号间隔;
下面我们看一点例子就知道了:
0 0 10,14,16 * * ? 就表示每天的10点,14点,16点
0 0,15,30,45 * 1-10 * ? 就表示 每个月前10天每隔15分钟
30 0 0 1 1 ? 2012 就表示在2012年1月1日 午夜过 30 秒的时候
其实啊,完全掌握Cron表达式的表示方法是比较难得,或者说如果你不是经常使用的话,完全熟练掌握是不现实的。
有很多的在线Cron表达式生成器,我们可以使用别人开发的在线Cron表达式生成器,快速的写出一个符合自己需求的Cron表达式,我这里找了一个链接,如下所示:
在线Cron表达式生成器 (qqe2.com)https://cron.qqe2.com/