依赖包pom:
<?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.canzhen.demo</groupId> <artifactId>ScheduledTask</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>scheduledTask</name> <description>定时任务</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!-- 默认就内嵌了Tomcat 容器,如需要更换容器也极其简单--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> <scope>provided</scope> </dependency> <!-- MYSQL包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Mybatis 的依赖包mybatis-spring-boot-starter,该包拥有自动装配的特点--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- 通用Mapper插件 文档地址:https://gitee.com/free/Mapper/wikis/Home --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.0.2</version> </dependency> </dependencies> <build> <plugins> <!-- 编译插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
项目结构:
1、基于注解@Scheduled
配置ScheduleDemo如下:
//基于注解@Scheduled package com.canzhen.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import java.time.LocalDateTime; //1.主要用于标记配置类,兼备Component的效果。 @Configuration //@Component // 2.开启定时任务 @EnableScheduling public class ScheduleDemo { //3.添加定时任务 @Scheduled(cron = "0/5 * * * * ?") //或直接指定时间间隔,例如:5秒 //@Scheduled(fixedRate=5000) private void configureTasks() { System.err.println("执行静态定时任务时间: " + LocalDateTime.now()); } } //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之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。 //显然,使用@Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。 // 为了达到实时生效的效果,可以使用接口来完成定时任务。
2、基于接口,可通过修改配置改变数据库表实现实时生效,无需重启应用
数据库连接配置application.properties
# 默认的 8080 我们将它改成 9090 server.port=9090 #开发库 spring.datasource.url=jdbc:mysql://localhost:3306/socks?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false spring.datasource.password=root spring.datasource.username=root
库表设计:
mapper:
package com.canzhen.demo.mapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface CronMapper { @Select("SELECT A.CRON FROM CRON A WHERE A.TASKNAME = #{taskName}") String getCron(String taskName); }
配置Trigger定时任务TriggerTask:
//基于接口SchedulingConfigurer package com.canzhen.demo.config; import com.canzhen.demo.mapper.CronMapper; 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 org.springframework.util.StringUtils; import java.time.LocalDateTime; //1.主要用于标记配置类,兼备Component的效果。 @Configuration //@Component // 2.开启定时任务 @EnableScheduling public class TriggerTask implements SchedulingConfigurer{ @Autowired private CronMapper cronMapper; @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { //数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask, // 目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。 scheduledTaskRegistrar.addTriggerTask( //1.添加任务内容(Runnable) () -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()), //2.设置执行周期(Trigger) triggerContext -> { //2.1 从数据库获取执行周期 String cron = cronMapper.getCron("testTrigger"); //2.2 合法性校验. if (StringUtils.isEmpty(cron)) { // Omitted Code .. } //2.3 返回执行周期(Date) return new CronTrigger(cron).nextExecutionTime(triggerContext); }); } }
测试:启动程序,修改库表cron字段配置,可以直接修改定时,无需重启程序。
3、基于注解设定多线程定时任务
配置MultiThreadScheduleTask:
//基于注解设定多线程定时任务 package com.canzhen.demo.config; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; //@Component注解用于对那些比较中立的类进行注释; //相对与在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释 @Component @EnableScheduling // 1.开启定时任务 @EnableAsync // 2.开启多线程 public class MultiThreadScheduleTask { @Async @Scheduled(fixedDelay = 1000) //间隔1秒 public void first() throws InterruptedException { System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName()); Thread.sleep(1000 * 10); } @Async @Scheduled(fixedDelay = 2000) public void second() { System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName()); } }
效果如下:
注:由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。