zoukankan      html  css  js  c++  java
  • Spring Scheduler定时任务 + Quartz

    原文地址: https://blog.csdn.net/revitalizing/article/details/61420556

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzx_2011/article/details/61420556

    定时任务几种实现方式

    1. Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务,没怎么用过就不说了。
    2. Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。
    3. java的线程池类ScheduledExecutorService也可以实现一些简单的定时任务,周期性任务。
    4. Quartz是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,可以方便的分布式部署、便捷的监控和管理任务,适合任务很多的情况。

    Spring Scheduler注解方式实现

    代码还是挺少的

    @Component
    public class SchedulerPractice{
        // @Scheduled(fixedDelay=60000)
        @Scheduled(cron = "0 0/1 * * * ?")
 public void execute() {
            logger.info("every one minute------");
 }
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    配置文件

    <beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:task="http://www.springframework.org/schema/task" 
                       http://www.springframework.org/schema/task  
                       http://www.springframework.org/schema/task/spring-task-3.0.xsd
                     >
     <context:annotation-config />  
        <!—spring扫描注解的配置   -->  
        <context:component-scan base-package="com.liu” />  
    <task:annotation-driven />
    • 1
    • 2
    • 3
    • 4
    • 5

    注解@Scheduled 中有三个方法,用来对执行规则的配置:

    cron:指定cron表达式,文章最后有些配置示例。

    fixedDelay:即表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。

    fixedRate:即从上一个任务开始到下一个任务开始的间隔,单位是毫秒。

    执行时间可配置化

    将cron表达式配置在java的properties文件或者环境变量中,是配置更灵活

    xml配置方式

    
    <task:scheduler id="myScheduler"/>
    
    <task:scheduled-tasks scheduler="myScheduler" pool-size="2" />
        <task:scheduled ref=“testScheduler” method="execute()” cron="${cron_expression}"/>
    </task:scheduled-tasks>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    pool-size=”2” 有多个任务可以配置以线程池执行

    注解使用方式

    @Scheduled(cron = "${cron_expression}")
    • 1

    分布式多实例运行

    scheduler与web配置在一起,在高可用的情况下,如果有多个web容器实例,scheduler会在多个实例上同时运行。

    解决办法:

    1. 使用写死服务器Host的方式执行task,存在单点风险,负载均衡手动完成。(或者一台代码中配置任务,其他不配置任务)

    2. 在task的基类加入一些逻辑,当开始运行时,将状态(运行机器的IP、时间等)写入数据库、缓存(redis)或者zk,运行结束时重置状态。其它实例看到有这样的数据,就直接返回。带来的问题是: 
      一定要保证结束运行后将状态重置,否则下一个运行周期,所有的task都会返回的。 
      因为读写状态并非原子操作,偶尔也会发生task同时运行的事。

    3. 使用zk分布式锁,比如在任务执行方法上自定义注解,在注解中配置锁在zk的路径,在该注解上自定义个拦截器,在拦截器中获取zk锁。

    Java线程池ScheduledExecutorService

    示例代码如下

    public void cronThread(){
            ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
    
                scheduledThreadPool.scheduleWithFixedDelay(new ThreadPractice(), 0, 3, TimeUnit.SECONDS);
    
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    new ThreadPractice()是一个实现了Runnable的类。 
    ScheduledExecutorService 类有两个方法

    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                      long initialDelay,
                                                      long period,
                                                      TimeUnit unit)
    
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                         long initialDelay,
                                                         long delay,
                                                         TimeUnit unit)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这两个方法和@scheduled 注解中的fixedDelay和fixedRate类似。

    Quartz

    Quartz框架是一个全功能、开源的任务调度服务,可以集成几乎任何的java应用程序—从小的单片机系统到大型的电子商务系统。可以方便的分布式部署、便捷的监控和管理任务,Quartz可以执行上千上万的任务调度。

    核心概念

    Quartz核心的概念:scheduler任务调度、Job任务、Trigger触发器、JobDetail任务细节

    • Job任务:其实Job是接口,其中只有一个execute方法, 只要实现此接口,实现execute方法即可。

    • JobDetail:任务细节,Quartz执行Job时,需要新建个Job实例,但是不能直接操作Job类,所以通过JobDetail来获取Job的名称、描述信息。

    • Trigger触发器:执行任务的规则;比如每天,每小时等。触发器有SimpleTrigger和CronTrigger,这个触发器实现了Trigger接口。对于复杂的时间表达式来说,比如每个月15日上午几点几分,使用CronTrigger,对于简单的时间来说,比如每天执行几次,使用SimpleTrigger。

    • scheduler任务调度:是最核心的概念,需要把JobDetail和Trigger注册到scheduler中,才可以执行。

    quartz单机示例

    使用的quartz的jar的版本是:2.2.1 ,低版本的核心类可能有些不同。

    job类

    public class MyJob implements Job {  
    
        @Override  
        //把要执行的操作,写在execute方法中  
        public void execute(JobExecutionContext arg0) throws JobExecutionException {  
            System.out.println(“test Quartz"+new Date());  
        }  
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试代码

    @Test
        public void startJobTest() {
    
            SchedulerFactory schedulerfactory = new StdSchedulerFactory();
            Scheduler scheduler = null;
            try {
                // 通过schedulerFactory获取一个调度器
                scheduler = schedulerfactory.getScheduler();
    
                // 创建jobDetail实例,绑定Job实现类
                // 指明job的名称,所在组的名称,以及绑定job类
                JobDetail job = JobBuilder.newJob(ImageTableMonitorJob.class).withIdentity("job1", "jgroup1").build();
    
                // 定义调度触发规则
                // 使用simpleTrigger规则
                Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup")
                        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withRepeatCount(8)).startNow().build();
                // 使用cornTrigger规则 每天10点42分
                // Trigger trigger= TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup")
                // .withSchedule(CronScheduleBuilder.cronSchedule("0 42 10 * * ? *"))
                // .startNow().build();
    
                // 把作业和触发器注册到任务调度中
                scheduler.scheduleJob(job, trigger);
    
                // 启动调度
                scheduler.start();
    
            } catch (Exception e) {
                // e.printStackTrace();
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    spring提供了对quartz的整合,可以通过 org.springframework.scheduling.quartz.SchedulerFactoryBean 注入scheduler调度器,并且对调度器做些配置,比如使用线程池,并配置线程数量等。配置示例如下。

    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
            <property name="taskExecutor" ref="taskExecutor" />
            <property name="autoStartup" value="false"/>
        </bean>
    
        <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
            <property name="corePoolSize" value="2" />
            <property name="maxPoolSize" value="512" />
        </bean>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Quartz分布式原理

    Quartz的集群部署方案在架构上是分布式的,没有负责集中管理的节点,而是利用数据库锁的方式来实现集群环境下进行并发控制。分布式部署时需要保证各个节点的系统时间一致。没弄过,就不细说了。

    Quartz数据库核心表QRTZ_LOCKS中有5条记录CALENDAR_ACCESS,JOB_ACCESS,MISFIRE_ACCESS,STATE_ACCESS,TRIGGER_ACCESS 代表5把锁,分别用于实现多个Quartz Node对Job、Trigger、Calendar访问的同步控制。

    cron表达式

    字段   允许值   允许的特殊字符
    秒    0-59    , - * /
    分    0-59    , - * /
    小时    0-23    , - * /
    日期    1-31    , - * ? / L W C
    月份    1-12 或者 JAN-DEC    , - * /
    星期    1-7 或者 SUN-SAT    , - * ? / L C #
    年(可选)    留空, 1970-2099    , - * / 
    
    - 区间  
    * 通配符  
    ? 你不想设置那个字段
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    下面列出一些实例

    CRON表达式    含义 
    "0 0 12 * * ?"    每天中午十二点触发 
    "0 15 10 ? * *"    每天早上10:15触发 
    "0 15 10 * * ?"    每天早上10:15触发 
    "0 15 10 * * ? *"    每天早上10:15触发 
    "0 15 10 * * ? 2005"    2005年的每天早上10:15触发 
    "0 * 14 * * ?"    每天从下午2点开始到2点59分每分钟一次触发 
    "0 0/5 14 * * ?"    每天从下午2点开始到2:55分结束每5分钟一次触发 
    "0 0/5 14,18 * * ?"    每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 
    "0 0-5 14 * * ?"    每天14:00至14:05每分钟一次触发 
    "0 10,44 14 ? 3 WED"    三月的每周三的14:10和14:44触发 
    "0 15 10 ? * MON-FRI"    每个周一、周二、周三、周四、周五的10:15触发 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    参考资料

    Java任务调度框架Quartz教程实例 
    Spring Scheduler的使用与坑 
    Quartz应用与集群原理分析

  • 相关阅读:
    让UILabel的大小自适应字符串长度
    Cocos2dx中的分辨率学习
    关键帧动画-五角星动画-在层上画出五角星
    .net WINFORM 界面怎么做凹凸效果的分割线?就是横线
    游标Cursor 使用小例 (SQLServer)
    winform屏蔽Alt+F4组合键以防止用户关闭对话框
    SQL Server 2005 数据类型和.Net数据类型的对应关系
    php $GLOBALS 超全局变量的理解
    我改行了
    PHP $_FILES详解
  • 原文地址:https://www.cnblogs.com/suizhikuo/p/9593148.html
Copyright © 2011-2022 走看看