定时任务是常用功能,比如超时检索等数据检索功能或者定时发布功能,使用spring boot 注解式代码如下:
① 在 main 中开启定时任务的注解 @EnableScheduling
package com.jiangcheng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling //开启定时任务注解
@SpringBootApplication
public class TaskApplication {
public static void main(String[] args) {
SpringApplication.run(TaskApplication.class, args);
}
}
②在 Service 中编写定时任务 @Scheduled
package com.jiangcheng.service;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class TaskService {
/**
* second(秒), minute(分), hour(时), day of month(日), month(月), day of week(周几).
* 例子:
* 【0 0/5 14,18 * * ?】 每天14点整,和18点整,每隔5分钟执行一次
* 【0 15 10 ? * 1-6】 每个月的周一至周六10:15分执行一次
* 【0 0 2 ? * 6L】每个月的最后一个周六凌晨2点执行一次
* 【0 0 2 LW * ?】每个月的最后一个工作日凌晨2点执行一次
* 【0 0 2-4 ? * 1#1】每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次;
*/
@Scheduled(cron = "0,1,2,3,4 * * * * MON-SAT")
public void runTask(){
System.out.println(new Date()+"超时锁定");
}
}
③ Maven 依赖
org.springframework.boot
spring-boot-starter-parent
使用spring注解方式优势是使用简单,劣势是不支持分布式。要实现分布式需要进行改动使多个服务访问同一资源判断其他服务是否已经执行过定时任务,如下方式改造第二步中方法:
private static String serverIp = null;
static {
//获取服务器的IP地址,便于后续追踪
try {
InetAddress address = InetAddress.getLocalHost();
serverIp = address.getHostAddress();
} catch (Exception e) {
logger.error("获取服务器IP地址有误!!");
e.printStackTrace();
}
}
/**
* second(秒), minute(分), hour(时), day of month(日), month(月), day of week(周几).
* 例子:
* 【0 0/5 14,18 * * ?】 每天14点整,和18点整,每隔5分钟执行一次
* 【0 15 10 ? * 1-6】 每个月的周一至周六10:15分执行一次
* 【0 0 2 ? * 6L】每个月的最后一个周六凌晨2点执行一次
* 【0 0 2 LW * ?】每个月的最后一个工作日凌晨2点执行一次
* 【0 0 2-4 ? * 1#1】每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次;
*/
@Scheduled(cron = "0,1,2,3,4 * * * * MON-SAT")
public void runTask(){
logger.info("job start");
String jobName = "doTask";
long startTime = new Date().getTime();
try {
if (checkTask(jobName)){
jobMapper.doTaskSchedule();
jobMapper.updateJobStatus(jobName,serverIp,"off");
logger.info(jobName+"执行完成,耗时:"+(new Date().getTime()-startTime)+"毫秒!");
System.out.println(new Date()+"超时锁定");
}
} catch (Exception e) {
e.printStackTrace();
}
}
private Boolean checkTask(String jobName) throws Exception {
int max = 10000;
int min = (int) Math.round(Math.random()*8000);
long sleepTime = Math.round(Math.random()*(max-min));
logger.info(jobName+"睡了:"+ sleepTime + "毫秒");
Thread.sleep(sleepTime);
if (jobMapper.getJobOff(jobName) == 1){
jobMapper.updateJobStatus(jobName,serverIp,"on");
return true;
}
logger.info(jobName+"已被其他服务器执行");
return false;
}
数据库新增表:
CREATE TABLE `job_manager` (
`job_name` varchar(50) NOT NULL PRIMARY KEY COMMENT '名称',
`job_desc` varchar(50) COMMENT 'job描述',
`server_ip` varchar(50) NOT NULL COMMENT '服务器ip',
`on_off` varchar(10) DEFAULT 'off' COMMENT '开关(on:正在执行,off:执行完毕)',
`update_date` datetime NOT NULL COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job管理' ROW_FORMAT=DYNAMIC;
INSERT INTO `job_manager`
VALUES
('doTask','更新doTask的job','0.0.0.0','off',now());
查询或修改任务状态上sql:
UPDATE job_manager
SET on_off=#{status},server_ip=#{serverIp},update_date=now()
WHERE job_name = #{jobName}