前提:在做业务平台的时候我们经常会遇到,某些跟时间打交道的需要修改状态,比如说在时间区间之前,属于未生效状态,区间之内属于有效期,区间之后,属于过期,或者需要每天 每周 每月,甚至是年为单位的做一些固定的操作。通过定时任务可以通过开启定时任务来完成这些需求。

我做合同管理模块,合同有未生效,已生效,已过期,三个状态,不可能每次用户登录的时候去判断这个状态,然后修改,这样做会在登录的逻辑里边耦合了合同业务逻辑,同时消耗了登录时间,不太可取。

下便是代码:

依赖:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xc</groupId>
<artifactId>timetask</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>timetask</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

pom.xml

主启动类开启定时任务注解

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.RestController; @SpringBootApplication
@RestController
@EnableScheduling
public class TimetaskApplication { public static void main(String[] args) {
SpringApplication.run(TimetaskApplication.class, args);
} }

SpringUtil工具类:需要ApplicationContextAware接口

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component; @Component
public class SpringUtil implements ApplicationContextAware { private Logger logger= LoggerFactory.getLogger(SpringUtil.class); private static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
logger.info("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringUtil.applicationContext+"========");
} //获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
} //通过name获取 Bean.
public static Object getBean(String name){
Class cla = null;
try {
cla=Class.forName(name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return getApplicationContext().getBean(cla);
} //通过class获取Bean.
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
} //通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
} }

SpringUtil.java

SysTaskController实现SchedulingConfigurer接口,配置定时任务以及开启定时任务

import com.xc.timetask.entity.Task;
import com.xc.timetask.service.TaskService;
import com.xc.timetask.util.SpringUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component; import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture; @Lazy(value = false)
@Component
public class SysTaskController implements SchedulingConfigurer { protected static Logger logger = LoggerFactory.getLogger(SysTaskController.class); private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); private static Map<String,ScheduledFuture<?>> scheduledFutureMap = new HashMap<>(); @Resource
private TaskService taskService; //从数据库里取得所有要执行的定时任务
private List<Task> getAllTasks() throws Exception {
List<Task> list=taskService.selectyunx();
return list;
}
static {
threadPoolTaskScheduler.initialize();
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
List<Task> tasks= null;
try {
tasks = getAllTasks();
} catch (Exception e) {
e.printStackTrace();
}
logger.info("定时任务启动,预计启动任务数量="+tasks.size()+"; time="+sdf.format(new Date())); //校验数据(这个步骤主要是为了打印日志,可以省略)
checkDataList(tasks); //通过校验的数据执行定时任务
int count = 0;
if(tasks.size()>0) {
for (Task task:tasks) {
try {
//taskRegistrar.addTriggerTask(getRunnable(task), getTrigger(task));
start(task);
count++;
} catch (Exception e) {
logger.error("定时任务启动错误:" + task.getBean_name() + ";" + task.getMethod_name() + ";" + e.getMessage());
}
}
}
logger.info("定时任务实际启动数量="+count+"; time="+sdf.format(new Date()));
}
private static Runnable getRunnable(Task task){
return new Runnable() {
@Override
public void run() {
try {
Object obj = SpringUtil.getBean(task.getBean_name());
Method method = obj.getClass().getMethod(task.getMethod_name());
method.invoke(obj);
} catch (InvocationTargetException e) {
logger.error("定时任务启动错误,反射异常:"+task.getBean_name()+";"+task.getMethod_name()+";"+ e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage());
}
}
};
} private static Trigger getTrigger(Task task){
return new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
//将Cron 0/1 * * * * ? 输入取得下一次执行的时间
CronTrigger trigger = new CronTrigger(task.getCron());
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
}; } private List<Task> checkDataList(List<Task> list) {
String errMsg="";
for(int i=0;i<list.size();i++){
if(!checkOneData(list.get(i)).equalsIgnoreCase("success")){
errMsg+=list.get(i).getName()+";";
list.remove(list.get(i));
i--;
};
}
if(!StringUtils.isBlank(errMsg)){
errMsg="未启动的任务:"+errMsg;
logger.error(errMsg);
}
return list;
} public static String checkOneData(Task task){
String result="success";
Class cal= null;
try {
cal = Class.forName(task.getBean_name()); Object obj = SpringUtil.getBean(cal);
Method method = obj.getClass().getMethod(task.getMethod_name());
String cron=task.getCron();
if(StringUtils.isBlank(cron)){
result="定时任务启动错误,无cron:"+task.getName();
logger.error(result);
}
} catch (ClassNotFoundException e) {
result="定时任务启动错误,找不到类:"+task.getBean_name()+ e.getMessage();
logger.error(result);
} catch (NoSuchMethodException e) {
result="定时任务启动错误,找不到方法,方法必须是public:"+task.getBean_name()+";"+task.getMethod_name()+";"+ e.getMessage();
logger.error(result);
} catch (Exception e) {
logger.error(e.getMessage());
}
return result;
}
/**
* 启动定时任务
* @param task
* @param
*/
public static void start(Task task){ ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(getRunnable(task),getTrigger(task));
scheduledFutureMap.put(task.getId(),scheduledFuture);
logger.info("启动定时任务" + task.getId() ); } /**
* 取消定时任务
* @param task
*/
public static void cancel(Task task){ ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(task.getId()); if(scheduledFuture != null && !scheduledFuture.isCancelled()){
scheduledFuture.cancel(Boolean.FALSE);
} scheduledFutureMap.remove(task.getId());
logger.info("取消定时任务" + task.getId() ); } /**
* 编辑
* @param task
* @param
*/
public static void reset(Task task){
logger.info("修改定时任务开始" + task.getId() );
cancel(task);
start(task);
logger.info("修改定时任务结束" + task.getId());
} }

SysTaskController.java

TaskDemo:定时任务要操作的类

import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date; @Component
public class TaskDemo {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //注入需要的service
//private ContractService contractService; public String run(){ try {
/*
使用service做一些修改的业务操作
获取所有的合同列表
List<Contract> list = contractService.getAllContract();
修改合同的状态
contractService.updateContractList(list); 下边用打印***来代替业务进行测试定时任务
*/
System.out.println("*********"); System.out.println("TaskContract is running"+sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
return "/main";
}
}

TaskDemo.java

其他的controller service dao类就省略了,后边会给出github地址,有demo可执行

演示及说明

访问/timetask/list可以看到所有的定时任务列表  可以进行启动  停止  以及常规的增删改查

特别说明 新增的时候类名必须是全路径类名,因为是通过Class.forName("com.xc.timetask········") 反射来加载要执行的类

表达式    是cron表达式  就是定时任务的执行单位  不知道的可以 戳这里 去看看

方法  是要执行的方法的名字

新增和修改页面  方法哪里填写 run 就可以 和 TaskDemo 里的那个方法对应

这里忘记加上时间区间的datepicker日历控件 来进行开始时间 结束时间填充, 直接去数据库表里修改开始 结束时间   轻点喷我!!!!!

另外demo使用了LayUI   真的是惨不忍睹  弹出层会重复 -!-  不过后台代码都是好用的

结果  因为上边图中列表  只有一个定时任务开启的

需要demo 源码的  请戳这里

SysTaskController

Spring的SchedulingConfigurer实现定时任务的更多相关文章

  1. Spring基于SchedulingConfigurer实现定时任务

    Spring 基于 SchedulingConfigurer 实现定时任务,代码如下: import org.springframework.scheduling.annotation.Schedul ...

  2. spring的Scheduled(定时任务)和多线程

    一.前言 在我们日常的开发中,经常用到数据同步的更新,这时我们采用的是spring的定时任务和java的多线程进行数据的更新,进行时实的服务调用. 二.实现思路            1.创建线程类 ...

  3. spring注解scheduled实现定时任务

    只想说,spring注解scheduled实现定时任务使用真的非常简单. 一.配置spring.xml文件 1.在beans加入xmlns:task="http://www.springfr ...

  4. Spring Boot 中实现定时任务的两种方式

    在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Qua ...

  5. Spring Boot(九):定时任务

    Spring Boot(九):定时任务 一.pom包配置 pom包里面只需要引入springboot starter包即可 <dependencies> <dependency> ...

  6. spring boot 学习(八)定时任务 @Scheduled

    SpringBoot 定时任务 @Scheduled 前言 有时候,我们有这样的需求,需要在每天的某个固定时间或者每隔一段时间让应用去执行某一个任务.一般情况下,可以使用多线程来实现这个功能:在 Sp ...

  7. 【spring boot】spring boot中使用定时任务配置

    spring boot中使用定时任务配置 =============================================================================== ...

  8. spring boot 基础篇 -- 定时任务

    在日常项目中,常常会碰到定时监控项目中某个业务的变化,下面是spring boot 集成的定时任务具体配置: @Component public class IndexWarningScheduled ...

  9. 品Spring:关于@Scheduled定时任务的思考与探索,结果尴尬了

    非Spring风格的代码与Spring的结合 现在的开发都是基于Spring的,所有的依赖都有Spring管理,这没有问题. 但是要突然写一些非Spring风格的代码时,可能会很不习惯,如果还要和Sp ...

随机推荐

  1. SQLSTATE[42000]: Syntax error or access violation: 1253 COLLATION 'utf8mb4_unicode_ci' is not valid for CHARACTER SET 'binary'

    SQLSTATE[42000]: Syntax error or access violation: 1253 COLLATION 'utf8mb4_unicode_ci' is not valid ...

  2. Vue数据更新页面没有更新问题总结

    Vue数据更新页面没有更新问题总结 1. Vue无法检测实例别创建时不存在于data中的property 原因: 由于Vue会在初始化实例时对property执行getter/setter转化,所以p ...

  3. Python3-算法-选择排序

    选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. ...

  4. stm32存储器映像和标准库中定义外设地址的方法

    结合存储器映像理解stm32标准库中定义外设地址的方法. stm32f103zet6是32位的.它所能访问的地址空间范围为2^32=4GB,把4GB分为8个block,分别为block0-block- ...

  5. Python 3.10 版本采纳了首个 PEP,中文翻译即将推出

    现在距离 Python 3.9.0 的最终版本还有 3 个月,官方公布的时间线是: 3.9.0 beta 4: Monday, 2020-06-29 3.9.0 beta 5: Monday, 202 ...

  6. 深入理解JVM(③)Java模块化系统

    前言 JDK9引入的Java模块化系统(Java Platform Module System ,JPMS)是 对Java技术的一次重要升级,除了像之前JAR包哪有充当代码的容器之外,还包括: 依赖其 ...

  7. 09 . Kubernetes之pv、pvc及使用nfs网络存储应用

    PV,PVC概述 PV的全称是: PersistentVolume (持久化卷),是对底层的共享存储的一种抽象,PV由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如Ceph.G ...

  8. 远程登录LINUX

    远程登录LINUX LINUX 大多数应用于服务器,因此我们一般都是用远程登录的方式访问系统,windows的操作系统远程访问Linux的操作系统,我们需要另外安装终端软件,如Scure CRT,PU ...

  9. 使用vs2019加.net core 对WeiApi的创建

    vs2019创建webapi 1.创建新的项目 2.选择.NET CORE的ASP .NET CORE WEB应用程序 3.定义项目名称和存放地点 4.选择API创建项目 5.删除原本的无用的类 6. ...

  10. 讲讲 Promise

    一.什么是 Promise 1.1 Promise 的前世今生 Promise 最早出现在 1988 年,由 Barbara Liskov.Liuba Shrira 首创(论文:Promises: L ...