xxl-job 分布式job调度中心接入手册

项目是spring cloud框架,eureka注册中心,使用许雪里的xxl-job,打算后续将其改造为spring boot工程,接入服务中心。以下是我对其源码接入spring cloud/boot的使用方式,可改良之处尚多,仅给大家提供参考,方便使用。

xxl-job项目地址:

github https://github.com/xuxueli/xxl-job

document http://www.xuxueli.com/xxl-job/

对原项目的介绍此处不再细说,可点开上面的参考文档熟悉
改动后的admin地址:https://github.com/lich1n/my-xxl-job

改动内容:
- 添加了通过业务单号查询job的方法
- 将jobinfo操作的几个接口直接暴露出来了,接我们系统权限验证的我移除了。
- jobinfo表增加业务类型及单号字段

使用方式
将xxl-job-admin打包部署好,自己的业务系统接入job中心启动即可。上面改动过的admin修改mysql连接地址后即可运行,sql脚本为resources下的tables_xxl_job.sql

以下是业务模块的接入过程

spring boot 项目接入步骤

1. 引入依赖
2. yml配置
3. 装配配置类
4. 创建jobhandler执行器
5. 进入xxl-job控制台新增执行器
6. 使用新增的执行器开始任务
7. 在业务模块中操作job的【增、删、改、查、暂停】

1 . 引入依赖

<!-- xxl-job-core -->
<dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>1.9.1</version>
</dependency>

2. yml配置

xxl:job:admin:### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"addresses: http://localhost:8080### xxl-job executor addressexecutor:appname: mktcenterip:port: 9888### xxl-job log pathlogpath: /data/applogs/xxl-job/jobhandler### xxl-job log retention dayslogretentiondays: -1### xxl-job, access tokenaccessToken:

3. 装配配置类

package com.bizvane.mktcenterserviceimpl.common.job;
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;
@Configuration
@ComponentScan(basePackages = "com.bizvane.mktcenterserviceimpl.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(-1);return xxlJobExecutor;}
}

4. 创建jobhandler执行器

package com.bizvane.mktcenterserviceimpl.service.jobhandler;import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHandler;
import org.springframework.stereotype.Component;@JobHandler(value="activity")
@Component
public class ActivityJobHandler extends IJobHandler {@Overridepublic ReturnT<String> execute(String param) throws Exception {System.out.println("开始执行生日活动");return null;}
}

5. 进入xxl-job控制台新增执行器

注意appname与yml中配置名字保持一致 !

6. 使用新增的执行器开始任务

JobHandler名字为步骤4中@JobHandler注解value值

保存即可。

7. 在业务模块中操作job的【增、删、改、查、暂停】等
jobclient工具类,使用restTemplate进行远程调用

package com.bizvane.utils.jobutils;import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;@Component
public class JobClient {@Autowiredprivate RestTemplate restTemplate;@Value("${xxl.job.admin.addresses}")private String[] jobAdminUrl;private static String add = "/jobinfo/add";private static String update = "/jobinfo/update";private static String remove = "/jobinfo/remove";private static String pause = "/jobinfo/pause";private static String resume = "/jobinfo/resume";private static String getJobInfoByBiz = "/jobinfo/getJobInfoByBiz";public JobClient() {}public ResponseEntity<String> addJob(XxlJobInfo xxlJobInfo) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);MultiValueMap<String, String> xxlJobInfoMap = MapUtil.obj2Map(xxlJobInfo);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(xxlJobInfoMap, headers);ResponseEntity<String> response = this.restTemplate.postForEntity(this.getLoadUrl(add), request, String.class, new Object[0]);return response;}public ResponseEntity<String> updateJob(XxlJobInfo xxlJobInfo) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);MultiValueMap<String, String> xxlJobInfoMap = MapUtil.obj2Map(xxlJobInfo);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(xxlJobInfoMap, headers);ResponseEntity<String> response = this.restTemplate.postForEntity(this.getLoadUrl(update), request, String.class, new Object[0]);return response;}public ResponseEntity<String> removeJob(Integer xxlJobInfoId) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<Integer> request = new HttpEntity(xxlJobInfoId, headers);ResponseEntity<String> response = this.restTemplate.postForEntity(this.getLoadUrl(remove), request, String.class, new Object[0]);return response;}public ResponseEntity<String> pauseJob(int xxlJobInfoId) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<Integer> request = new HttpEntity(xxlJobInfoId, headers);ResponseEntity<String> response = this.restTemplate.postForEntity(this.getLoadUrl(pause), request, String.class, new Object[0]);return response;}public ResponseEntity<String> resumeJob(int xxlJobInfoId) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<Integer> request = new HttpEntity(xxlJobInfoId, headers);ResponseEntity<String> response = this.restTemplate.postForEntity(this.getLoadUrl(resume), request, String.class, new Object[0]);return response;}public ResponseEntity<String> getJobInfoByBizJob(XxlJobInfo xxlJobInfo) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);MultiValueMap<String, String> xxlJobInfoMap = MapUtil.obj2Map(xxlJobInfo);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(xxlJobInfoMap, headers);ResponseEntity<String> response = this.restTemplate.postForEntity(this.getLoadUrl(getJobInfoByBiz), request, String.class, new Object[0]);return response;}public String getLoadUrl(String method) {int length = this.jobAdminUrl.length;Random random = new Random();int i = random.nextInt(length);String url = this.jobAdminUrl[i] + method;return url;}
}

map工具类

package com.bizvane.utils.jobutils;import java.lang.reflect.Field;
import java.util.Collections;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;public class MapUtil {public MapUtil() {}public static MultiValueMap<String, String> obj2Map(Object obj) {MultiValueMap<String, String> map = new LinkedMultiValueMap();Field[] fields = obj.getClass().getDeclaredFields();int i = 0;for(int len = fields.length; i < len; ++i) {String varName = fields[i].getName();try {boolean accessFlag = fields[i].isAccessible();fields[i].setAccessible(true);Object o = fields[i].get(obj);if (o != null) {map.put(varName, Collections.singletonList(o.toString()));}fields[i].setAccessible(accessFlag);} catch (IllegalArgumentException var8) {var8.printStackTrace();} catch (IllegalAccessException var9) {var9.printStackTrace();}}return map;}public static MultiValueMap<String, String> obj2MapWithNull(Object obj) {MultiValueMap<String, String> map = new LinkedMultiValueMap();Field[] fields = obj.getClass().getDeclaredFields();int i = 0;for(int len = fields.length; i < len; ++i) {String varName = fields[i].getName();try {boolean accessFlag = fields[i].isAccessible();fields[i].setAccessible(true);Object o = fields[i].get(obj);if (o != null) {map.put(varName, Collections.singletonList(o.toString()));} else {map.put(varName, (Object)null);}fields[i].setAccessible(accessFlag);} catch (IllegalArgumentException var8) {var8.printStackTrace();} catch (IllegalAccessException var9) {var9.printStackTrace();}}return map;}public static MultiValueMap<String, String> obj2MapWithString(Object obj) {MultiValueMap<String, String> map = new LinkedMultiValueMap();Field[] fields = obj.getClass().getDeclaredFields();int i = 0;for(int len = fields.length; i < len; ++i) {String varName = fields[i].getName();try {boolean accessFlag = fields[i].isAccessible();fields[i].setAccessible(true);Object o = fields[i].get(obj);if (o != null) {map.put(varName, Collections.singletonList(o.toString()));} else {map.put(varName, Collections.singletonList(""));}fields[i].setAccessible(accessFlag);} catch (IllegalArgumentException var8) {var8.printStackTrace();} catch (IllegalAccessException var9) {var9.printStackTrace();}}return map;}
}

添加了业务类型及code的实体类

package com.bizvane.utils.jobutils;import java.util.Date;public class XxlJobInfo {private int id;private int jobGroup;private String jobCron;private String jobDesc;private Date addTime;private Date updateTime;private String author;private String alarmEmail;private String executorRouteStrategy;private String executorHandler;private String executorParam;private String executorBlockStrategy;private String executorFailStrategy;private int executorTimeout;private String glueType;private String glueSource;private String glueRemark;private Date glueUpdatetime;private String childJobId;private String jobStatus;private String appName;private Integer bizType;private String bizCode;public XxlJobInfo() {}public int getId() {return this.id;}public void setId(int id) {this.id = id;}public int getJobGroup() {return this.jobGroup;}public void setJobGroup(int jobGroup) {this.jobGroup = jobGroup;}public String getJobCron() {return this.jobCron;}public void setJobCron(String jobCron) {this.jobCron = jobCron;}public String getJobDesc() {return this.jobDesc;}public void setJobDesc(String jobDesc) {this.jobDesc = jobDesc;}public Date getAddTime() {return this.addTime;}public void setAddTime(Date addTime) {this.addTime = addTime;}public Date getUpdateTime() {return this.updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}public String getAuthor() {return this.author;}public void setAuthor(String author) {this.author = author;}public String getAlarmEmail() {return this.alarmEmail;}public void setAlarmEmail(String alarmEmail) {this.alarmEmail = alarmEmail;}public String getExecutorRouteStrategy() {return this.executorRouteStrategy;}public void setExecutorRouteStrategy(String executorRouteStrategy) {this.executorRouteStrategy = executorRouteStrategy;}public String getExecutorHandler() {return this.executorHandler;}public void setExecutorHandler(String executorHandler) {this.executorHandler = executorHandler;}public String getExecutorParam() {return this.executorParam;}public void setExecutorParam(String executorParam) {this.executorParam = executorParam;}public String getExecutorBlockStrategy() {return this.executorBlockStrategy;}public void setExecutorBlockStrategy(String executorBlockStrategy) {this.executorBlockStrategy = executorBlockStrategy;}public String getExecutorFailStrategy() {return this.executorFailStrategy;}public void setExecutorFailStrategy(String executorFailStrategy) {this.executorFailStrategy = executorFailStrategy;}public int getExecutorTimeout() {return this.executorTimeout;}public void setExecutorTimeout(int executorTimeout) {this.executorTimeout = executorTimeout;}public String getGlueType() {return this.glueType;}public void setGlueType(String glueType) {this.glueType = glueType;}public String getGlueSource() {return this.glueSource;}public void setGlueSource(String glueSource) {this.glueSource = glueSource;}public String getGlueRemark() {return this.glueRemark;}public void setGlueRemark(String glueRemark) {this.glueRemark = glueRemark;}public Date getGlueUpdatetime() {return this.glueUpdatetime;}public void setGlueUpdatetime(Date glueUpdatetime) {this.glueUpdatetime = glueUpdatetime;}public String getChildJobId() {return this.childJobId;}public void setChildJobId(String childJobId) {this.childJobId = childJobId;}public String getJobStatus() {return this.jobStatus;}public void setJobStatus(String jobStatus) {this.jobStatus = jobStatus;}public String getAppName() {return this.appName;}public void setAppName(String appName) {this.appName = appName;}public Integer getBizType() {return this.bizType;}public void setBizType(Integer bizType) {this.bizType = bizType;}public String getBizCode() {return this.bizCode;}public void setBizCode(String bizCode) {this.bizCode = bizCode;}
}

再封装一个工具类使用jobclient,下面给出了一个添加job的操作

package com.bizvane.mktcenterserviceimpl.common.utils;import com.bizvane.mktcenterservice.models.po.MktTaskPOWithBLOBs;
import com.bizvane.mktcenterservice.models.vo.ActivitySmartVO;
import com.bizvane.mktcenterservice.models.vo.ActivityVO;
import com.bizvane.mktcenterserviceimpl.common.constants.JobHandlerConstants;
import com.bizvane.mktcenterserviceimpl.common.enums.BusinessTypeEnum;
import com.bizvane.mktcenterserviceimpl.common.job.XxlJobConfig;
import com.bizvane.utils.enumutils.JobEnum;
import com.bizvane.utils.jobutils.JobClient;
import com.bizvane.utils.jobutils.XxlJobInfo;
import com.bizvane.utils.tokens.SysAccountPO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Date;/*** @author chen.li* @date on 2018/7/4 9:50* @description*/
@Component
public class JobUtil {@Autowiredprivate XxlJobConfig xxlJobConfig;@Autowiredprivate JobClient jobClient;/*** 通用job添加方法* @param execuDate* @param desc* @param param* @param author* @param jobHandler* @param businessType*/public void addJob(Date execuDate,String desc,String param,String author,String jobHandler,int businessType){//构建job对象XxlJobInfo xxlJobInfo = new XxlJobInfo();//设置appNamexxlJobInfo.setAppName(xxlJobConfig.getAppName());//设置路由策略xxlJobInfo.setExecutorRouteStrategy(JobEnum.EXECUTOR_ROUTE_STRATEGY_FIRST.getValue());//设置job定时器xxlJobInfo.setJobCron(DateUtil.getCronExpression(execuDate));//设置运行模式xxlJobInfo.setGlueType(JobEnum.GLUE_TYPE_BEAN.getValue());//设置job处理器xxlJobInfo.setExecutorHandler(jobHandler);//设置job描述xxlJobInfo.setJobDesc(desc);//设置执行参数xxlJobInfo.setExecutorParam(param);//设置阻塞处理策略xxlJobInfo.setExecutorBlockStrategy(JobEnum.EXECUTOR_BLOCK_SERIAL_EXECUTION.getValue());//设置失败处理策略xxlJobInfo.setExecutorFailStrategy(JobEnum.EXECUTOR_FAIL_STRATEGY_NULL.getValue());//设置负责人xxlJobInfo.setAuthor(author);//设置业务类型xxlJobInfo.setBizType(businessType);//添加jobjobClient.addJob(xxlJobInfo);}}

至此将job-admin启动起来,自己的业务模块启动起来,就可通过业务操作对job中心的job进行更改,也可以直接在job平台直观操作job控制业务模块的jobhandler的执行。由于restTemplate的loadBalance注解会产生问题,具体问题我没有细查,因此在启动类上需要注释掉此注解,于是我手动在上面jobClient最下方中做了简单的请求负载。以下是启动类代码

package com.bizvane.mktcenterserviceimpl;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;import springfox.documentation.swagger2.annotations.EnableSwagger2;@SpringBootApplication(scanBasePackages = "com.bizvane")
@EnableDiscoveryClient
@EnableSwagger2
@EnableFeignClients(basePackages={"com.bizvane.centerstageservice.rpc","com.bizvane.members.facade.service.api","com.bizvane.couponfacade.interfaces"})
@MapperScan("com.bizvane.mktcenterserviceimpl.mappers")
public class MktcenterApplication {// @Value("${swagger.show}")// private boolean swaggerShow;//  @LoadBalanced@BeanRestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {return restTemplateBuilder.build();}public static void main(String[] args) {SpringApplication.run(MktcenterApplication.class, args);}
}

spring boot 接入xxl-job手册相关推荐

  1. 2021 版 Spring Boot 基础知识复习手册(2w字,建议收藏)

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:分享一套基于SpringBoot和Vue的企业级中后台开源项目,这个项目有点哇塞!个人原创100W +访问量博客: ...

  2. Spring Boot 接入支付宝完整流程实战,网友:看完后秒懂,原来是我想复杂了!...

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 作者:李秀才 blog.csdn.net/qq_33556185/article/details/110445827 ...

  3. Spring Boot 接入 GitHub 第三方登录,只要两行配置!

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:14 个 github 项目!个人原创100W +访问量博客:点击前往,查看更多 本文地址:https://www ...

  4. spring boot接入阿里云rabbitmq

    接入文档 调用SDK收发消息 (aliyun.com) 推荐博客 (5条消息) SpringBoot项目使用阿里云消息队列RabbitMQ版_钞money的博客-CSDN博客 (5条消息) 配置并使用 ...

  5. spring boot接入微信小程序支付流程

    前言 正好最近项目中有需要做微信支付,跟着官方文档写下来坑还是踩了不少,于是写了这篇流程给自己长长记性,代码比较粗糙大家图一乐就好. 官方文档 官方接入指引--微信支付开发者文档 所用依赖 <d ...

  6. Spring Boot 接入钉钉扫码登录

    公司如果有在使用钉钉,向企业管理员申请一个开发者权限. 如果觉得麻烦,可以自己去钉钉平台注册一个企业,不需要认证的. 创建第三方授权应用 1. 选择 工作台 tab 页 2. 拉取至末尾,选择自建应用 ...

  7. Spring Boot接入Graylog

  8. 操作方法:Spring Boot和Thymeleaf与Maven

    Spring Boot是一款出色的软件,可让您在几秒钟内引导Spring应用程序. 它确实有效. 尽可能少的配置即可上手. 而且仍然可以更改默认值. 让我们看看用Thymeleaf和Maven引导Sp ...

  9. Spring Boot 中关于 %2e 的 坑,希望你不要遇到

    作者 | Ruilin 来源 | http://rui0.cn/archives/1643 分享一个Spring Boot中关于%2e的小Trick. 先说结论,当Spring Boot版本在小于等于 ...

  10. Payment Spring Boot 1.0.2.RELEASE 发布,接入微信支付分、先享卡功能

    Payment Spring Boot 是微信支付V3的Java实现,仅仅依赖Spring内置的一些类库.配置简单方便,可以让开发者快速为Spring Boot应用接入微信支付. 演示例子:https ...

最新文章

  1. C#中标准Dis“.NET研究”pose模式的实现
  2. 使用apache的ab对想迪科技站点www.thinkdee.com进行压力测试
  3. 并发工具类纵览——建立起Java并发体系的大厦
  4. Oracle自定义聚集函数
  5. 第八节:常见安全隐患和传统的基于Session和Token的安全校验
  6. 【论文翻译】学习新闻事件预测的因果关系
  7. pandas日常数据处理
  8. [转] 各种数据类型转换
  9. C#-WPF实现抽屉效果抽屉式风格主题框架源码-使用MaterialDesignThemes实现WPF炫酷漂亮的效果-提供Demo下载
  10. 【教程】CoreAVC+Haali安装及设置简易教程(KMPlayer)(2)
  11. Python自定义模块
  12. 将VMware与SoftICE基于网络的远程调试功能相结合
  13. 图片上传File对象不兼容IE
  14. Yolov5如何在训练意外中断后接续训练
  15. 零学Java(7)之数据类型,小AD竟然solo不过小朋友
  16. 关于虚拟机.vmdk与.ovf 磁盘装载问题
  17. 远道知学院| 名下有很多子公司,每个都要独立申请知识产权吗?
  18. JAVA初学者学习书籍推荐
  19. sqlDbx连接mysql 及乱码
  20. RCC APB2PeriphClockCmd RCC APB1PeriphClockCmd

热门文章

  1. java中mysql的优化,Java培训实战教程之mysql优化
  2. Unity3D 材质球学习
  3. 里去频闪的插件叫什么_冬天去海南,你才会发现什么叫“不枉此生”!
  4. 【渗透测试实战】—社会工程学利用详解
  5. mac tortoisesvn客户端_tortoisesvn mac版下载
  6. IT技术员的发展方向和晋升秘笈
  7. 从零开始学习区块链技术
  8. 胡侃学习计算机--理论之外-From南大小百合
  9. Java的Abstraction抽象类/方法-笔记
  10. simulink方框_simulink模型引用