许雪里,简称XXL,业内高手,主要作品有XXL-JOB,XXL-SSO等
XXL-JOB主要解决的是分布式任务调度问题。传统的调度任务,主要有以下几种解决方法:
- Thread 线程轮训
- Timer 定期调用
- Quartz 作业调度
- ElasticJob 分布式任务
相对来说,技术方案最成熟的是Quartz,一个纯Java的任务管理库,包括任务定义job,触发器trigger,特别是提出的cron表达式,几乎奠定整个时间规则的基础。
cron的格式一般为0 15 8 ? * * 的六位格式,分别代表秒分时日月周,可以组合成变化多样的条件,例如,每天、每周、几点几分执行等等。
按道理quartz可以解决所有的问题了,但随着分布式、微服务的大规模应用,暴露出一些新的问题,比如说:
- cron需要写在类或配置文件里,修改需要重启
- 处于集群环境下,存在重复执行任务的情况
- 任务的执行情况很难监控,尤其是执行错误
- 一个项目里,如果有多个任务,可能很难查找和管理
一个先进的理念,往往会在带来便利的同时,引发一系列难以预料的问题。幸好通过XXL-JOB的使用,可以解决这些问题。
先来了解一下XXL-JOB的内容,他是一个任务管理工具,你可以理解他是一个管理平台,与业务无关,甚至可以一个控制台管理多个不同系统。简单来说他就是一个图形化界面的job admin dashboard,里面包含针对任务的增删改查、监控、配置等功能。
前提
- 我们自己有个独立的应用系统,假设是一个springboot项目,功能已经开发完成
- 该系统里有几个java方法,需要定期执行,有的需要每天夜间执行,有的需要每隔一小时执行一次,等等
典型任务包括:月末数据汇总统计、批量发送短信、微信
目标
- 创建2个项目,admin 和 demo 项目
- demo项目为一个普通的SpringBoot项目,里面有一个或多个类(方法)作为任务,需要定时执行
- admin是xxl官方提供的管理组件,直接下载后部署即可,用于配置demo的任务执行和监控
准备工作
- JDK 8
- MySQL 5.7
- 以xxl job 2.4版本为示范
git clone https://gitee.com/xuxueli0323/xxl-job.git
doc/db/tables_xxl_job.sql 是MySQL版本的建表语句,请先自行建库建表
admin是管理系统,必要,需要数据库,我们主要用这个
core是公共依赖,必要
samples是示例任务类,非必要,里面有个SampleXxlJob
用git打开项目,打开其中的xxl-job-admin,修改resource的application.properties
# 主要修改内容:数据库地址,账号密码等 server.port=10000 spring.datasource.url=jdbc:mysql://localhost:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=xxl spring.datasource.password=xxlpass spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
改完之后,先尝试运行xxl-job-admin,如果运行成功,可以选择打包运行,将xxl整个工程执行package即可,然后在admin的target下,会有xxl-job-admin-2.4.0-SNAPSHOT.jar文件,可以通过java -jar方式,在服务器运行。
浏览器访问 http://localhost:10000/xxl-job-admin,可以看到登录界面了。
默认账密为 admin / 123456
建议进入“用户管理”菜单,对管理用户进行设置。管理员可以设置所有任务,而普通用户只能修改具体某几个任务。
执行器
执行器对admin来说,是一个外部的应用节点。
执行器需要一个名字,并且执行器内可以有多个任务执行类(JobHandler)
先新建一个Springboot项目demo,pom关键内容如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>2.3.0</version> </dependency> <!-- 如果maven识别不到2.4.0,也可以写2.3.0 -->
然后配置该项目的yml文件
server: port: 8080 servlet: context-path: /demoapp xxl: job: enable: true admin: addresses: http://localhost:10000/xxl-job-admin accessToken: executor: appname: first-executor address: ip: port: 9090 logpath: logretentiondays: 30
其中,admin.addresses是前面我们配置的admin管理地址,appname为本项目的执行器名称,port是本项目与admin通讯的端口
另外需要一个配置类
@Configuration public class XxlJobConfig { private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class); @Value("${xxl.job.admin.addresses}") private String adminAddresses; @Value("${xxl.job.accessToken}") private String accessToken; @Value("${xxl.job.executor.appname}") private String appname; @Value("${xxl.job.executor.address}") private String address; @Value("${xxl.job.executor.ip}") private String ip; @Value("${xxl.job.executor.port}") private int port; @Value("${xxl.job.executor.logpath}") private String logPath; @Value("${xxl.job.executor.logretentiondays}") private int logRetentionDays; @Bean public XxlJobSpringExecutor xxlJobExecutor() { XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); xxlJobSpringExecutor.setAdminAddresses(adminAddresses); xxlJobSpringExecutor.setAppname(appname); xxlJobSpringExecutor.setAddress(address); xxlJobSpringExecutor.setIp(ip); xxlJobSpringExecutor.setPort(port); xxlJobSpringExecutor.setAccessToken(accessToken); xxlJobSpringExecutor.setLogPath(logPath); xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); return xxlJobSpringExecutor; } }
这样,执行器就可以用了
任务类
任务类就是一个Java执行类,书写一个方法,然后xxljob就可以设置这个类的触发时机。
每个项目可以有多个任务类,彼此之间没有关系。
例如,可以在demo项目里写10个任务类,但通过admin,只运行其中的一个或几个。
先写一个简单方法如下:
@Component public class HelloJob { private static final Logger log = LoggerFactory.getLogger(HelloJob.class); @Resource private TestService testService; //这里的demoSaveData就是我们自己定义的jobhandler的名字 @XxlJob("demoSaveData") public void saveData() { log.info("hello world"); testService.saveObject(); } }
现在我们的项目通过config配置了执行器,又建立了任务类,接下来需要配置让他运行。
配置任务执行
先分别启动admin项目和demo项目
进入admin控制台,菜单-执行器管理
点击新增,Appname输入demo的yml文件里的first-executor,名称写第一个执行器,注册方式自动
保存后等待,启动demo项目,过一会就会显示Online机器1台,表示找到了我们的项目。
点击菜单-任务管理
点击新增,执行器选“第一个执行器”,描述和负责人随意写,调度类型cron,表达式写0/5 * * * * ? ,每5秒执行一次。保存
回到列表,点击操作-启动,如果顺利,在项目控制台,就会每5秒看到输出的日志了。