Pre Merge pull request !24 from FanX/2.3.0
commit
ba0846961b
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
# 使用方式
|
||||||
|
## 1. 添加依赖
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xuxueli</groupId>
|
||||||
|
<artifactId>xxl-job-spring-boot-starter</artifactId>
|
||||||
|
<version>2.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 之类的任务方法即可
|
@ -0,0 +1,65 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.xuxueli</groupId>
|
||||||
|
<artifactId>xxl-job</artifactId>
|
||||||
|
<version>2.3.0</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>xxl-job-spring-boot-starter</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>${project.artifactId}</name>
|
||||||
|
<description>xxl-job spring-boot starter</description>
|
||||||
|
<url>https://www.xuxueli.com/</url>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xuxueli</groupId>
|
||||||
|
<artifactId>xxl-job-core</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- slf4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>${spring-boot.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
</project>
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<String> 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<String> preferredNetworks) {
|
||||||
|
try {
|
||||||
|
for (Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces(); nics.hasMoreElements(); ) {
|
||||||
|
NetworkInterface ifc = nics.nextElement();
|
||||||
|
if (ifc.isLoopback() || ifc.isVirtual() || !ifc.isUp()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Enumeration<InetAddress> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<String> 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<String> getPreferredNetworks() {
|
||||||
|
return preferredNetworks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreferredNetworks(Set<String> 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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
Loading…
Reference in new issue