From 442fef2bcdd4a77aa74eaa0d4697cf6051c88fd8 Mon Sep 17 00:00:00 2001 From: fanhang Date: Tue, 18 May 2021 14:11:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BE=9B=20spring-boot-starter=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + .../pom.xml | 4 +- .../executor/core/config/XxlJobConfig.java | 78 --------- .../src/main/resources/application.properties | 23 +-- xxl-job-spring-boot-starter/README.md | 57 +++++++ xxl-job-spring-boot-starter/pom.xml | 65 ++++++++ .../spring/config/XxlJobAdminProperties.java | 31 ++++ .../config/XxlJobAutoConfiguration.java | 107 +++++++++++++ .../config/XxlJobExecutorProperties.java | 150 ++++++++++++++++++ .../main/resources/META-INF/spring.factories | 4 + .../java/com/xxl/job/springtest/Boot.java | 13 ++ .../src/test/resources/application.yml | 15 ++ 12 files changed, 448 insertions(+), 100 deletions(-) delete mode 100644 xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java create mode 100644 xxl-job-spring-boot-starter/README.md create mode 100644 xxl-job-spring-boot-starter/pom.xml create mode 100644 xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAdminProperties.java create mode 100644 xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAutoConfiguration.java create mode 100644 xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobExecutorProperties.java create mode 100644 xxl-job-spring-boot-starter/src/main/resources/META-INF/spring.factories create mode 100644 xxl-job-spring-boot-starter/src/test/java/com/xxl/job/springtest/Boot.java create mode 100644 xxl-job-spring-boot-starter/src/test/resources/application.yml diff --git a/pom.xml b/pom.xml index ac599310..fd572fdc 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ xxl-job-core xxl-job-admin + xxl-job-spring-boot-starter xxl-job-executor-samples diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml index 9782a28d..bebeccfc 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml @@ -43,10 +43,10 @@ test - + com.xuxueli - xxl-job-core + xxl-job-spring-boot-starter ${project.parent.version} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java deleted file mode 100644 index bfd80e22..00000000 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.xxl.job.executor.core.config; - -import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; -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.Configuration; - -/** - * xxl-job config - * - * @author xuxueli 2017-04-28 - */ -@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() { - logger.info(">>>>>>>>>>> xxl-job config init."); - 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; - } - - /** - * 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP; - * - * 1、引入依赖: - * - * org.springframework.cloud - * spring-cloud-commons - * ${version} - * - * - * 2、配置文件,或者容器启动变量 - * spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.' - * - * 3、获取IP - * String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); - */ - - -} \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties index e067db4f..f718d2d8 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties @@ -1,26 +1,9 @@ # web port server.port=8081 -# no web -#spring.main.web-environment=false -# log config -logging.config=classpath:logback.xml +spring.application.name=demo-app -### xxl-job admin address list, such as "http://address" or "http://address01,http://address02" -xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin +xxl-job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin,http://192.168.50.11:8080/xxl-job-admin +xxl-job.executor.preferred-networks=192.168.50 -### xxl-job, access token -xxl.job.accessToken= - -### xxl-job executor appname -xxl.job.executor.appname=xxl-job-executor-sample -### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null -xxl.job.executor.address= -### xxl-job executor server-info -xxl.job.executor.ip= -xxl.job.executor.port=9999 -### xxl-job executor log-path -xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler -### xxl-job executor log-retention-days -xxl.job.executor.logretentiondays=30 diff --git a/xxl-job-spring-boot-starter/README.md b/xxl-job-spring-boot-starter/README.md new file mode 100644 index 00000000..91cbec1e --- /dev/null +++ b/xxl-job-spring-boot-starter/README.md @@ -0,0 +1,57 @@ + +# 使用方式 +## 1. 添加依赖 +```xml + + com.xuxueli + xxl-job-spring-boot-starter + 2.3.0 + +``` + +## 2. 配置 application.yml +遵循约定优于配置的原则, 提供更多的默认配置 +最低配置仅需提供 admin.address 即可 +```yaml +spring: + application: + name: demo-app + +xxl-job: + admin: + addresses: http://localhost:7878 # 必填 + access-token: abcdefghijklmn # 可选, 若 amin 配有 accessToken, 则需要填写 + executor: + enable: true # 是否启用, 默认: true + app-name: demo-app # 可选, 为空则取值 ${spring.application.name} + port-min: 30000 # 可选, 默认: 30000 + port-max: 40000 # 可选, 默认: 49151 + ip: 192.168.3.5 # 可选, 为空则按 preferred-networks 匹配 + preferred-networks: # 可选, 当 ip 为空时, 将遍历网卡的 ip 与此值进行 startWith 匹配 + - 192.168.50 +``` +### 关于 ip 相关配置 +若已经配置 ip, 则以配置为准 +若 ip 留空, 则按 preferred-networks 进行匹配 +若 ip 与 preferred-networks 均未提供, 则按 xxl-job-core 的 IpUtil 获取 + +警告: +多网卡环境, 采用 IpUtil 获取本机 ip 进行注册, 可能存在问题. +比如, admin 与 job 不在同一台机器, 此时使用 job 获取的本机 ip 注册到 admin, 但 admin 可能无法访问此 ip!!! + +建议: +手工指定本机 ip, 或者配置 preferred-networks, 以确保 admin 能正常访问此 ip + + +### 关于 port 相关配置 +port-max 和 port-min 分别指端口的最大值和最小值 +启动时, 会在区间内自动查找可用端口. +查找方法: 由最大值开始, 一直递减, 直到找到可用为止. +若此区间内无可用端口, 则会抛出异常, 无法启动 + +通常情况下, 建议使用默认的区间值 +未提供特定端口的配置, 若希望固定端口, 请将 port-min 与 port-max 设为同一值 + + +## 3. 其他 +照常编写 @XxlJob 之类的任务方法即可 diff --git a/xxl-job-spring-boot-starter/pom.xml b/xxl-job-spring-boot-starter/pom.xml new file mode 100644 index 00000000..271818d8 --- /dev/null +++ b/xxl-job-spring-boot-starter/pom.xml @@ -0,0 +1,65 @@ + + 4.0.0 + + com.xuxueli + xxl-job + 2.3.0 + + xxl-job-spring-boot-starter + jar + + ${project.artifactId} + xxl-job spring-boot starter + https://www.xuxueli.com/ + + + + com.xuxueli + xxl-job-core + ${project.parent.version} + + + + org.springframework.boot + spring-boot-starter + compile + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.slf4j + slf4j-api + compile + + + + + junit + junit + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring-boot.version} + pom + import + + + + \ No newline at end of file diff --git a/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAdminProperties.java b/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAdminProperties.java new file mode 100644 index 00000000..30c6b41b --- /dev/null +++ b/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAdminProperties.java @@ -0,0 +1,31 @@ +package com.xxl.job.spring.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * admin config + * @author fanhang + */ +@Configuration +@ConfigurationProperties(prefix = "xxl-job.admin") +public class XxlJobAdminProperties { + private String addresses; + private String accessToken; + + public String getAddresses() { + return addresses; + } + + public void setAddresses(String addresses) { + this.addresses = addresses; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } +} \ No newline at end of file diff --git a/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAutoConfiguration.java b/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAutoConfiguration.java new file mode 100644 index 00000000..c2ebeb22 --- /dev/null +++ b/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobAutoConfiguration.java @@ -0,0 +1,107 @@ +package com.xxl.job.spring.config; + +import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; +import com.xxl.job.core.util.IpUtil; +import com.xxl.job.core.util.NetUtil; + +import java.io.IOException; +import java.net.*; +import java.util.Enumeration; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.*; + +/** + * @author fanhang + */ +@Configuration +public class XxlJobAutoConfiguration { + private static final Logger log = LoggerFactory.getLogger(XxlJobAutoConfiguration.class); + + @Bean + @ConditionalOnProperty(name = "xxl-job.executor.enable", havingValue = "true", matchIfMissing = true) + public XxlJobSpringExecutor xxlJobSpringExecutor(XxlJobAdminProperties adminProps, XxlJobExecutorProperties executorProps) { + log.info("xxl-job admin [{}] with properties: {}", adminProps.getAddresses(), executorProps); + Assert.hasText(adminProps.getAddresses(), "require [xxl-job.admin.addresses]"); + Assert.hasText(executorProps.getAppName(), "require [xxl-job.executor.appName]"); + String ip = resolveIp(executorProps.getIp(), executorProps.getPreferredNetworks()); + Assert.hasLength(ip, "resolve ip failed"); + int port = resolvePort(executorProps.getPortMin(), executorProps.getPortMax()); + + XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); + xxlJobSpringExecutor.setAdminAddresses(adminProps.getAddresses()); + if (StringUtils.hasLength(adminProps.getAccessToken())) { + xxlJobSpringExecutor.setAccessToken(adminProps.getAccessToken()); + } + xxlJobSpringExecutor.setAppname(executorProps.getAppName()); + xxlJobSpringExecutor.setPort(port); + xxlJobSpringExecutor.setLogPath(executorProps.getLogPath()); + xxlJobSpringExecutor.setLogRetentionDays(executorProps.getLogRetentionDays()); + xxlJobSpringExecutor.setIp(ip); + log.info("xxl-job-executor: (admin:{}, appName:{}, ip={}, port:{})", adminProps.getAddresses(), executorProps.getAppName(), ip, port); + return xxlJobSpringExecutor; + } + + private String resolveIp(String ip, Set preferredNetworks) { + if (StringUtils.hasLength(ip)) { + // 已设置 ip + return ip; + } + // 未设置 ip + if (!CollectionUtils.isEmpty(preferredNetworks)) { + // 已配置 preferredNetworks + ip = findNonLoopbackPreferredAddress(preferredNetworks); + if (StringUtils.hasLength(ip)) { + return ip; + } + } + // 始终都没有找到 ip, 则按 xxl-job-core 默认方式获取 + ip = IpUtil.getIp(); + log.warn("auto get address: {}", ip); + return ip; + } + + private int resolvePort(int portMin, int portMax) { + Assert.state(portMin <= portMax, String.format("invalid port range [%d, %d]", portMin, portMax)); + int port = NetUtil.findAvailablePort(portMax); + Assert.state(port >= portMin, String.format("find available port [%d] out of bounds: [%d, %d]", port, portMin, portMax)); + return port; + } + + /** + * copy from spring-cloud-commons #InetUtils + * + * @param preferredNetworks + * @return + */ + private String findNonLoopbackPreferredAddress(Set preferredNetworks) { + try { + for (Enumeration nics = NetworkInterface.getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isLoopback() || ifc.isVirtual() || !ifc.isUp()) { + continue; + } + for (Enumeration addrs = ifc.getInetAddresses(); addrs.hasMoreElements(); ) { + InetAddress address = addrs.nextElement(); + if (address.isLoopbackAddress()) { + continue; + } + for (String preferredNetwork : preferredNetworks) { + if (address.getHostAddress().startsWith(preferredNetwork)) { + log.debug("resolved preferred ip [{}] from [{} - {}]", address.getHostAddress(), ifc.getName(), ifc.getDisplayName()); + return address.getHostAddress(); + } + } + } + } + } catch (IOException ex) { + log.error("Cannot get non-loopback address", ex); + } + return null; + } +} diff --git a/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobExecutorProperties.java b/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobExecutorProperties.java new file mode 100644 index 00000000..2a497610 --- /dev/null +++ b/xxl-job-spring-boot-starter/src/main/java/com/xxl/job/spring/config/XxlJobExecutorProperties.java @@ -0,0 +1,150 @@ +package com.xxl.job.spring.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import java.io.File; +import java.util.Set; + +/** + * executor config + * @author fanhang + */ +@Configuration +@ConfigurationProperties(prefix = "xxl-job.executor") +public class XxlJobExecutorProperties implements EnvironmentAware, InitializingBean { + private static final Logger log = LoggerFactory.getLogger(XxlJobExecutorProperties.class); + private static final int PORT_MIN = 30000; + private static final int PORT_MAX = 49151; + + private Environment environment; + + private boolean enable = true; + /** + * executor appName, default ${spring.application.name} + */ + private String appName; + /** + * executor ip + */ + private String ip; + /** + * logPath dir, default ${user.home}/logs/xxl-job/${spring.application.name} + */ + private String logPath; + private int logRetentionDays = 30; + /** + * port range min + */ + private int portMin = PORT_MIN; + /** + * port range max + */ + private int portMax = PORT_MAX; + private Set preferredNetworks; + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getLogPath() { + return logPath; + } + + public void setLogPath(String logPath) { + this.logPath = logPath; + } + + public int getLogRetentionDays() { + return logRetentionDays; + } + + public void setLogRetentionDays(int logRetentionDays) { + this.logRetentionDays = logRetentionDays; + } + + public int getPortMin() { + return portMin; + } + + public void setPortMin(int portMin) { + this.portMin = portMin; + } + + public int getPortMax() { + return portMax; + } + + public void setPortMax(int portMax) { + this.portMax = portMax; + } + + public Set getPreferredNetworks() { + return preferredNetworks; + } + + public void setPreferredNetworks(Set preferredNetworks) { + this.preferredNetworks = preferredNetworks; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void afterPropertiesSet() throws Exception { + if (!enable) { + log.warn("xxl-job-executor DISABLE because [xxl-job.executor.enable] is false "); + return; + } + if (!StringUtils.hasLength(appName)) { + appName = environment.getProperty("spring.application.name"); + } + if (!StringUtils.hasLength(logPath)) { + String userHome = environment.getProperty("user.home"); + logPath = userHome + File.separator + "logs" + File.separator + "xxl-job" + File.separator + appName; + } + } + + @Override + public String toString() { + return "XxlJobProperties{" + + "enable=" + enable + + ", appName='" + appName + '\'' + + ", ip='" + ip + '\'' + + ", logPath='" + logPath + '\'' + + ", logRetentionDays=" + logRetentionDays + + ", portMin=" + portMin + + ", portMax=" + portMax + + ", preferredNetworks=" + preferredNetworks + + '}'; + } + +} \ No newline at end of file diff --git a/xxl-job-spring-boot-starter/src/main/resources/META-INF/spring.factories b/xxl-job-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..f75b077a --- /dev/null +++ b/xxl-job-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.xxl.job.spring.config.XxlJobAdminProperties,\ +com.xxl.job.spring.config.XxlJobExecutorProperties,\ +com.xxl.job.spring.config.XxlJobAutoConfiguration diff --git a/xxl-job-spring-boot-starter/src/test/java/com/xxl/job/springtest/Boot.java b/xxl-job-spring-boot-starter/src/test/java/com/xxl/job/springtest/Boot.java new file mode 100644 index 00000000..16494fe7 --- /dev/null +++ b/xxl-job-spring-boot-starter/src/test/java/com/xxl/job/springtest/Boot.java @@ -0,0 +1,13 @@ +package com.xxl.job.springtest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Boot { + + public static void main(String[] args) { + SpringApplication.run(Boot.class, args); + } + +} diff --git a/xxl-job-spring-boot-starter/src/test/resources/application.yml b/xxl-job-spring-boot-starter/src/test/resources/application.yml new file mode 100644 index 00000000..ba6074bf --- /dev/null +++ b/xxl-job-spring-boot-starter/src/test/resources/application.yml @@ -0,0 +1,15 @@ +spring: + application: + name: demo-app + +xxl-job: + admin: + addresses: http://localhost:8080/xxl-job-admin + executor: + preferred-networks: + - 192.168.50 + + +logging: + level: + com.xxl.job: debug -- Gitee