守时使命在咱们项目开发中也是很重要的,对于某些场景必须要用守时使命 ,如守时发送邮件啊,守时统计数据等,这篇文章首要讲讲项目中完成守时使命的几种办法。
一、根据注解
这种办法很简单,首要就是先@EnableScheduling
敞开守时使命功用,然后在相应的办法上增加@Scheduled()
中间写上相应的cron
表达式即可。示例如下:
schedule.ScheduleTask:
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@EnableScheduling //敞开守时使命
public class ScheduleTask {
@Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
public void testScheduleTask() {
System.out.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)
主张:直接在线生成Cron表达式比较便利:www.matools.com/cron/
@Scheduled
:除了支持灵敏的参数表达式cron
之外,还支持 fixedDelay
,fixedRate
,initialDelay
这些延时性的操作。
发动测验就完成了基本的守时使命功用,但是假如咱们修正了cron
表达式,需要重启整个使用才能收效,不是很便利。想要完成修正cron
表达式就收效就需要用到接口
的办法来完成守时使命。
二、根据接口
接口的办法是咱们把守时使命的信息放在数据库中,程序从数据库去拉取守时使命的信息如cron
表达式来完成实时修正收效等功用。
1. 首先在数据库中创建一张用来记载守时使命的表
CREATE TABLE `scheduled`(
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) NULL,
`cron` varchar(255) NULL,
PRIMARY KEY (`id`)
)
INSERT INTO `mydb`.`scheduled` (`id`, `name`, `cron`) VALUES (1, '守时使命1', '0/6 * * * * ?')
2. 在项目中引入mabatis-plus
和mysql
相应的依赖包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
3. 在application.yml
中进行衔接数据库相应配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8&serverTimeZone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
4. 界说查询cron
表达式的mapper
mapper.CronMapper:
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface CronMapper {
@Select("select cron from scheduled where id=#{id}")
String getCron(Long id);
}
5. 完成守时使命
import com.jk.mapper.CronMapper;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Component;
@Component
@EnableScheduling //敞开守时使命
public class ScheduleTask implements SchedulingConfigurer {
@Autowired
private CronMapper cronMapper;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//增加使命内容
() -> process(),
//设置履行的周期
triggerContext -> {
//查询cron表达式
String cron = cronMapper.getCron(1L);
if (cron.isEmpty()) {
System.out.println("cron is null");
}
return new CronTrigger(cron).nextExecutionTime(triggerContext);
});
}
private void process() {
System.out.println("根据接口的守时使命");
}
}
这种办法需要去完成SchedulingConfigurer
接口并重写configureTasks
办法,然后设置使命内容和履行周期等,发动测验就完成了根据接口的守时使命,此时咱们改动数据库里的cron
表达式也会实时收效
三、多线程守时使命
但上面的办法界说的守时使命会有个问题,就是假如我一个守时使命里边履行了复杂逻辑,导致自身履行花的时刻就现已超过了守时使命间隔的时刻怎么办呢?这时候守时使命的履行就会呈现必定的问题,具体如下,我用线程睡觉的办法模拟处理复杂逻辑
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@EnableScheduling //敞开守时使命
public class ScheduleTask {
@Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
public void testScheduleTask1() throws InterruptedException {
System.out.println("履行守时使命1 " + LocalDateTime.now());
Thread.sleep(10 * 1000);
}
@Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
public void testScheduleTask2() {
System.out.println("履行守时使命2 " + LocalDateTime.now());
}
}
能够看到两个使命的履行时刻都被影响了,和咱们设置的5秒不对应。此时就能够使用多线程守时使命,对多线程的使用不了解的能够看我的另一篇文章 SpringBoot 中异步使命完成及自界说线程池履行异步使命
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
@EnableScheduling //敞开守时使命
@EnableAsync //敞开多线程
public class ScheduleTask {
@Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
@Async
public void testScheduleTask1() throws InterruptedException {
System.out.println("履行守时使命1 " + LocalDateTime.now());
Thread.sleep(10 * 1000);
}
@Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
@Async
public void testScheduleTask2() {
System.out.println("履行守时使命2 " + LocalDateTime.now());
}
}
这样多线程的守时使命就完成了,每个守时使命之间不会相互影响,守时使命履行时刻太长也不会影响。
这就是守时使命完成的几种办法,对我们有协助的话多多
点赞
、收藏
哦,感谢!