【定时任务】---- xxl-job、@Scheduled

一、@Scheduled注解实现的定时任务

要实现计划任务,首先通过在配置类注解@EnableScheduling来开启对计划任务的支持,然后在要执行计划任务的方法上注解@Scheduled,声明这是一个计划任务。

在Spring Boot 的入口类 XXXApplication 中,必然会有@SpringBootApplication注解,用来标注项目入口,以及完成一些基本的自动自动配置。所以Spring Boot 的项目,可以在启动类中注解@EnableScheduling。

配置类:
在这里插入图片描述计划任务执行类:
在这里插入图片描述其中Scheduled注解中有以下几个参数:
  1.cron是设置定时执行的表达式,如 0 0/5 * * * ?每隔五分钟执行一次 秒 分 时 天 月,cron表达式支持使用占位符
  2.zone表示执行时间的时区
  3.fixedDelay 和fixedDelayString 表示一个固定延迟时间执行,上个任务完成后,延迟多长时间执行
  4.fixedRate 和fixedRateString表示一个固定频率执行,上个任务开始后,多长时间后开始执行
  5.initialDelay 和initialDelayString表示一个初始延迟时间,第一次被调用前延迟的时间

如果多个定时任务定义的是同一个时间,会根据程序加载标有 @Scheduled 方法的先后来执行。若某个定时任务一直无法执行完成,则无法设置下次任务执行时间,之后会导致此任务后面的所有定时任务无法继续执行,也就会出现所有的定时任务罢工的现象。所以应用SpringBoot 的定时任务的方法中,一定不要出现“死循环”、“执行耗费大量时间”、“http持续等待无响应”的现象,否则会导致定时任务直接罢工。针对数据量、查询或者远程调用特别多的场景,推荐把定时任务分段处理。

优点:
不需要依赖外部框架。
简单快速实现任务。@EnableScheduling、@Scheduled 注解

缺点:
无法管理任务。要停止某个任务,必须重新发布。
不支持动态调整。修改任务参数需要重启项目。
不支持集群方式部署。集群模式下会出现任务多次被调度执行的情况,因为集群的节点之间是不会共享任务信息的,每个节点上的任务都会按时执行。

单体,即一个项目部署在一台服务器上;
集群,即将单体复制多份部署在多台服务器,其中每个单体被称为一个节点。

二、xxl-job实现的定时任务

1、xxl-job的使用

1. 简介

XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可,源码结构如下:
xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
xxl-job-executor-sample-spring:Spring版本,通过Spring容器管理执行器,比较通用;
xxl-job-executor-sample-frameless:无框架版本;
在这里插入图片描述

在xxl-job中,有2个角色:
xxl-job-admin调度中心: 统一管理任务调度平台上的调度任务,负责触发调度执行,并且提供任务管理平台。
xxl-job-executor执行器: 执行器通常是我们的业务系统,如示例中的springboot项目。

设计思想:
将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求。

将任务抽象成分散的JobHandler,交由“执行器”统一管理,“执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑。因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性。

xxl-job就是一个中心化管理系统,系统主要通过MySQL管理各种定时任务信息,当到了定时任务的触发时间,就把任务信息从数据库中拉进内存,对任务执行器发起调度请求。
在这里插入图片描述

2. 使用

①下载源码 : https://github.com/xuxueli/xxl-job/

②初始化“调度数据库”:
到官网下载项目源码并解压,获取 “调度数据库初始化SQL脚本” 并执行即可,正常情况下应该生成16张表。SQL脚本位置:/xxl-job/doc/db/tables_xxl_job.sql

表名 作用
xxl_job_group 执行器信息表:维护任务执行器信息
xxl_job_info 调度扩展信息表:用于保存xxl-job调度任务的扩展信息,如任务分组、任务名、机器地址、执行器、执行入参和报警邮件等等
xxl_job_lock 任务调度锁表
xxl_job_log 调度日志表:用于保存xxl-job调度任务的历史信息,如调度结果、执行结果、调度入参、调度机器和执行器等等
xxl_job_log_report 调度日志报表:用户存储xxl-job任务调度日志的报表,调度中心报表功能页面会用到
xxl_job_logglue 任务GLUE日志:用于保存GLUE更新历史,用于支持GLUE的版本回溯功能
xxl_job_registry 执行器注册表:维护在线的执行器和调度中心机器地址信息
xxl_job_user 系统用户表

注意⚠️:调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例;
如果mysql做主从,调度中心集群节点务必强制走主库

步骤一:调度中心(xxl-job-admin)配置、部署等

调度中心项目: xxl-job-admin
作用: 统一管理任务调度平台上调度任务,负责触发调度执行,并且提供任务管理平台。
调度中心配置文件地址: /xxl-job/xxl-job-admin/src/main/resources/xxl-job-admin.properties

### 调度中心JDBC链接
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl-job?Unicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root_pwd
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

### 报警邮箱
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

### 登录账号
xxl.job.login.username=admin
xxl.job.login.password=123456

### 调度中心通讯TOKEN,用于调度中心和执行器之间的通讯进行数据加密,非空时启用
xxl.job.accessToken=

### 调度中心国际化设置,默认为中文版本,值设置为“en”时切换为英文版本
xxl.job.i18n=

启动:部署项目
如果已经正确进行上述配置,可将项目编译打包部署。 调度中心访问地址:http://localhost:8080/xxl-job-admin (该地址执行器将会使用到,作为回调地址),登录后运行界面如下图所示 默认登录账号 “admin/123456”
在这里插入图片描述至此“调度中心”项目已经部署成功。

调度中心集群:
调度中心支持集群部署,提升调度系统容灾和可用性。
调度中心集群部署时,几点要求和建议:

  • DB配置保持一致;
  • 登陆账号配置保持一致;
  • 集群机器时钟保持一致(单机集群忽视);
  • 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。

步骤二. xxl-job-executor执行器 在项目中的配置使用

xxl-job-excutor是任务的执行单元,需要在业务系统中实现。

步骤一:在你的项目里引入xxl-job-core的依赖
<dependency>
  <groupId>com.xuxueli</groupId>
  <artifactId>xxl-job-core</artifactId>
  <version>2.0.1</version>
</dependency>
步骤二:在项目的配置文件中添加

web和执行器端口号不同,调度中心地址addresses和执行器应用名appname保持一致

### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册""任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin

### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=xxl-job-executor-athena

### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册""调度中心请求并触发任务";
xxl.job.executor.ip=

### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999

### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=

### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler

### 执行器日志保存天数 [选填] :值大于3时生效,启用执行器Log文件定期清理功能,否则不生效;
xxl.job.executor.logretentiondays=-1
步骤三:添加XxlJobConfig配置类:

在XxljobConfig中初始化一个XxlJobSpringExecutor,该类用于处理xxl-job-admin和xxl-job-excutor之间的通讯以及任务的处理。

package com.xxl.job.executor.core.config;

import com.xxl.job.core.executor.XxlJobExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * xxl-job config
 *
 * @author xuxueli 2017-04-28
 */
@Configuration
@ComponentScan(basePackages = "com.xxl.job.executor.service.jobhandler")
public class XxlJobConfig {
    
    
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.executor.appname}")
    private String appName;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;


    @Bean(initMethod = "start", destroyMethod = "destroy")
    public XxlJobExecutor xxlJobExecutor() {
    
    
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
        xxlJobExecutor.setAdminAddresses(adminAddresses);
        xxlJobExecutor.setAppName(appName);
        xxlJobExecutor.setIp(ip);
        xxlJobExecutor.setPort(port);
        xxlJobExecutor.setAccessToken(accessToken);
        xxlJobExecutor.setLogPath(logPath);
        xxlJobExecutor.setLogRetentionDays(logRetentionDays);

        return xxlJobExecutor;
    }
}
步骤四:在项目中创建任务

1、继承”IJobHandler”:“com.xxl.job.core.handler.IJobHandler”;
2、注册到Spring容器:添加“@Component”注解,被Spring容器扫描为Bean实例;
3、注册到执行器工厂:添加“@JobHandler(value=”自定义jobhandler名称”)”注解,注解value值对应的是调度中心新建任务的JobHandler属性的值。

@JobHandler(value="jobtest")
@Component
public class job_test extends IJobHandler {
    
    
    @Override
    public ReturnT<String> execute(String s) throws Exception {
    
    
         try {
    
    
            System.out.println("测试~~~");
            /*测试数据*/
            return SUCCESS;
        } catch (Exception e){
    
    
            e.printStackTrace();
            return FAIL;
        }
    }
}
步骤五:执行器项目集群(可选)

执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
执行器集群部署时,几点要求和建议:

  • 执行器回调地址(xxl.job.admin.addresses)需要保持一致;执行器根据该配置进行执行器自动注册等操作
  • 同一个执行器集群内AppName(xxl.job.executor.appname)需要保持一致;调度中心根据该配置动态发现不同集群的在线执行器列表

步骤三. 使用调度中心

1、执行器管理

在这里插入图片描述在这里插入图片描述注意:当是自动注册的时候,会根据appname寻找执行器机器地址,此时Appname 必须和 application.properties 执行器配置文件中appname 保持一致.
如果手动注册,appname 可以不一致,但是机器地址必须和xxl.job.executor.ip 保持一致.

xxl.job.executor.appname=xxl-job-executor-sample
xxl.job.executor.ip=192.168.21.168
xxl.job.executor.port=9999

执行器属性说明
AppName: 是每个执行器集群的唯一标示AppName, 执行器会周期性以AppName为对象进行自动注册。可通过该配置自动发现注册成功的执行器, 供任务调度时使用;

名称: 执行器的名称, 因为AppName限制字母数字等组成,可读性不强, 名称为了提高执行器的可读性;

排序: 执行器的排序, 系统中需要执行器的地方,如任务新增, 将会按照该排序读取可用的执行器列表;

注册方式:调度中心获取执行器地址的方式;

自动注册:执行器自动进行执行器注册,调度中心通过底层注册表可以动态发现执行器机器地址;

手动录入:人工手动录入执行器的地址信息,多地址逗号分隔,供调度中心使用;

机器地址:”注册方式”为”手动录入”时有效,支持人工维护执行器的地址信息;

2、任务管理

在这里插入图片描述点击新增任务后创建任务
jobhandler里的内容需要与任务代码中@jobhandler的value 保持一致.

运行模式:

  • BEAN模式:支持基于类的开发方式,每个任务对应一个Java类。
  • GLUE模式:任务以源码方式维护在调度中心,支持通过Web IDE在线更新,实时编译和生效,因此不需要指定JobHandler。
    在这里插入图片描述路由策略: 集群模式下某个任务选择由哪个执行器完成的策略。
    在这里插入图片描述
3、日志管理,执行任务后,在调度中心可以查看调度日志。在这里插入图片描述

调度时间:”调度中心”触发本次调度并向”执行器”发送任务执行信号的时间;
调度结果:”调度中心”触发本次调度的结果,200表示成功,500或其他表示失败;
调度备注:”调度中心”触发本次调度的日志信息;
执行器地址:本次任务执行的机器地址
运行模式:触发调度时任务的运行模式,运行模式可参考章节 “三、任务详解”;
任务参数:本地任务执行的入参
执行时间:”执行器”中本次任务执行结束后回调的时间;

查看两个临近的调度结果,可以发现任务是由两个执行器轮询执行的。
在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_46459413/article/details/128618089
今日推荐