diff --git a/pom.xml b/pom.xml index 1ee06fb..9f1641d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,165 +2,165 @@ - 4.0.0 + 4.0.0 - com.xkcoding - spring-boot-demo - 1.0.0-SNAPSHOT - - spring-boot-demo-helloworld - spring-boot-demo-properties - spring-boot-demo-actuator - spring-boot-demo-admin-client - spring-boot-demo-admin-server - spring-boot-demo-logback - spring-boot-demo-log-aop - spring-boot-demo-exception-handler - spring-boot-demo-template-freemarker - spring-boot-demo-template-thymeleaf - spring-boot-demo-template-beetl - spring-boot-demo-template-enjoy - spring-boot-demo-orm-jdbctemplate - spring-boot-demo-orm-jpa - spring-boot-demo-orm-mybatis - spring-boot-demo-orm-mybatis-mapper-page - spring-boot-demo-orm-mybatis-plus - spring-boot-demo-orm-beetlsql - spring-boot-demo-upload - spring-boot-demo-cache-redis - spring-boot-demo-cache-ehcache - spring-boot-demo-email - spring-boot-demo-task - spring-boot-demo-task-quartz - spring-boot-demo-swagger - spring-boot-demo-swagger-beauty - spring-boot-demo-rbac-security - spring-boot-demo-rbac-shiro - spring-boot-demo-session - spring-boot-demo-oauth - spring-boot-demo-social - spring-boot-demo-zookeeper - spring-boot-demo-mq-rabbitmq - spring-boot-demo-mq-rocketmq - spring-boot-demo-mq-kafka - spring-boot-demo-websocket - spring-boot-demo-websocket-socketio - spring-boot-demo-ureport2 - spring-boot-demo-uflo - spring-boot-demo-urule - spring-boot-demo-activiti - spring-boot-demo-async - spring-boot-demo-dubbo - spring-boot-demo-war - spring-boot-demo-elasticsearch - spring-boot-demo-mongodb - spring-boot-demo-neo4j - spring-boot-demo-docker - spring-boot-demo-multi-datasource-jpa - spring-boot-demo-multi-datasource-mybatis - spring-boot-demo-sharding-jdbc - spring-boot-demo-tio - spring-boot-demo-codegen - spring-boot-demo-graylog - spring-boot-demo-task-xxl-job - - pom + com.xkcoding + spring-boot-demo + 1.0.0-SNAPSHOT + + spring-boot-demo-helloworld + spring-boot-demo-properties + spring-boot-demo-actuator + spring-boot-demo-admin-client + spring-boot-demo-admin-server + spring-boot-demo-logback + spring-boot-demo-log-aop + spring-boot-demo-exception-handler + spring-boot-demo-template-freemarker + spring-boot-demo-template-thymeleaf + spring-boot-demo-template-beetl + spring-boot-demo-template-enjoy + spring-boot-demo-orm-jdbctemplate + spring-boot-demo-orm-jpa + spring-boot-demo-orm-mybatis + spring-boot-demo-orm-mybatis-mapper-page + spring-boot-demo-orm-mybatis-plus + spring-boot-demo-orm-beetlsql + spring-boot-demo-upload + spring-boot-demo-cache-redis + spring-boot-demo-cache-ehcache + spring-boot-demo-email + spring-boot-demo-task + spring-boot-demo-task-quartz + spring-boot-demo-task-xxl-job + spring-boot-demo-swagger + spring-boot-demo-swagger-beauty + spring-boot-demo-rbac-security + spring-boot-demo-rbac-shiro + spring-boot-demo-session + spring-boot-demo-oauth + spring-boot-demo-social + spring-boot-demo-zookeeper + spring-boot-demo-mq-rabbitmq + spring-boot-demo-mq-rocketmq + spring-boot-demo-mq-kafka + spring-boot-demo-websocket + spring-boot-demo-websocket-socketio + spring-boot-demo-ureport2 + spring-boot-demo-uflo + spring-boot-demo-urule + spring-boot-demo-activiti + spring-boot-demo-async + spring-boot-demo-dubbo + spring-boot-demo-war + spring-boot-demo-elasticsearch + spring-boot-demo-mongodb + spring-boot-demo-neo4j + spring-boot-demo-docker + spring-boot-demo-multi-datasource-jpa + spring-boot-demo-multi-datasource-mybatis + spring-boot-demo-sharding-jdbc + spring-boot-demo-tio + spring-boot-demo-codegen + spring-boot-demo-graylog + + pom - spring-boot-demo - http://xkcoding.com + spring-boot-demo + http://xkcoding.com - - UTF-8 - UTF-8 - 1.8 - 1.8 - 1.8 - 2.1.0.RELEASE - 8.0.12 - 4.5.1 - 27.0.1-jre - 1.20 - + + UTF-8 + UTF-8 + 1.8 + 1.8 + 1.8 + 2.1.0.RELEASE + 8.0.12 + 4.5.1 + 27.0.1-jre + 1.20 + - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - mysql - mysql-connector-java - ${mysql.version} - - - - cn.hutool - hutool-all - ${hutool.version} - - - - com.google.guava - guava - ${guava.version} - - - - eu.bitwalker - UserAgentUtils - ${user.agent.version} - - - + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + mysql + mysql-connector-java + ${mysql.version} + + + + cn.hutool + hutool-all + ${hutool.version} + + + + com.google.guava + guava + ${guava.version} + + + + eu.bitwalker + UserAgentUtils + ${user.agent.version} + + + - - - - - maven-clean-plugin - 3.0.0 - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.7.0 - - - maven-surefire-plugin - 2.20.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - org.springframework.boot - spring-boot-maven-plugin - ${spring.boot.version} - - - - repackage - - - - - - - + + + + + maven-clean-plugin + 3.0.0 + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.7.0 + + + maven-surefire-plugin + 2.20.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + \ No newline at end of file diff --git a/spring-boot-demo-task-xxl-job/README.md b/spring-boot-demo-task-xxl-job/README.md new file mode 100644 index 0000000..96c8bb2 --- /dev/null +++ b/spring-boot-demo-task-xxl-job/README.md @@ -0,0 +1,488 @@ +# spring-boot-demo-task-xxl-job + +> 此 demo 主要演示了 Spring Boot 如何集成 XXL-JOB 实现分布式定时任务,并提供绕过 `xxl-job-admin` 对定时任务的管理的方法,包括定时任务列表,触发器列表,新增定时任务,删除定时任务,停止定时任务,启动定时任务,修改定时任务,手动触发定时任务。 + +## 1. xxl-job-admin调度中心 + +> https://github.com/xuxueli/xxl-job.git + +克隆 调度中心代码 + +```bash +$ git clone https://github.com/xuxueli/xxl-job.git +``` + +### 1.1. 创建调度中心的表结构 + +数据库脚本地址:`/xxl-job/doc/db/tables_xxl_job.sql` + +### 1.2. 修改 application.properties + +```properties +server.port=18080 + +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&useSSL=false +spring.datasource.username=root +spring.datasource.password=root +``` + +### 1.3. 修改日志配置文件 logback.xml + +```xml + +``` + +### 1.4. 启动调度中心 + +Run `XxlJobAdminApplication` + +默认用户名密码:admin/admin + +![image-20190808105554414](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025555.png) + +![image-20190808105628852](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025629.png) + +## 2. 编写执行器项目 + +### 2.1. pom.xml + +```xml + + + 4.0.0 + + spring-boot-demo-task-xxl-job + 1.0.0-SNAPSHOT + jar + + spring-boot-demo-task-xxl-job + Demo project for Spring Boot + + + com.xkcoding + spring-boot-demo + 1.0.0-SNAPSHOT + + + + UTF-8 + UTF-8 + 1.8 + 2.1.0 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + com.xuxueli + xxl-job-core + ${xxl-job.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + + cn.hutool + hutool-all + + + + com.google.guava + guava + + + + org.projectlombok + lombok + true + + + + + spring-boot-demo-task-xxl-job + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` + +### 2.2. 编写 配置类 XxlJobProps.java + +```java +/** + *

+ * xxl-job 配置 + *

+ * + * @author yangkai.shen + * @date Created in 2019-08-07 10:25 + */ +@Data +@ConfigurationProperties(prefix = "xxl.job") +public class XxlJobProps { + /** + * 调度中心配置 + */ + private XxlJobAdminProps admin; + + /** + * 执行器配置 + */ + private XxlJobExecutorProps executor; + + /** + * 与调度中心交互的accessToken + */ + private String accessToken; + + @Data + public static class XxlJobAdminProps { + /** + * 调度中心地址 + */ + private String address; + } + + @Data + public static class XxlJobExecutorProps { + /** + * 执行器名称 + */ + private String appName; + + /** + * 执行器 IP + */ + private String ip; + + /** + * 执行器端口 + */ + private int port; + + /** + * 执行器日志 + */ + private String logPath; + + /** + * 执行器日志保留天数,-1 + */ + private int logRetentionDays; + } +} +``` + +### 2.3. 编写配置文件 application.yml + +```yaml +server: + port: 8080 + servlet: + context-path: /demo +xxl: + job: + # 执行器通讯TOKEN [选填]:非空时启用; + access-token: + admin: + # 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + address: http://localhost:18080/xxl-job-admin + executor: + # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + app-name: spring-boot-demo-task-xxl-job-executor + # 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务"; + ip: + # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口; + port: 9999 + # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + log-path: logs/spring-boot-demo-task-xxl-job/task-log + # 执行器日志保存天数 [选填] :值大于3时生效,启用执行器Log文件定期清理功能,否则不生效; + log-retention-days: -1 +``` + +### 2.4. 编写自动装配类 XxlConfig.java + +```java +/** + *

+ * xxl-job 自动装配 + *

+ * + * @author yangkai.shen + * @date Created in 2019-08-07 10:20 + */ +@Slf4j +@Configuration +@EnableConfigurationProperties(XxlJobProps.class) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class XxlJobConfig { + private final XxlJobProps xxlJobProps; + + @Bean(initMethod = "start", destroyMethod = "destroy") + public XxlJobSpringExecutor xxlJobExecutor() { + log.info(">>>>>>>>>>> xxl-job config init."); + XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); + xxlJobSpringExecutor.setAdminAddresses(xxlJobProps.getAdmin().getAddress()); + xxlJobSpringExecutor.setAccessToken(xxlJobProps.getAccessToken()); + xxlJobSpringExecutor.setAppName(xxlJobProps.getExecutor().getAppName()); + xxlJobSpringExecutor.setIp(xxlJobProps.getExecutor().getIp()); + xxlJobSpringExecutor.setPort(xxlJobProps.getExecutor().getPort()); + xxlJobSpringExecutor.setLogPath(xxlJobProps.getExecutor().getLogPath()); + xxlJobSpringExecutor.setLogRetentionDays(xxlJobProps.getExecutor().getLogRetentionDays()); + + return xxlJobSpringExecutor; + } + +} +``` + +### 2.5. 编写具体的定时逻辑 DemoTask.java + +```java +/** + *

+ * 测试定时任务 + *

+ * + * @author yangkai.shen + * @date Created in 2019-08-07 10:15 + */ +@Slf4j +@Component +@JobHandler("demoTask") +public class DemoTask extends IJobHandler { + + /** + * execute handler, invoked when executor receives a scheduling request + * + * @param param 定时任务参数 + * @return 执行状态 + * @throws Exception 任务异常 + */ + @Override + public ReturnT execute(String param) throws Exception { + // 可以动态获取传递过来的参数,根据参数不同,当前调度的任务不同 + log.info("【param】= {}", param); + XxlJobLogger.log("demo task run at : {}", DateUtil.now()); + return RandomUtil.randomInt(1, 11) % 2 == 0 ? SUCCESS : FAIL; + } +} +``` + +### 2.6. 启动执行器 + +Run `SpringBootDemoTaskXxlJobApplication` + +## 3. 配置定时任务 + +### 3.1. 将启动的执行器添加到调度中心 + +执行器管理 - 新增执行器 + +![image-20190808105910203](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025910.png) + +### 3.2. 添加定时任务 + +任务管理 - 新增 - 保存 + +![image-20190808110127956](https://static.xkcoding.com/spring-boot-demo/2019-08-08-030128.png) + +### 3.3. 启停定时任务 + +任务列表的操作列,拥有以下操作:执行、启动/停止、日志、编辑、删除 + +执行:单次触发任务,不影响定时逻辑 + +启动:启动定时任务 + +停止:停止定时任务 + +日志:查看当前任务执行日志 + +编辑:更新定时任务 + +删除:删除定时任务 + +## 4. 使用API添加定时任务 + +> 实际场景中,如果添加定时任务都需要手动在 xxl-job-admin 去操作,这样可能比较麻烦,用户更希望在自己的页面,添加定时任务参数、定时调度表达式,然后通过 API 的方式添加定时任务 + +### 4.1. 改造xxl-job-admin + +#### 4.1.1. 修改 JobGroupController.java + +```java +... +// 添加执行器列表 +@RequestMapping("/list") +@ResponseBody +// 去除权限校验 +@PermissionLimit(limit = false) +public ReturnT> list(){ + return new ReturnT<>(xxlJobGroupDao.findAll()); +} +... +``` + +#### 4.1.2. 修改 JobInfoController.java + +```java +// 分别在 pageList、add、update、remove、pause、start、triggerJob 方法上添加注解,去除权限校验 +@PermissionLimit(limit = false) +``` + +### 4.2. 改造 执行器项目 + +#### 4.2.1. 添加手动触发类 + +```java +/** + *

+ * 手动操作 xxl-job + *

+ * + * @author yangkai.shen + * @date Created in 2019-08-07 14:58 + */ +@Slf4j +@RestController +@RequestMapping("/xxl-job") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ManualOperateController { + private final static String baseUri = "http://127.0.0.1:18080/xxl-job-admin"; + private final static String JOB_INFO_URI = "/jobinfo"; + private final static String JOB_GROUP_URI = "/jobgroup"; + + /** + * 任务组列表,xxl-job叫做触发器列表 + */ + @GetMapping("/group") + public String xxlJobGroup() { + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_GROUP_URI + "/list").execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + + /** + * 分页任务列表 + * @param page 当前页,第一页 -> 0 + * @param size 每页条数,默认10 + * @return 分页任务列表 + */ + @GetMapping("/list") + public String xxlJobList(Integer page, Integer size) { + Map jobInfo = Maps.newHashMap(); + jobInfo.put("start", page != null ? page : 0); + jobInfo.put("length", size != null ? size : 10); + jobInfo.put("jobGroup", 2); + jobInfo.put("triggerStatus", -1); + + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/pageList").form(jobInfo).execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + + /** + * 测试手动保存任务 + */ + @GetMapping("/add") + public String xxlJobAdd() { + Map jobInfo = Maps.newHashMap(); + jobInfo.put("jobGroup", 2); + jobInfo.put("jobCron", "0 0/1 * * * ? *"); + jobInfo.put("jobDesc", "手动添加的任务"); + jobInfo.put("author", "admin"); + jobInfo.put("executorRouteStrategy", "ROUND"); + jobInfo.put("executorHandler", "demoTask"); + jobInfo.put("executorParam", "手动添加的任务的参数"); + jobInfo.put("executorBlockStrategy", ExecutorBlockStrategyEnum.SERIAL_EXECUTION); + jobInfo.put("glueType", GlueTypeEnum.BEAN); + + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/add").form(jobInfo).execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + + /** + * 测试手动触发一次任务 + */ + @GetMapping("/trigger") + public String xxlJobTrigger() { + Map jobInfo = Maps.newHashMap(); + jobInfo.put("id", 4); + jobInfo.put("executorParam", JSONUtil.toJsonStr(jobInfo)); + + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/trigger").form(jobInfo).execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + + /** + * 测试手动删除任务 + */ + @GetMapping("/remove") + public String xxlJobRemove() { + Map jobInfo = Maps.newHashMap(); + jobInfo.put("id", 4); + + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/remove").form(jobInfo).execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + + /** + * 测试手动停止任务 + */ + @GetMapping("/stop") + public String xxlJobStop() { + Map jobInfo = Maps.newHashMap(); + jobInfo.put("id", 4); + + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/stop").form(jobInfo).execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + + /** + * 测试手动停止任务 + */ + @GetMapping("/start") + public String xxlJobStart() { + Map jobInfo = Maps.newHashMap(); + jobInfo.put("id", 4); + + HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/start").form(jobInfo).execute(); + log.info("【execute】= {}", execute); + return execute.body(); + } + +} +``` + +> 后端其余代码请 clone 本项目,查看具体代码 + +## 参考 + +- [《分布式任务调度平台xxl-job》](http://www.xuxueli.com/xxl-job/#/) + diff --git a/spring-boot-demo-task-xxl-job/pom.xml b/spring-boot-demo-task-xxl-job/pom.xml index d222bc1..efa9656 100644 --- a/spring-boot-demo-task-xxl-job/pom.xml +++ b/spring-boot-demo-task-xxl-job/pom.xml @@ -35,11 +35,6 @@ true - - mysql - mysql-connector-java - - com.xuxueli