spring定时任务详解spring schedule和spring-quartz-程序员宅基地

技术标签: spring  java  mybatis  

从实现的技术上来分类,java定时任务目前主要有三种:

  1. Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行;而且作业类需要集成java.util.TimerTask,一般用的较少。
  2. Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行;使用起来需要继承org.springframework.scheduling.quartz.QuartzJobBean,配置稍显复杂,所以,一般会使用spring集成quartz,稍后会详细介绍;
  3. Spring3.0以后自带的task,即:spring schedule,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。

综上,spring中使用定时任务有两种方式:spring schedule和spring-quartz,接下来我们重点介绍这两种。使用前都需要引入spring的包。

<!-- spring -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-core</artifactId>
	<version>${org.springframework.version}</version>
	<type>jar</type>
	<scope>compile</scope>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-beans</artifactId>
	<version>${org.springframework.version}</version>
	<type>jar</type>
	<scope>compile</scope>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>${org.springframework.version}</version>
	<type>jar</type>
	<scope>compile</scope>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
	<version>${org.springframework.version}</version>
</dependency>

spring schedule

1、xml配置的方式:

1)application.xml:

首先在application.xml中引入task的命名空间,以及通过task标签定义任务。

<?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:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">

    <task:scheduler id="myScheduler"/>
    <task:scheduled-tasks scheduler="myScheduler">
        <task:scheduled ref="doSomethingTask" method="doSomething" cron="0 * * * * *"/>
    </task:scheduled-tasks>
</beans>

2)任务类:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class DoSomethingTask {

    public void doSomething() {
        System.out.println("do something");
    }
}

2、@schedule 注解方式:

1)application.xml

同样在application.xml中引入task的命名空间,以及启用注解驱动的定时任务。

<?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:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">

    <task:annotation-driven/> 
</beans>

2)任务类:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class DoSomethingTask {
    @Scheduled(cron="0 * * * * *")
    public void doSomething() {
        System.out.println("do something");
    }
}

3、Cron表达式:

由6~7项组成,中间用空格分开。从左到右依次是:秒、分、时、日、月、周几、年(可省略)。值可以是数字,也可以是以下符号:
*:所有值都匹配
?:无所谓,不关心,通常放在“周几”里
,:或者
/:增量值
-:区间

例如:

0 * * * * *:每分钟(当秒为0的时候)
0 0 * * * *:每小时(当秒和分都为0的时候)
*/10 * * * * *:每10秒
0 5/15 * * * *:每小时的5分、20分、35分、50分
0 0 9,13 * * *:每天的9点和13点

4、@Scheduled注解的另外两个属性:fixedRate和fixedDelay

 1)fixedDelay设置的是:上一个任务结束后多久执行下一个任务;

 2)fixedRate设置的是:上一个任务的开始到下一个任务开始时间的间隔;

注:如果是强调任务间隔的定时任务,建议使用fixedRate和fixedDelay,如果是强调任务在某时某分某刻执行的定时任务,建议使用cron表达式。

5、并发执行

1)spring schedule的定时任务默认是单线程的

处理方式是等待上一个任务执行完成后,再去执行下一个任务。(无论是cron还是fixedDelay、fixedRate都遵循这个原则)。下面举一些例子:

示例1:通过cron定时执行:任务运行时间6s、每5s运行一次任务

//使用注解方式创建定时任务
<task:annotation-driven/>

@Component
public class testTask {
    private Logger logger = LoggerFactory.getLogger(testTask.class);
    @Scheduled(cron = "0/5 * * * * ?")
    public void doTask() {
        logger.info(Thread.currentThread().getName()+"===task run");
        Thread.sleep(6*1_000);
        logger.info(Thread.currentThread().getName()+"===task end");
    }
}

//日志如下
2018-06-11 16:03:00.006 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:03:06.013 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:03:10.115 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:03:17.267 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:03:20.055 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:03:26.164 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end

根据日志可以看出,spring schedule默认是单线程处理的,下一个任务会等上一个运行完再执行。

示例2:换成fixedDelay

@Scheduled(fixedDelay = 5*1_000)
public void doTask() throws InterruptedException {
    logger.info(Thread.currentThread().getName()+"===task run");
    Thread.sleep(6*1_000);
    logger.info(Thread.currentThread().getName()+"===task end");
}
//日志如下:
2018-06-11 16:31:08.122 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:31:14.139 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:31:19.149 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:31:25.261 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:31:30.269 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:31:36.385 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end

从日志可以看出,任务结束时间再经过5s开始再次运行。

示例3:fixedRate

@Scheduled(fixedRate = 5*1_000)
public void doTask() throws InterruptedException {
        logger.info(Thread.currentThread().getName()+"===task run");
        Thread.sleep(6*1_000);
        logger.info(Thread.currentThread().getName()+"===task end");
}
//日志
2018-06-11 16:54:36.118 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:54:42.580 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:54:42.607 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:54:48.632 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 16:54:48.639 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 16:54:55.188 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end

从日志可以看出,上一个任务结束后,下一个任务立刻开始执行了,因为:fixedRate设置的上一个任务的开始时间到下一个任务开始时间的间隔。

示例4:fixedRate

上面例子,运行时间从6s改成2s,日志如下:

2018-06-11 17:08:43.086 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 17:08:45.093 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 17:08:48.025 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 17:08:50.083 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end
2018-06-11 17:08:53.239 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task run
2018-06-11 17:08:55.245 [pool-12-thread-1] INFO  service.task.testTask -pool-12-thread-1===task end

结果和我们推断的一致,两个任务的开始时间间隔是5s。

2)配置并行处理

上面的例子是同一个task,如果前一个还没跑完后面一个就不会触发,这没有太大问题。但是,假设系统中有多个task,默认spring schedule是单线程的,就会造成不同的task也不能同时运行,就不太合理了。解决方法:

方法一:配置多个线程,但这样会导致同一个task前一个还没跑完后面又被触发的问题。

<task:scheduler id="scheduler" pool-size="2" />

方法二:让任务分别运行在不同的scheduler里

<task:scheduler id="myScheduler1"/>
<task:scheduler id="myScheduler2"/>
<task:scheduled-tasks scheduler="myScheduler1">
    <task:scheduled ref="doSomethingTask" method="doSomething" cron="${0 * * * * *}"/>
</task:scheduled-tasks>
<task:scheduled-tasks scheduler="myScheduler2">
    <task:scheduled ref="doOtherThingTask" method="doOtherThing" cron="${0 * * * * *}"/>
</task:scheduled-tasks>

spring-quartz

maven中需要引入:quartz.jar、spring-context-support.jar。

示例:

1)定义任务类:(spring集成的quartz不需要集成任何类)

@Service
public class QuartzTest {

    public void test(){
        System.out.println("It's time to run :" + new Date().toString());
        //TODO 执行任务逻辑
        //........
    }
}

2)spring-quartz.xml配置:

a)SimpleTrigger方式:

<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<ref local="quartzTestTrigger" />
		</list>
	</property>
</bean>
<bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
	<property name="jobDetail" ref="quartzTestJob"/>
	<!-- 20秒后运行 -->
	<property name="startDelay" value="20000" />
	<!-- 每隔三十秒重复 -->
	<property name="repeatInterval" value="30000" />
</bean>

<bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	<property name="targetObject" ref="quartzTest"></property>
	<property name="targetMethod" value="autoRun"></property>
	<property name="concurrent" value="false"></property><!--不并发运行-->
</bean>

b)CronTrigger方式:

<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<ref local="quartzTestTrigger" />
		</list>
	</property>
	<property name="startupDelay" value="500"/>
</bean>
<bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
	<property name="jobDetail" ref="quartzTestJob"/>
	<property name="cronExpression">
		<value>0 */1 * * * ?</value>
	</property>
</bean>

<bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	<property name="targetObject" ref="quartzTest"></property>
	<property name="targetMethod" value="autoRun"></property>
	<property name="concurrent" value="false"></property><!--不并发运行-->
</bean>

最后,在spring主配置文件application.xml中把上面的application-quartz.xml 包含进去即可。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/liuxiao723846/article/details/90546619

智能推荐

干货!5大移动端表单设计原则及案例赏析_手机端表格怎么写逻辑-程序员宅基地

文章浏览阅读1.5w次,点赞2次,收藏10次。当我们在享受手机App为生活带来的巨大便利时,无形中已经经历了多种多样的移动表单设计形式。而表单设计又是移动应用设计中与用户产生最多交互的步骤,包括用户注册、订阅服务、用户反馈、问卷表单、买卖交易等等。一个优秀的表单设计更有助于提升用户体验,提高转化率,达到更好的营销效果。每一个表单设计的页面都有一个特定的目的,或是吸引注册,或是达成交易。考虑不周甚至是错误的设计有可能会导致用户的流失或交易失败。..._手机端表格怎么写逻辑

计算机按键音乐葫芦娃,Arduino学习笔记—超简单制作音乐(播放葫芦娃)-程序员宅基地

文章浏览阅读1.1k次。一曲葫芦娃 带你回归美好童年本文是个人学习心得,供新人参考,老鸟可瞬间飘过。本文很简单,需要用到的材料:adruino uno一块(其他也可),面保线若干条,蜂鸣器或小喇叭一个(小喇叭更好蜂鸣器要接电阻不然声音有点刺耳)连接方法如图:首先讲下简单的乐理知识,知道音乐是怎么演奏出来的自然就可以通过代码来进行编排了。1.演奏单音符一首乐曲有若干音符组成,一个音符对应一个频率。我们知道到相对应的频率..._.葫撸娃.net

爱贝支付 - 服务端 - nodejs实现_export const generatesign = (signstr) => { let sig-程序员宅基地

文章浏览阅读591次。爱贝支付nodejs实现,完整的代码,复制即可执行总结几个小坑:1. 使用私钥进行签名的问题,爱贝支付的签名规则是采用RSA MD5数字签名算法,私钥签名、公钥验签 所以本案例中用的是 nodejs 的 crypto 模块// 签名crypto.createSign('md5WithRSAEncryption');//验签crypto.createVerify('..._export const generatesign = (signstr) => { let sign = crypto.createsign('md5

VS2017使用scanf_s函数报错: (ucrtbased.dll)写入位置 0x00F6B000 时发生访问冲突。_vs2017写入位置时发生访问冲突-程序员宅基地

文章浏览阅读1.5w次,点赞46次,收藏59次。#include <stdio.h>#include <malloc.h>int main(){ char *str= (char *)malloc(20*sizeof(char)); scanf_s("%s", str); printf("%s\n",str);} 在使用VS2017时,应编译器要求需使用更加安全的..._vs2017写入位置时发生访问冲突

2048游戏的实现用C语言_2048游戏的实现用c语言studying one-程序员宅基地

文章浏览阅读118次。#include<stdlib.h>#include<stdio.h>#include<time.h>#define ROW 4#define LINE 4//这个数组为 全局数组--全局数组可以被该文件内任意函数调用//调用的前提--出现在任何函数之前int array_2048[ROW][LINE] = { 0 };//现在设定一个函数,功能是设置某个位置的随机值void position()//随机产生4或2{ int i..._2048游戏的实现用c语言studying one

毕业设计springboot宿舍管理系统-程序员宅基地

文章浏览阅读479次,点赞6次,收藏8次。1.1 研究背景近些年,随着中国经济发展,人民的生活质量逐渐提高,对网络的依赖性越来越高,通过网络处理的事务越来越多。随着宿舍管理的常态化,如果依然采用传统的管理方式,将会为工作人员带来庞大的工作量,这将是一个巨大考验,需要投入大量人力开展对宿舍管理等相关工作进行管理,单一且反复的操作容易出错且不易被察觉,工作人员对此风险并不能完全归避。利用现代信息技术,设计开发一款宿舍管理系统,能够极大的节省人力物力、提高工作效率、降低工作成本。1.2研究目的及意义。

随便推点

java encodeuricomponent 编码_encodeURIComponent编码与解码-程序员宅基地

文章浏览阅读1.3w次。问题:JavaScript用encodeURIComponentt编码后无法再后台解码的问题。目前写法:window.self.location="list.jsp?searchtext="+encodeURIComponent(seartext);java处理的代码为:searchtext=java.net.URLDecoder.decode(searchtext,"UTF-8");咋一看觉的没..._java encodeuricomponent

HBase与Zookeeper的关系_hbase和zookeeper的关系-程序员宅基地

文章浏览阅读2.7k次,点赞3次,收藏9次。HBase与Zookeeper的关系一、HBase与Zookeeper的关系ZookeeperClientMasterRegionServer一、HBase与Zookeeper的关系Client客户端、Master、Region都会通过心跳机制(RPC通信)与zookeeper保持联系。当在Hbase中插入或读取数据时流程如下:在Client中写一个Java类运行,客户端只需要连接zoo..._hbase和zookeeper的关系

点击列表项跳转_如何在Windows 10中增加跳转列表项的数量-程序员宅基地

文章浏览阅读520次。点击列表项跳转In previous versions of Windows, you could change the number of recent items shown in jump lists with a simple option in taskbar properties. For whatever reason, Microsoft removed thisability ..._要显示在跳转列表中最近使用的项目数

hibernate mysql驱动包_java – 错误:org.hibernate.util.JDBCExceptionReporter – 无法加载JDBC驱动程序类’com.mysql.jd...-程序员宅基地

文章浏览阅读1.2k次。我正在尝试使用Spring和Hibernate以及MySQL数据库配置Java MVC webapp,但是当我运行服务器时出现此错误,我不知道是什么问题.WARN : org.hibernate.util.JDBCExceptionReporter - sql Error: 0,sqlState: nullERROR: org.hibernate.util.JDBCExceptionReporte..._2023-12-14 21:21:01,540 [org.hibernate.util.jdbcexceptionreporter]-[error] o

经不住逝水流年-程序员宅基地

文章浏览阅读69次。活着,为了什么?陈老师这样问我们。许久,我都没找到答案。整天沉醉与周公与网络的世界。一天又一天,早已忘却时间与烦恼。你说,举杯消愁。你说,明天再来。可我,明明习惯了自己的世界,为何心中总有些不安与惶恐。是体弱多病的爷爷奶奶,还是年少童真的小妹,亦或是整日奔劳在外的父母。那份期待,那份盼望,那份心安与放下。。。路,是自己选的,如何...

BUUCTF cmcc_simplerop_mo77.tup/501-程序员宅基地

文章浏览阅读871次。这道题打开ida又是那么一大堆一大堆的函数,也没有外部引用的段,所以就是静态链接把好多函数都链接进来了所以就和 BUU上另一道 inndy_rop 一样,直接用ROPgadget 去找rop链 from struct import pack # Padding goes here p = '' p += pack('<I', 0x0806e82a) # pop edx ..._mo77.tup/501

推荐文章

热门文章

相关标签