原因

最近在公司写一些job,公司使用的是spring boot提供的注解形式实现的。

这样在自测的时候很麻烦,而且测试提测的时候需要修改cron表达式->提交git->jenkins打包重启

解决方案

查阅资料后决定选用任务调度平台,有很多优秀的任务调度平台,选择xxl-job是因为文档清晰、使用简单、基于远程RPC调用、官方提供spring boot例子。

部署

首先需要执行官网提供的sql

使用docker下载镜像 这里最新版本是2.0.2

  1. docker pull xuxueli/xxl-job-admin:2.0.2

然后运行docker镜像 注意修改参数

  1. docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://数据库地址:3306/xxl-job?Unicode=true&characterEncoding=UTF-8 --spring.datasource.password=数据库密码 --spring.mail.host=smtp.163.com --spring.mail.username=邮箱名 --spring.mail.password=邮箱密码 --xxl.job.login.password=登录密码" -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin --privileged=true -d xuxueli/xxl-job-admin:2.0.2

注意一些参数如邮箱可以省略

在项目中配置

这里配置使用官网示例中的spring boot配置

  1. @Configuration
  2. public class XxlJobConfig {
  3. private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
  4. @Value("${xxl.job.admin.addresses}")
  5. private String adminAddresses;
  6. @Value("${xxl.job.executor.appname}")
  7. private String appName;
  8. @Value("${xxl.job.executor.ip}")
  9. private String ip;
  10. @Value("${xxl.job.executor.port}")
  11. private int port;
  12. @Value("${xxl.job.accessToken}")
  13. private String accessToken;
  14. @Value("${xxl.job.executor.logpath}")
  15. private String logPath;
  16. @Value("${xxl.job.executor.logretentiondays}")
  17. private int logRetentionDays;
  18. @Bean(initMethod = "start", destroyMethod = "destroy")
  19. public XxlJobSpringExecutor xxlJobExecutor() {
  20. logger.info(">>>>>>>>>>> xxl-job config init.");
  21. XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
  22. xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
  23. xxlJobSpringExecutor.setAppName(appName);
  24. xxlJobSpringExecutor.setIp(ip);
  25. xxlJobSpringExecutor.setPort(port);
  26. xxlJobSpringExecutor.setAccessToken(accessToken);
  27. xxlJobSpringExecutor.setLogPath(logPath);
  28. xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
  29. return xxlJobSpringExecutor;
  30. }
  31. }

官网给出的执行器配置说明

  1. ### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
  2. xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
  3. ### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
  4. xxl.job.executor.appname=xxl-job-executor-sample
  5. ### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
  6. xxl.job.executor.ip=
  7. ### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
  8. xxl.job.executor.port=9999
  9. ### 执行器通讯TOKEN [选填]:非空时启用;
  10. xxl.job.accessToken=
  11. ### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
  12. xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
  13. ### 执行器日志保存天数 [选填] :值大于3时生效,启用执行器Log文件定期清理功能,否则不生效;
  14. xxl.job.executor.logretentiondays=-1

执行器

官方给出了不少执行器,但是要在原有项目上改造需要自己写执行器,当然可以使用一个任务写一个执行器,这样执行器就会很多,很难以维护。所以这里采用反射的方式

首先是全类名执行器使用反射的方式

  1. @Component
  2. @JobHandler(value = "BeanByClassHandler")
  3. public class BeanByClassHandler extends IJobHandler {
  4. @Autowired
  5. private ApplicationContext applicationContext;
  6. //根据完整类名 通过反射执行指定方法
  7. @Override
  8. public ReturnT<String> execute(String param) throws Exception {
  9. XxlJobLogger.log(param);
  10. if (param == null || param.equals("")) {
  11. return new ReturnT<>(ReturnT.FAIL_CODE, "参数不能为空!");
  12. }
  13. String[] split = param.split(",");
  14. if (split == null || split.length < 2) {
  15. return new ReturnT<>(ReturnT.FAIL_CODE, "参数格式错误,应为 完整类名,方法名");
  16. }
  17. Class taskBeanClass = null;
  18. try {
  19. taskBeanClass = Class.forName(split[0]);
  20. } catch (Exception e) {
  21. return new ReturnT<>(ReturnT.FAIL_CODE, "类" + split[0] + "不存在");
  22. }
  23. Method method = null;
  24. try {
  25. method = taskBeanClass.getMethod(split[1]);
  26. } catch (Exception e) {
  27. return new ReturnT<>(ReturnT.FAIL_CODE, "方法" + split[1] + "不存在");
  28. }
  29. Object o = applicationContext.getBean(taskBeanClass);
  30. if (o == null) {
  31. return new ReturnT<>(ReturnT.FAIL_CODE, "在Application中类不存在");
  32. }
  33. try {
  34. method.invoke(o);
  35. } catch (Exception e) {
  36. return new ReturnT<>(ReturnT.FAIL_CODE, "方法执行失败");
  37. }
  38. return new ReturnT<>(ReturnT.SUCCESS_CODE, "执行成功");
  39. }
  40. }

这样全类名很长所以可以使用spring管理beanName获得实例进行反射

  1. @Component
  2. @JobHandler(value = "BeanByNameHandler")
  3. public class BeanByNameHandler extends IJobHandler {
  4. @Autowired
  5. private ApplicationContext applicationContext;
  6. //根据spring管理的bean name获取指定类
  7. @Override
  8. public ReturnT<String> execute(String param) throws Exception {
  9. XxlJobLogger.log(param);
  10. if (param == null || param.equals("")) {
  11. return new ReturnT<>(ReturnT.FAIL_CODE, "参数不能为空!");
  12. }
  13. String[] split = param.split(",");
  14. if (split == null || split.length < 2) {
  15. return new ReturnT<>(ReturnT.FAIL_CODE, "参数格式错误,应为bean名称,方法名");
  16. }
  17. Object o = applicationContext.getBean(split[0]);
  18. if(o == null){
  19. return new ReturnT<>(ReturnT.FAIL_CODE,"类在applicationContext中不存在");
  20. }
  21. Method method;
  22. try {
  23. method = o.getClass().getMethod(split[1]);
  24. }catch (Exception e){
  25. return new ReturnT<>(ReturnT.FAIL_CODE,"方法"+split[1]+"不存在");
  26. }
  27. try {
  28. method.invoke(o);
  29. }catch (Exception e){
  30. return new ReturnT<>(ReturnT.FAIL_CODE,"调用方法失败");
  31. }
  32. return new ReturnT<>(ReturnT.SUCCESS_CODE,"调用job成功");
  33. }
  34. }

调用

在web界面新建任务 参数为 全类名,方法名即可。如下图所示



当然也可以执行shell脚本

缺点

  1. xxl-job只支持mysql数据库,公司使用的Oracle 所以docker需要运行一个mysql数据库
  2. xxl-job截至2.0.2版本没有提供多用户及权限管理

补充

好消息xxl-job在最新的 6.27 版本 v2.1.2 Release Notes[2019-12-12]中支持了方法级别的Handler注解,不需要再写反射啦!

docker部署xxl-job 通用反射执行器的更多相关文章

  1. Docker 部署前后端项目

    Docker 部署前后端项目 平生不会相思,才会相思,便害相思. 简介:都是被逼的,从零开始一个Docker 部署九个微服务和三个前端项目.其中,这些服务需要用到Nacos.MySQL.Nginx.E ...

  2. Docker 部署xxl-job 报错:xxl-rpc remoting error(connect timed out), for url : xxxxxx

    使用Docker 部署的xxl-job,当调度中心和执行器部署在不同的容器内,此时xxl-job调用执行器的服务就会报: address:http://172.0.0.1:8841/ code:500 ...

  3. ASP.NET Core开发-Docker部署运行

    ASP.NET Core开发Docker部署,.NET Core支持Docker 部署运行.我们将ASP.NET Core 部署在Docker 上运行. 大家可能都见识过Docker ,今天我们就详细 ...

  4. Docker部署Hadoop集群

    Docker部署Hadoop集群 2016-09-27 杜亦舒 前几天写了文章"Hadoop 集群搭建"之后,一个朋友留言说希望介绍下如何使用Docker部署,这个建议很好,Doc ...

  5. Atiti  qq空间破解(3)------------gui图形化通用cli执行器atiuse

    Atiti  qq空间破解(3)------------gui图形化通用cli执行器atiuse 结构:::命令行+以及反馈log框1 cli_guiUI/index.htm1 /AtiPlatf_c ...

  6. 程序开发使用docker部署

    我们公司自己研发了一套 grand-line 系统,使用 docker 来部署项目. 我是第一批小白鼠,一开始网络差,build 一次要半个小时,连接进入 web shell 也很慢,部署一个微信项目 ...

  7. 我使用celery以及docker部署遇到的问题

    首先我本机测试时没有问题的,但是在线上docker中,任务一直显示 "Sending due task".超时的任务是 django orm update 操作,本地不会出现这样的 ...

  8. Docker部署SDN环境

    2014-12-03 by muzi Docker image = Java class Docker container = Java object 前言 5月份的时候,当我还是一个大学生的时候,有 ...

  9. 在生产环境使用Docker部署应用

    导读 Docker现在越来越流行,但是真正在生产环境部署Docker还是个比较新的概念,还没有一个标准的流程.作者是ROR的程序员,作者结合平时的部署经验,联系Docker的特点,向大家分享了其在生产 ...

随机推荐

  1. spring cloud 系列第7篇 —— sleuth+zipkin 服务链路追踪 (F版本)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.简介 在微服务架构中,几乎每一个前端的请求都会经过多个服务单元协调来提 ...

  2. java源码解析之String类(四)

    /* * 返回指定字符第一次出现的字符串内的索引 */ public int indexOf(int ch) { return indexOf(ch, 0); } /* * 返回指定字符第一次出现的字 ...

  3. ElasticStack学习(二):ElasticStack安装与运行

    一.ElasticSearch的安装与运行 1.由于ElasticSearch是由Java语言开发的,若要运行ElasticSearch,需要安装并配置JDK,并要设置$JAVA_HOME环境变量. ...

  4. selenium3+python3自动化测试学习之网页元素定位

    selenium基础实战之定位网页元素技巧 selenium定位网页元素 find_element_by_id,find_element_by_name,find_element_by_class_n ...

  5. KVM web管理工具——WebVirtMgr

    系统环境: [root@kvm-admin ~]# cat /etc/redhat-release CentOS Linux release (Core) 关闭防火墙.selinux [root@kv ...

  6. Oracle Awr报告_生成

    AWR的概念 Oracle数据库是一个使用量很多的数据库,关于Oracle数据库的性能.Oracle10g以后,Oracle提供了一个性能检测的工具:AWR(Automatic Workload Re ...

  7. Vue的生命周期函数

    详解Vue Lifecycle 先来看看vue官网对vue生命周期的介绍 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.销毁等一系列过程,我们称 ...

  8. Oracle基础学习笔记

    Oracle基础学习笔记 最近找到一份实习工作,有点头疼的是,有阶段性考核,这...,实际想想看,大学期间只学过数据库原理,并没有针对某一数据库管理系统而系统的学习,这正好是一个机会,于是乎用了三天时 ...

  9. WordPress教程之初识WordPress

    你是否梦想过以极低的成本获得一个漂亮的网站,而无需聘请专业的开发和设计人员,也不必学习任何编程知识,并且网站功能可以无限扩展?对这些问题中的任何一个,如果你的答案是肯定的,那么 WordPress 将 ...

  10. LinkedList源码分析:JDK源码分析系列

    如果本文中有不正确的地方请指出由于没有留言可以在公众号添加我的好友共同讨论. 1.介绍 LinkedList 是线程不安全的,允许元素为null的双向链表. 2.继承结构 我们来看一下LinkedLi ...