Java传统定时任务实现

项目中使用定时任务处理业务是很常见的需求,现整理了一下Java传统定时任务的几种实现

一.分类

从实现的技术上来分类,目前主要有三种技术(或者说有三种产品)

  • Java自带的java.util.Timer类

    这个类允许你调度一个java.util.TimerTask任务。
    使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。
    一般用的较少,这篇文章将不做详细介绍。
    
  • Quartz

    这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行
    配置起来稍显复杂,稍后会详细介绍。
    
  • Spring Task

    Spring3.0以后自带的task
    可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多,稍后会介绍。
    

从作业类的继承方式,可以分为两类

  • 作业类需要继承特定的作业类基类

    Quartz中需要继承自org.springframework.scheduling.quartz.QuartzJobBean
    java.util.Timer中需要继承自java.util.TimerTask
    
  • 作业类是普通的java类,不需要继承任何基类

    个人推荐使用这种方式,因为这样所有的类都是普通类,不需要区别对待,保证程序的扩展性
    

按照作业触发时机,可以分为两类

  • 每隔指定时间则触发一次

    在Quartz中对应的触发器为:org.springframework.scheduling.quartz.SimpleTriggerBean
    
  • 每到指定时间则触发一次

    在Quartz中对应的调度器为:org.springframework.scheduling.quartz.CronTriggerBean
    

注意⚠️:并非每种任务都可以使用这两种触发器,如:Java.util.TimerTask任务就只能使用第一种,Quartz和Spring Task都可以支持这两种触发条件。

二.使用

现详细介绍一下Quartz和Spring Task如何使用

使用Quartz

  • Quartz是OpenSymphony开源组织在Job scheduling领域的开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表
  • Quartz是一个任务日程管理系统,一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统
  • Quartz用一个小Java库发布文件(.jar文件),这个库文件包含了所有Quartz核心功能。这些功能的主要接口(API)是Scheduler接口。它提供了简单的操作,例如:将任务纳入日程或者从日程中取消,开始/停止/暂停日程进度

Quartz中的核心对象

Scheduler   -- 核心调度器
Job         -- 任务
JobDetail   -- 任务描述
Trigger     -- 触发器
  • scheduler是一个计划调度器容器,容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就班自动去执行。
  • JobDetail是一个可执行的工作,它本身可能是有状态的。
  • Trigger代表一个调度参数的配置,什么时候去调。
  • 当JobDetail和Trigger在scheduler容器上注册后,形成了装配好的作业(JobDetail和Trigger所组成的一对儿),就可以伴随容器启动而调度执行了。
  • scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
对象之间的关系

对象之间的关系

Java中使用Quartz示例

1.项目中引入maven依赖

  <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
  <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
  </dependency>

2.编写作业类
Java中可以使用两种实现方式

  • 作业类继承自特定的基类:org.springframework.scheduling.quartz.QuartzJobBean(不推荐,就不写实现了)

  • 作业类不继承自特定的基类
    Spring能够支持这种方式,归功于两个类:

     org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean
    
     org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
    

    这两个类分别对应spring支持的两种实现任务调度的方式,即前文提到到java自带的timer task方式和Quartz方式。
    这里我只写MethodInvokingJobDetailFactoryBean的用法,使用该类的好处是,我们的任务类不再需要继承自任何类,而是普通的pojo,作业类代码如下:

    package com.chainfin.ssmdemo.tasks;
    
    public class QuartzJob {
        public void task1(){
          System.out.println("Hello Quartz");
        }
    }
    

3.配置作业类

<bean id="myJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject">
        <bean class="com.chainfin.ssmdemo.tasks.QuartzJob" />
    </property>
    <property name="targetMethod" value="task1" />
    <property name="concurrent" value="false" /><!-- 作业不并发调度 -->
</bean>

4.配置触发器

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="myJob" />
    <property name="cronExpression" value="*/10 * * * * ?" />
</bean>

5.配置调度工厂

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger" />
        </list>
    </property>
</bean>

运行效果如下:


Quartz定时任务执行结果.png

使用Spring Task

Spring Task是Spring3.0以后自主开发的定时任务工具,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种

第一种配置文件方式

1.编写任务类

  package com.chainfin.ssmdemo.tasks;

  import org.springframework.stereotype.Component;

  @Component
  public class SpringTaskJob {
      public void task1(){
          System.out.println("Hello Spring Task1 ......");
      }
  }

2.在spring配置文件中设置具体的任务

  <task:scheduled-tasks>
      <task:scheduled ref="springTaskJob" method="task1" cron="*/10 * * * * ?"/>
  </task:scheduled-tasks>

注意⚠️:需要在配置文件头部增加task的命名空间及描述,如果你的开发工具是IDEA,会自动提示你引入对应的命名空间及描述,引入即可
运行效果:


Spring Task配置文件定时任务.png
第二种:使用注解@Scheduled形式

也许我们不想每写一个任务类还要在xml文件中配置下,我们可以使用注解@Scheduled,我们看看源文件中该注解的定义:
Java代码 :

@Target({java.lang.annotation.ElementType.METHOD,     java.lang.annotation.ElementType.ANNOTATION_TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface Scheduled  {  
   public abstract String cron();    
   public abstract long fixedDelay(); 
   public abstract long fixedRate();  
}  

可以看出该注解有三个方法或者叫参数,分别表示的意思是:
1.cron:指定cron表达式
2.fixedDelay:官方文档解释:An interval-based trigger where the interval is measured from the completion time of the previous task. The time unit value is measured in milliseconds.即表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。
3.fixedRate:官方文档解释:An interval-based trigger where the interval is measured from the start time of the previous task. The time unit value is measured in milliseconds.即从上一个任务开始到下一个任务开始的间隔,单位是毫秒。
1.编写任务类

package com.chainfin.ssmdemo.tasks;

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

@Component
public class SpringTaskJob {
    public void task1() {
        System.out.println("Hello Spring Task1 ......");
    }

    @Scheduled(cron = "*/10 * * * * ?")
    public void task2() {
        System.out.println("Hello Spring Task2 ......");
    }
}

2.在Spring配置文件中打开注解驱动,使@Scheduled注解生效

<!--开启这个配置,spring才能识别@Scheduled注解-->
<task:annotation-driven />

运行效果:


Spring Task注解配置定时任务.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343