提交 c3cf0f74 authored 作者: chenshiying's avatar chenshiying

[新增] nacos 版本升级2.0.3

上级 cceef1d1
差异被折叠。
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-timeloit</artifactId> <artifactId>spring-cloud-timeloit</artifactId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Spring Cloud Timeloit</name> <name>Spring Cloud Timeloit</name>
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<properties> <properties>
<!-- Project revision --> <!-- Project revision -->
<revision>2.3.3-SNAPSHOT</revision> <revision>2.2.8-SNAPSHOT</revision>
<!-- Dependency Versions --> <!-- Dependency Versions -->
<spring-cloud-commons.version>2.2.5.RELEASE</spring-cloud-commons.version> <spring-cloud-commons.version>2.2.5.RELEASE</spring-cloud-commons.version>
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<javax-servlet-api>3.0</javax-servlet-api> <javax-servlet-api>3.0</javax-servlet-api>
<slf4j-api.version>1.7.25</slf4j-api.version> <slf4j-api.version>1.7.30</slf4j-api.version>
<!-- Apache Dubbo --> <!-- Apache Dubbo -->
<dubbo.version>2.7.8</dubbo.version> <dubbo.version>2.7.8</dubbo.version>
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-timeloit-dependencies</artifactId> <artifactId>spring-cloud-timeloit-dependencies</artifactId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Spring Cloud Timeloit</name> <name>Spring Cloud Timeloit</name>
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
<properties> <properties>
<revision>2.3.3-SNAPSHOT</revision> <revision>2.2.8-SNAPSHOT</revision>
<sentinel.version>1.8.0</sentinel.version> <sentinel.version>1.8.1</sentinel.version>
<oss.version>3.1.0</oss.version> <oss.version>3.1.0</oss.version>
<seata.version>1.3.0</seata.version> <seata.version>1.3.0</seata.version>
<nacos.client.version>1.2.1</nacos.client.version> <nacos.client.version>2.0.3</nacos.client.version>
<nacos.config.version>0.8.0</nacos.config.version> <nacos.config.version>0.8.0</nacos.config.version>
<spring.context.support.version>1.0.9</spring.context.support.version> <spring.context.support.version>1.0.11</spring.context.support.version>
<!-- Maven Plugin Versions --> <!-- Maven Plugin Versions -->
<maven-source-plugin.version>2.2.1</maven-source-plugin.version> <maven-source-plugin.version>2.2.1</maven-source-plugin.version>
...@@ -190,6 +190,12 @@ ...@@ -190,6 +190,12 @@
<!-- Own dependencies --> <!-- Own dependencies -->
<dependency>
<groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-timeloit-commons</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-circuitbreaker-sentinel</artifactId> <artifactId>spring-cloud-circuitbreaker-sentinel</artifactId>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit</artifactId> <artifactId>spring-cloud-timeloit</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<module>spring-cloud-timeloit-sentinel-datasource</module> <module>spring-cloud-timeloit-sentinel-datasource</module>
<module>spring-cloud-timeloit-sentinel-gateway</module> <module>spring-cloud-timeloit-sentinel-gateway</module>
<module>spring-cloud-starter-timeloit-sentinel</module> <module>spring-cloud-starter-timeloit-sentinel</module>
<module>spring-cloud-timeloit-commons</module>
</modules> </modules>
</project> </project>
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
...@@ -51,15 +51,10 @@ ...@@ -51,15 +51,10 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
...@@ -87,12 +87,6 @@ ...@@ -87,12 +87,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock.modules.test.powermockito/powermock-modules-test-powermockito --> <!-- https://mvnrepository.com/artifact/org.powermock.modules.test.powermockito/powermock-modules-test-powermockito -->
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
...@@ -110,5 +104,4 @@ ...@@ -110,5 +104,4 @@
</dependencies> </dependencies>
</project> </project>
...@@ -53,6 +53,7 @@ import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT; ...@@ -53,6 +53,7 @@ import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT;
import static com.alibaba.nacos.api.PropertyKeyConst.MAX_RETRY; import static com.alibaba.nacos.api.PropertyKeyConst.MAX_RETRY;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE; import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD; import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD;
import static com.alibaba.nacos.api.PropertyKeyConst.RAM_ROLE_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY; import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME; import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME;
...@@ -202,6 +203,11 @@ public class NacosConfigProperties { ...@@ -202,6 +203,11 @@ public class NacosConfigProperties {
*/ */
private String secretKey; private String secretKey;
/**
* access key for namespace.
*/
private String ramRoleName;
/** /**
* context path for nacos config server. * context path for nacos config server.
*/ */
...@@ -356,6 +362,14 @@ public class NacosConfigProperties { ...@@ -356,6 +362,14 @@ public class NacosConfigProperties {
this.secretKey = secretKey; this.secretKey = secretKey;
} }
public String getRamRoleName() {
return ramRoleName;
}
public void setRamRoleName(String ramRoleName) {
this.ramRoleName = ramRoleName;
}
public String getEncode() { public String getEncode() {
return encode; return encode;
} }
...@@ -548,6 +562,7 @@ public class NacosConfigProperties { ...@@ -548,6 +562,7 @@ public class NacosConfigProperties {
properties.put(NAMESPACE, Objects.toString(this.namespace, "")); properties.put(NAMESPACE, Objects.toString(this.namespace, ""));
properties.put(ACCESS_KEY, Objects.toString(this.accessKey, "")); properties.put(ACCESS_KEY, Objects.toString(this.accessKey, ""));
properties.put(SECRET_KEY, Objects.toString(this.secretKey, "")); properties.put(SECRET_KEY, Objects.toString(this.secretKey, ""));
properties.put(RAM_ROLE_NAME, Objects.toString(this.ramRoleName, ""));
properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, "")); properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
properties.put(MAX_RETRY, Objects.toString(this.maxRetry, "")); properties.put(MAX_RETRY, Objects.toString(this.maxRetry, ""));
properties.put(CONFIG_LONG_POLL_TIMEOUT, properties.put(CONFIG_LONG_POLL_TIMEOUT,
...@@ -560,8 +575,7 @@ public class NacosConfigProperties { ...@@ -560,8 +575,7 @@ public class NacosConfigProperties {
int index = endpoint.indexOf(":"); int index = endpoint.indexOf(":");
properties.put(ENDPOINT, endpoint.substring(0, index)); properties.put(ENDPOINT, endpoint.substring(0, index));
properties.put(ENDPOINT_PORT, endpoint.substring(index + 1)); properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
} } else {
else {
properties.put(ENDPOINT, endpoint); properties.put(ENDPOINT, endpoint);
} }
...@@ -597,6 +611,7 @@ public class NacosConfigProperties { ...@@ -597,6 +611,7 @@ public class NacosConfigProperties {
+ ", enableRemoteSyncConfig=" + enableRemoteSyncConfig + ", endpoint='" + ", enableRemoteSyncConfig=" + enableRemoteSyncConfig + ", endpoint='"
+ endpoint + '\'' + ", namespace='" + namespace + '\'' + ", accessKey='" + endpoint + '\'' + ", namespace='" + namespace + '\'' + ", accessKey='"
+ accessKey + '\'' + ", secretKey='" + secretKey + '\'' + accessKey + '\'' + ", secretKey='" + secretKey + '\''
+ ", ramRoleName='" + ramRoleName + '\''
+ ", contextPath='" + contextPath + '\'' + ", clusterName='" + clusterName + ", contextPath='" + contextPath + '\'' + ", clusterName='" + clusterName
+ '\'' + ", name='" + name + '\'' + '\'' + ", shares=" + sharedConfigs + '\'' + ", name='" + name + '\'' + '\'' + ", shares=" + sharedConfigs
+ ", extensions=" + extensionConfigs + ", refreshEnabled=" + ", extensions=" + extensionConfigs + ", refreshEnabled="
......
...@@ -16,12 +16,16 @@ ...@@ -16,12 +16,16 @@
package com.alibaba.cloud.nacos.client; package com.alibaba.cloud.nacos.client;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.alibaba.cloud.nacos.NacosConfigProperties; import com.alibaba.cloud.nacos.NacosConfigProperties;
import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.CollectionUtils;
/** /**
* @author xiaojing * @author xiaojing
...@@ -58,6 +62,32 @@ public class NacosPropertySource extends MapPropertySource { ...@@ -58,6 +62,32 @@ public class NacosPropertySource extends MapPropertySource {
this.isRefreshable = isRefreshable; this.isRefreshable = isRefreshable;
} }
NacosPropertySource(List<PropertySource<?>> propertySources, String group,
String dataId, Date timestamp, boolean isRefreshable) {
this(group, dataId, getSourceMap(group, dataId, propertySources), timestamp,
isRefreshable);
}
private static Map<String, Object> getSourceMap(String group, String dataId,
List<PropertySource<?>> propertySources) {
if (CollectionUtils.isEmpty(propertySources)) {
return Collections.emptyMap();
}
// If only one, return the internal element, otherwise wrap it.
if (propertySources.size() == 1) {
PropertySource propertySource = propertySources.get(0);
if (propertySource != null && propertySource.getSource() instanceof Map) {
return (Map<String, Object>) propertySource.getSource();
}
}
// If it is multiple, it will be returned as it is, and the internal elements
// cannot be directly retrieved, so the user needs to implement the retrieval
// logic by himself
return Collections.singletonMap(
String.join(NacosConfigProperties.COMMAS, dataId, group),
propertySources);
}
public String getGroup() { public String getGroup() {
return this.group; return this.group;
} }
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
package com.alibaba.cloud.nacos.client; package com.alibaba.cloud.nacos.client;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.List;
import java.util.Map;
import com.alibaba.cloud.nacos.NacosPropertySourceRepository; import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
import com.alibaba.cloud.nacos.parser.NacosDataParserHandler; import com.alibaba.cloud.nacos.parser.NacosDataParserHandler;
...@@ -27,6 +27,7 @@ import com.alibaba.nacos.api.exception.NacosException; ...@@ -27,6 +27,7 @@ import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
...@@ -38,8 +39,6 @@ public class NacosPropertySourceBuilder { ...@@ -38,8 +39,6 @@ public class NacosPropertySourceBuilder {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(NacosPropertySourceBuilder.class); .getLogger(NacosPropertySourceBuilder.class);
private static final Map<String, Object> EMPTY_MAP = new LinkedHashMap();
private ConfigService configService; private ConfigService configService;
private long timeout; private long timeout;
...@@ -71,14 +70,15 @@ public class NacosPropertySourceBuilder { ...@@ -71,14 +70,15 @@ public class NacosPropertySourceBuilder {
*/ */
NacosPropertySource build(String dataId, String group, String fileExtension, NacosPropertySource build(String dataId, String group, String fileExtension,
boolean isRefreshable) { boolean isRefreshable) {
Map<String, Object> p = loadNacosData(dataId, group, fileExtension); List<PropertySource<?>> propertySources = loadNacosData(dataId, group,
NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId, fileExtension);
p, new Date(), isRefreshable); NacosPropertySource nacosPropertySource = new NacosPropertySource(propertySources,
group, dataId, new Date(), isRefreshable);
NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource); NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
return nacosPropertySource; return nacosPropertySource;
} }
private Map<String, Object> loadNacosData(String dataId, String group, private List<PropertySource<?>> loadNacosData(String dataId, String group,
String fileExtension) { String fileExtension) {
String data = null; String data = null;
try { try {
...@@ -87,24 +87,23 @@ public class NacosPropertySourceBuilder { ...@@ -87,24 +87,23 @@ public class NacosPropertySourceBuilder {
log.warn( log.warn(
"Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]", "Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]",
dataId, group); dataId, group);
return EMPTY_MAP; return Collections.emptyList();
} }
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug(String.format( log.debug(String.format(
"Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId, "Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId,
group, data)); group, data));
} }
Map<String, Object> dataMap = NacosDataParserHandler.getInstance() return NacosDataParserHandler.getInstance().parseNacosData(dataId, data,
.parseNacosData(data, fileExtension); fileExtension);
return dataMap == null ? EMPTY_MAP : dataMap;
} }
catch (NacosException e) { catch (NacosException e) {
log.error("get data from Nacos error,dataId:{}, ", dataId, e); log.error("get data from Nacos error,dataId:{} ", dataId, e);
} }
catch (Exception e) { catch (Exception e) {
log.error("parse data from Nacos error,dataId:{},data:{},", dataId, data, e); log.error("parse data from Nacos error,dataId:{},data:{}", dataId, data, e);
} }
return EMPTY_MAP; return Collections.emptyList();
} }
} }
...@@ -101,7 +101,6 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { ...@@ -101,7 +101,6 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
loadSharedConfiguration(composite); loadSharedConfiguration(composite);
loadExtConfiguration(composite); loadExtConfiguration(composite);
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env); loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
return composite; return composite;
} }
...@@ -156,16 +155,15 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { ...@@ -156,16 +155,15 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
private void loadNacosConfiguration(final CompositePropertySource composite, private void loadNacosConfiguration(final CompositePropertySource composite,
List<NacosConfigProperties.Config> configs) { List<NacosConfigProperties.Config> configs) {
for (NacosConfigProperties.Config config : configs) { for (NacosConfigProperties.Config config : configs) {
String dataId = config.getDataId(); loadNacosDataIfPresent(composite, config.getDataId(), config.getGroup(),
String fileExtension = dataId.substring(dataId.lastIndexOf(DOT) + 1); NacosDataParserHandler.getInstance()
loadNacosDataIfPresent(composite, dataId, config.getGroup(), fileExtension, .getFileExtension(config.getDataId()),
config.isRefresh()); config.isRefresh());
} }
} }
private void checkConfiguration(List<NacosConfigProperties.Config> configs, private void checkConfiguration(List<NacosConfigProperties.Config> configs,
String tips) { String tips) {
String[] dataIds = new String[configs.size()];
for (int i = 0; i < configs.size(); i++) { for (int i = 0; i < configs.size(); i++) {
String dataId = configs.get(i).getDataId(); String dataId = configs.get(i).getDataId();
if (dataId == null || dataId.trim().length() == 0) { if (dataId == null || dataId.trim().length() == 0) {
...@@ -173,10 +171,7 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { ...@@ -173,10 +171,7 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
"the [ spring.cloud.nacos.config.%s[%s] ] must give a dataId", "the [ spring.cloud.nacos.config.%s[%s] ] must give a dataId",
tips, i)); tips, i));
} }
dataIds[i] = dataId;
} }
// Just decide that the current dataId must have a suffix
NacosDataParserHandler.getInstance().checkDataId(dataIds);
} }
private void loadNacosDataIfPresent(final CompositePropertySource composite, private void loadNacosDataIfPresent(final CompositePropertySource composite,
......
...@@ -36,7 +36,7 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; ...@@ -36,7 +36,7 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
* *
* @author xiaojing * @author xiaojing
*/ */
@Endpoint(id = "nacos-config") @Endpoint(id = "nacosconfig")
public class NacosConfigEndpoint { public class NacosConfigEndpoint {
private final NacosConfigProperties properties; private final NacosConfigProperties properties;
......
...@@ -32,6 +32,16 @@ public class NacosConfigHealthIndicator extends AbstractHealthIndicator { ...@@ -32,6 +32,16 @@ public class NacosConfigHealthIndicator extends AbstractHealthIndicator {
private final ConfigService configService; private final ConfigService configService;
/**
* status up .
*/
private final String STATUS_UP = "UP";
/**
* status down .
*/
private final String STATUS_DOWN = "DOWN";
public NacosConfigHealthIndicator(ConfigService configService) { public NacosConfigHealthIndicator(ConfigService configService) {
this.configService = configService; this.configService = configService;
} }
...@@ -43,10 +53,10 @@ public class NacosConfigHealthIndicator extends AbstractHealthIndicator { ...@@ -43,10 +53,10 @@ public class NacosConfigHealthIndicator extends AbstractHealthIndicator {
// Set the status to Builder // Set the status to Builder
builder.status(status); builder.status(status);
switch (status) { switch (status) {
case "UP": case STATUS_UP:
builder.up(); builder.up();
break; break;
case "DOWN": case STATUS_DOWN:
builder.down(); builder.down();
break; break;
default: default:
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.logging;
import com.alibaba.nacos.client.logging.NacosLogging;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
/**
* Reload nacos log configuration file, after
* {@link org.springframework.boot.context.logging.LoggingApplicationListener}.
*
* @author mai.jh
*/
public class NacosLoggingListener implements GenericApplicationListener {
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
Class<?> type = resolvableType.getRawClass();
if (type != null) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type);
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
NacosLogging.getInstance().loadConfiguration();
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 21;
}
}
...@@ -20,103 +20,87 @@ import java.io.IOException; ...@@ -20,103 +20,87 @@ import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Nacos-specific loader, If need to support other methods of parsing,you need to do the
* following steps:
* <p>
* 1.inherit {@link AbstractPropertySourceLoader} ;<br/>
* 2. define the file{@code spring.factories} and append
* {@code org.springframework.boot.env.PropertySourceLoader=..}; <br/>
* 3.the last step validate.
* </p>
* Notice the use of {@link NacosByteArrayResource} .
*
* @author zkz * @author zkz
*/ */
public abstract class AbstractNacosDataParser { public abstract class AbstractPropertySourceLoader implements PropertySourceLoader {
protected static final String DOT = ".";
protected static final String VALUE = "value";
protected static final String EMPTY_STRING = "";
private String extension;
private AbstractNacosDataParser nextParser;
protected AbstractNacosDataParser(String extension) {
if (StringUtils.isEmpty(extension)) {
throw new IllegalArgumentException("extension cannot be empty");
}
this.extension = extension.toLowerCase();
}
/** /**
* Verify dataId extensions. * symbol: dot.
* @param extension file extension. json or xml or yml or yaml or properties
* @return valid or not
*/ */
public final boolean checkFileExtension(String extension) { static final String DOT = ".";
if (this.isLegal(extension.toLowerCase())) {
return true;
}
if (this.nextParser == null) {
return false;
}
return this.nextParser.checkFileExtension(extension);
/**
* Prevent interference with other loaders.Nacos-specific loader, unless the reload
* changes it.
* @param name the root name of the property source. If multiple documents are loaded
* an additional suffix should be added to the name for each source loaded.
* @param resource the resource to load
* @return if the resource can be loaded
*/
protected boolean canLoad(String name, Resource resource) {
return resource instanceof NacosByteArrayResource;
} }
/** /**
* Parsing nacos configuration content. * Load the resource into one or more property sources. Implementations may either
* @param data config data from Nacos * return a list containing a single source, or in the case of a multi-document format
* @param extension file extension. json or xml or yml or yaml or properties * such as yaml a source for each document in the resource.
* @return result of Properties * @param name the root name of the property source. If multiple documents are loaded
* @throws IOException thrown if there is a problem parsing config. * an additional suffix should be added to the name for each source loaded.
* @param resource the resource to load
* @return a list property sources
* @throws IOException if the source cannot be loaded
*/ */
public final Map<String, Object> parseNacosData(String data, String extension) @Override
public List<PropertySource<?>> load(String name, Resource resource)
throws IOException { throws IOException {
if (extension == null || extension.length() < 1) { if (!canLoad(name, resource)) {
throw new IllegalStateException("The file extension cannot be empty"); return Collections.emptyList();
}
if (this.isLegal(extension.toLowerCase())) {
return this.doParse(data);
} }
if (this.nextParser == null) { return this.doLoad(name, resource);
throw new IllegalStateException(getTips(extension));
}
return this.nextParser.parseNacosData(data, extension);
} }
/** /**
* Core logic for parsing. * Load the resource into one or more property sources. Implementations may either
* @param data config from Nacos * return a list containing a single source, or in the case of a multi-document format
* @return result of Properties * such as yaml a source for each document in the resource.
* @throws IOException thrown if there is a problem parsing config. * @param name the root name of the property source. If multiple documents are loaded
* an additional suffix should be added to the name for each source loaded.
* @param resource the resource to load
* @return a list property sources
* @throws IOException if the source cannot be loaded
*/ */
protected abstract Map<String, Object> doParse(String data) throws IOException; protected abstract List<PropertySource<?>> doLoad(String name, Resource resource)
throws IOException;
protected AbstractNacosDataParser setNextParser(AbstractNacosDataParser nextParser) {
this.nextParser = nextParser;
return this;
}
public AbstractNacosDataParser addNextParser(AbstractNacosDataParser nextParser) {
if (this.nextParser == null) {
this.nextParser = nextParser;
}
else {
this.nextParser.addNextParser(nextParser);
}
return this;
}
protected boolean isLegal(String extension) {
return this.extension.equalsIgnoreCase(extension)
|| this.extension.contains(extension);
}
protected void flattenedMap(Map<String, Object> result, Map<String, Object> dataMap, protected void flattenedMap(Map<String, Object> result, Map<String, Object> dataMap,
String parentKey) { String parentKey) {
Set<Map.Entry<String, Object>> entries = dataMap.entrySet(); if (dataMap == null || dataMap.isEmpty()) {
for (Iterator<Map.Entry<String, Object>> iterator = entries.iterator(); iterator return;
}
Set<Entry<String, Object>> entries = dataMap.entrySet();
for (Iterator<Entry<String, Object>> iterator = entries.iterator(); iterator
.hasNext();) { .hasNext();) {
Map.Entry<String, Object> entry = iterator.next(); Map.Entry<String, Object> entry = iterator.next();
String key = entry.getKey(); String key = entry.getKey();
...@@ -145,31 +129,4 @@ public abstract class AbstractNacosDataParser { ...@@ -145,31 +129,4 @@ public abstract class AbstractNacosDataParser {
} }
} }
/**
* Reload the key ending in `value` if need.
*/
protected Map<String, Object> reloadMap(Map<String, Object> map) {
if (map == null || map.isEmpty()) {
return null;
}
Map<String, Object> result = new LinkedHashMap<>(map);
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
if (key.contains(DOT)) {
int idx = key.lastIndexOf(DOT);
String suffix = key.substring(idx + 1);
if (VALUE.equalsIgnoreCase(suffix)) {
result.put(key.substring(0, idx), entry.getValue());
}
}
}
return result;
}
public static String getTips(String fileName) {
return String.format(
"[%s] must contains file extension with properties|yaml|yml|xml|json",
fileName);
}
} }
...@@ -16,51 +16,45 @@ ...@@ -16,51 +16,45 @@
package com.alibaba.cloud.nacos.parser; package com.alibaba.cloud.nacos.parser;
import java.io.IOException; import org.springframework.core.io.ByteArrayResource;
import java.util.LinkedHashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/** /**
* Nacos-specific resource.
*
* @author zkz * @author zkz
* @author yuhuangbin
*/ */
public class NacosDataJsonParser extends AbstractNacosDataParser { public class NacosByteArrayResource extends ByteArrayResource {
protected NacosDataJsonParser() { private String filename;
super("json");
}
@Override /**
protected Map<String, Object> doParse(String data) throws IOException { * Create a new {@code ByteArrayResource}.
if (StringUtils.isEmpty(data)) { * @param byteArray the byte array to wrap
return null; */
} public NacosByteArrayResource(byte[] byteArray) {
Map<String, Object> map = parseJSON2Map(data); super(byteArray);
return this.reloadMap(map);
} }
/** /**
* JSON to Map. * Create a new {@code ByteArrayResource} with a description.
* @param json json data * @param byteArray the byte array to wrap
* @return the map convert by json string * @param description where the byte array comes from
* @throws IOException thrown if there is a problem parsing config.
*/ */
private Map<String, Object> parseJSON2Map(String json) throws IOException { public NacosByteArrayResource(byte[] byteArray, String description) {
Map<String, Object> result = new LinkedHashMap<>(32); super(byteArray, description);
}
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> nacosDataMap = mapper.readValue(json, LinkedHashMap.class);
if (CollectionUtils.isEmpty(nacosDataMap)) { public void setFilename(String filename) {
return result; this.filename = filename;
} }
flattenedMap(result, nacosDataMap, EMPTY_STRING);
return result; /**
* This implementation always returns {@code null}, assuming that this resource type
* does not have a filename.
*/
@Override
public String getFilename() {
return null == this.filename ? this.getDescription() : this.filename;
} }
} }
...@@ -17,63 +17,144 @@ ...@@ -17,63 +17,144 @@
package com.alibaba.cloud.nacos.parser; package com.alibaba.cloud.nacos.parser;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import com.alibaba.cloud.nacos.utils.NacosConfigUtils;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import static com.alibaba.cloud.nacos.parser.AbstractPropertySourceLoader.DOT;
/** /**
* @author zkz * @author zkz
*/ */
public final class NacosDataParserHandler { public final class NacosDataParserHandler {
private AbstractNacosDataParser parser; /**
* default extension.
*/
private static final String DEFAULT_EXTENSION = "properties";
private static List<PropertySourceLoader> propertySourceLoaders;
private NacosDataParserHandler() { private NacosDataParserHandler() {
parser = this.createParser(); propertySourceLoaders = SpringFactoriesLoader
.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());
} }
/** /**
* Parsing nacos configuration content. * Parsing nacos configuration content.
* @param data config from Nacos * @param configName name of nacos-config
* @param extension file extension. json or xml or yml or yaml or properties * @param configValue value from nacos-config
* @return result of LinkedHashMap * @param extension identifies the type of configValue
* @return result of Map
* @throws IOException thrown if there is a problem parsing config. * @throws IOException thrown if there is a problem parsing config.
*/ */
public Map<String, Object> parseNacosData(String data, String extension) public List<PropertySource<?>> parseNacosData(String configName, String configValue,
throws IOException { String extension) throws IOException {
if (null == parser) { if (StringUtils.isEmpty(configValue)) {
parser = this.createParser(); return Collections.emptyList();
}
if (StringUtils.isEmpty(extension)) {
extension = this.getFileExtension(configName);
}
for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) {
if (!canLoadFileExtension(propertySourceLoader, extension)) {
continue;
}
NacosByteArrayResource nacosByteArrayResource;
if (propertySourceLoader instanceof PropertiesPropertySourceLoader) {
// PropertiesPropertySourceLoader internal is to use the ISO_8859_1,
// the Chinese will be garbled, needs to transform into unicode.
nacosByteArrayResource = new NacosByteArrayResource(
NacosConfigUtils.selectiveConvertUnicode(configValue).getBytes(),
configName);
}
else {
nacosByteArrayResource = new NacosByteArrayResource(
configValue.getBytes(), configName);
}
nacosByteArrayResource.setFilename(getFileName(configName, extension));
List<PropertySource<?>> propertySourceList = propertySourceLoader
.load(configName, nacosByteArrayResource);
if (CollectionUtils.isEmpty(propertySourceList)) {
return Collections.emptyList();
} }
return parser.parseNacosData(data, extension); return propertySourceList.stream().filter(Objects::nonNull)
.map(propertySource -> {
if (propertySource instanceof EnumerablePropertySource) {
String[] propertyNames = ((EnumerablePropertySource) propertySource)
.getPropertyNames();
if (propertyNames != null && propertyNames.length > 0) {
Map<String, Object> map = new LinkedHashMap<>();
Arrays.stream(propertyNames).forEach(name -> {
map.put(name, propertySource.getProperty(name));
});
return new OriginTrackedMapPropertySource(
propertySource.getName(), map, true);
}
}
return propertySource;
}).collect(Collectors.toList());
}
return Collections.emptyList();
} }
/** /**
* check the validity of file extensions in dataid. * check the current extension can be processed.
* @param dataIdAry array of dataId * @param loader the propertySourceLoader
* @return dataId handle success or not * @param extension file extension
* @return if can match extension
*/ */
public boolean checkDataId(String... dataIdAry) { private boolean canLoadFileExtension(PropertySourceLoader loader, String extension) {
StringBuilder stringBuilder = new StringBuilder(); return Arrays.stream(loader.getFileExtensions())
for (String dataId : dataIdAry) { .anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(extension,
int idx = dataId.lastIndexOf(AbstractNacosDataParser.DOT); fileExtension));
if (idx > 0 && idx < dataId.length() - 1) {
String extension = dataId.substring(idx + 1);
if (parser.checkFileExtension(extension)) {
break;
} }
/**
* @param name filename
* @return file extension, default {@code DEFAULT_EXTENSION} if don't get
*/
public String getFileExtension(String name) {
if (StringUtils.isEmpty(name)) {
return DEFAULT_EXTENSION;
} }
// add tips int idx = name.lastIndexOf(DOT);
stringBuilder.append(dataId).append(","); if (idx > 0 && idx < name.length() - 1) {
} return name.substring(idx + 1);
if (stringBuilder.length() > 0) {
String result = stringBuilder.substring(0, stringBuilder.length() - 1);
throw new IllegalStateException(AbstractNacosDataParser.getTips(result));
} }
return true; return DEFAULT_EXTENSION;
} }
private AbstractNacosDataParser createParser() { private String getFileName(String name, String extension) {
return new NacosDataPropertiesParser().addNextParser(new NacosDataYamlParser()) if (StringUtils.isEmpty(extension)) {
.addNextParser(new NacosDataXmlParser()) return name;
.addNextParser(new NacosDataJsonParser()); }
if (StringUtils.isEmpty(name)) {
return extension;
}
int idx = name.lastIndexOf(DOT);
if (idx > 0 && idx < name.length() - 1) {
String ext = name.substring(idx + 1);
if (extension.equalsIgnoreCase(ext)) {
return name;
}
}
return name + DOT + extension;
} }
public static NacosDataParserHandler getInstance() { public static NacosDataParserHandler getInstance() {
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.parser;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
/**
* @author zkz
*/
public class NacosJsonPropertySourceLoader extends AbstractPropertySourceLoader {
/**
* constant.
*/
private static final String VALUE = "value";
/**
* Returns the file extensions that the loader supports (excluding the '.').
* @return the file extensions
*/
@Override
public String[] getFileExtensions() {
return new String[] { "json" };
}
/**
* Load the resource into one or more property sources. Implementations may either
* return a list containing a single source, or in the case of a multi-document format
* such as yaml a source for each document in the resource.
* @param name the root name of the property source. If multiple documents are loaded
* an additional suffix should be added to the name for each source loaded.
* @param resource the resource to load
* @return a list property sources
* @throws IOException if the source cannot be loaded
*/
@Override
protected List<PropertySource<?>> doLoad(String name, Resource resource)
throws IOException {
Map<String, Object> result = new LinkedHashMap<>(32);
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> nacosDataMap = mapper.readValue(resource.getInputStream(),
LinkedHashMap.class);
flattenedMap(result, nacosDataMap, null);
return Collections.singletonList(
new OriginTrackedMapPropertySource(name, this.reloadMap(result), true));
}
/**
* Reload the key ending in `value` if need.
*/
protected Map<String, Object> reloadMap(Map<String, Object> map) {
if (map == null || map.isEmpty()) {
return null;
}
Map<String, Object> result = new LinkedHashMap<>(map);
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
if (key.contains(DOT)) {
int idx = key.lastIndexOf(DOT);
String suffix = key.substring(idx + 1);
if (VALUE.equalsIgnoreCase(suffix)) {
result.put(key.substring(0, idx), entry.getValue());
}
}
}
return result;
}
}
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
package com.alibaba.cloud.nacos.parser; package com.alibaba.cloud.nacos.parser;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
...@@ -28,39 +29,76 @@ import org.w3c.dom.Document; ...@@ -28,39 +29,76 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.core.Ordered;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* With relatively few usage scenarios, only simple parsing is performed to reduce jar * Parsing for XML requires overwriting the default
* dependencies. * {@link PropertiesPropertySourceLoader}, because it internally rigorously validates
* ({@conde DOCTYPE}) THE XML in a way that makes it difficult to customize the
* configuration; at finally, make sure it's in the first place.
* *
* @author zkz * @author zkz
*/ */
public class NacosDataXmlParser extends AbstractNacosDataParser { public class NacosXmlPropertySourceLoader extends AbstractPropertySourceLoader
implements Ordered {
public NacosDataXmlParser() { /**
super("xml"); * Get the order value of this object.
* <p>
* Higher values are interpreted as lower priority. As a consequence, the object with
* the lowest value has the highest priority (somewhat analogous to Servlet
* {@code load-on-startup} values).
* <p>
* Same order values will result in arbitrary sort positions for the affected objects.
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
@Override
public int getOrder() {
return Integer.MIN_VALUE;
} }
/**
* Returns the file extensions that the loader supports (excluding the '.').
* @return the file extensions
*/
@Override @Override
protected Map<String, Object> doParse(String data) throws IOException { public String[] getFileExtensions() {
if (StringUtils.isEmpty(data)) { return new String[] { "xml" };
return null;
} }
Map<String, Object> map = parseXml2Map(data);
return this.reloadMap(map); /**
* Load the resource into one or more property sources. Implementations may either
* return a list containing a single source, or in the case of a multi-document format
* such as yaml a source for each document in the resource.
* @param name the root name of the property source. If multiple documents are loaded
* an additional suffix should be added to the name for each source loaded.
* @param resource the resource to load
* @return a list property sources
* @throws IOException if the source cannot be loaded
*/
@Override
protected List<PropertySource<?>> doLoad(String name, Resource resource)
throws IOException {
Map<String, Object> nacosDataMap = parseXml2Map(resource);
return Collections.singletonList(
new OriginTrackedMapPropertySource(name, nacosDataMap, true));
} }
private Map<String, Object> parseXml2Map(String xml) throws IOException { private Map<String, Object> parseXml2Map(Resource resource) throws IOException {
xml = xml.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll("\\t", "");
Map<String, Object> map = new LinkedHashMap<>(32); Map<String, Object> map = new LinkedHashMap<>(32);
try { try {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance() DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder(); .newDocumentBuilder();
Document document = documentBuilder Document document = documentBuilder.parse(resource.getInputStream());
.parse(new InputSource(new StringReader(xml)));
if (null == document) { if (null == document) {
return null; return null;
} }
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.utils;
/**
* @author zkzlx
*/
public final class NacosConfigUtils {
private NacosConfigUtils() {
}
/**
* Convert Chinese characters to Unicode.
* @param configValue value of config
* @return new string
*/
public static String selectiveConvertUnicode(String configValue) {
StringBuilder sb = new StringBuilder();
char[] chars = configValue.toCharArray();
for (char aChar : chars) {
if (isBaseLetter(aChar)) {
sb.append(aChar);
}
else {
sb.append(String.format("\\u%04x", (int) aChar));
}
}
return sb.toString();
}
/**
* char is base latin or whitespace?
* @param ch a character
* @return true or false
*/
public static boolean isBaseLetter(char ch) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(ch);
return ub == Character.UnicodeBlock.BASIC_LATIN || Character.isWhitespace(ch);
}
/**
* char is chinese?
* @param c a character
* @return true or false
*/
public static boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
}
}
...@@ -5,3 +5,8 @@ com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\ ...@@ -5,3 +5,8 @@ com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.FailureAnalyzer=\
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
org.springframework.boot.env.PropertySourceLoader=\
com.alibaba.cloud.nacos.parser.NacosJsonPropertySourceLoader,\
com.alibaba.cloud.nacos.parser.NacosXmlPropertySourceLoader
org.springframework.context.ApplicationListener=\
com.alibaba.cloud.nacos.logging.NacosLoggingListener
\ No newline at end of file
...@@ -50,7 +50,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen ...@@ -50,7 +50,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
*/ */
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*") @PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*",
"com.sun.org.apache.xerces.internal.jaxp.*", "org.w3c.dom.*" })
@PowerMockRunnerDelegate(SpringRunner.class) @PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class }) @PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationNoSuffixTest.TestConfig.class, properties = { @SpringBootTest(classes = NacosConfigurationNoSuffixTest.TestConfig.class, properties = {
......
...@@ -49,7 +49,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen ...@@ -49,7 +49,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
* @author zkz * @author zkz
*/ */
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*") @PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*",
"com.sun.org.apache.xerces.internal.jaxp.*", "org.w3c.dom.*" })
@PowerMockRunnerDelegate(SpringRunner.class) @PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class }) @PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, properties = { @SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, properties = {
...@@ -83,13 +84,15 @@ public class NacosConfigurationXmlJsonTest { ...@@ -83,13 +84,15 @@ public class NacosConfigurationXmlJsonTest {
throws Throwable { throws Throwable {
if ("xmlApp.xml".equals(args[0]) && "test-group".equals(args[1])) { if ("xmlApp.xml".equals(args[0]) && "test-group".equals(args[1])) {
return "<top>\n" + " <first>one</first>\n" return "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<top>\n"
+ " <first>one</first>\n"
+ " <sencond value=\"two\">\n" + " <sencond value=\"two\">\n"
+ " <third>three</third>\n" + " </sencond>\n" + " <third>three</third>\n" + " </sencond>\n"
+ "</top>"; + "</top>";
} }
if ("test-name.xml".equals(args[0]) && "test-group".equals(args[1])) { if ("test-name.xml".equals(args[0]) && "test-group".equals(args[1])) {
return "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n" return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
+ " <Service name=\"Catalina\"> \n" + " <Service name=\"Catalina\"> \n"
+ " <Connector value=\"第二个连接器\"> \n" + " <Connector value=\"第二个连接器\"> \n"
+ " <open>开启服务</open> \n" + " <open>开启服务</open> \n"
...@@ -108,7 +111,8 @@ public class NacosConfigurationXmlJsonTest { ...@@ -108,7 +111,8 @@ public class NacosConfigurationXmlJsonTest {
if ("test-name-dev.xml".equals(args[0]) if ("test-name-dev.xml".equals(args[0])
&& "test-group".equals(args[1])) { && "test-group".equals(args[1])) {
return "<application android:label=\"@string/app_name\" android:icon=\"@drawable/osg\">\n" return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<application android:label=\"@string/app_name\" android:icon=\"@drawable/osg\">\n"
+ " <activity android:name=\".osgViewer\"\n" + " <activity android:name=\".osgViewer\"\n"
+ " android:label=\"@string/app_name\" android:screenOrientation=\"landscape\">\n" + " android:label=\"@string/app_name\" android:screenOrientation=\"landscape\">\n"
+ " <intent-filter>\n" + " <intent-filter>\n"
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
...@@ -15,6 +15,11 @@ ...@@ -15,6 +15,11 @@
<dependencies> <dependencies>
<dependency>
<groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-timeloit-commons</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId> <artifactId>spring-boot-actuator</artifactId>
...@@ -107,12 +112,6 @@ ...@@ -107,12 +112,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>io.projectreactor</groupId> <groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId> <artifactId>reactor-test</artifactId>
......
...@@ -28,9 +28,8 @@ import java.util.regex.Matcher; ...@@ -28,9 +28,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import com.alibaba.nacos.api.naming.NamingMaintainService; import com.alibaba.cloud.nacos.event.NacosDiscoveryInfoChangedEvent;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys; import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.client.naming.utils.UtilAndComs; import com.alibaba.nacos.client.naming.utils.UtilAndComs;
...@@ -41,14 +40,12 @@ import org.slf4j.LoggerFactory; ...@@ -41,14 +40,12 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static com.alibaba.nacos.api.NacosFactory.createMaintainService;
import static com.alibaba.nacos.api.NacosFactory.createNamingService;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME; import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
...@@ -186,17 +183,17 @@ public class NacosDiscoveryProperties { ...@@ -186,17 +183,17 @@ public class NacosDiscoveryProperties {
private String secretKey; private String secretKey;
/** /**
* Heart beat interval. Time unit: second. * Heart beat interval. Time unit: millisecond.
*/ */
private Integer heartBeatInterval; private Integer heartBeatInterval;
/** /**
* Heart beat timeout. Time unit: second. * Heart beat timeout. Time unit: millisecond.
*/ */
private Integer heartBeatTimeout; private Integer heartBeatTimeout;
/** /**
* Ip delete timeout. Time unit: second. * Ip delete timeout. Time unit: millisecond.
*/ */
private Integer ipDeleteTimeout; private Integer ipDeleteTimeout;
...@@ -210,15 +207,23 @@ public class NacosDiscoveryProperties { ...@@ -210,15 +207,23 @@ public class NacosDiscoveryProperties {
*/ */
private boolean ephemeral = true; private boolean ephemeral = true;
/**
* Throw exceptions during service registration if true, otherwise, log error
* (defaults to true).
*/
private boolean failFast = true;
@Autowired @Autowired
private InetUtils inetUtils; private InetUtils inetUtils;
@Autowired @Autowired
private Environment environment; private Environment environment;
private NamingService namingService; @Autowired
private NacosServiceManager nacosServiceManager;
private NamingMaintainService namingMaintainService; @Autowired
private ApplicationEventPublisher applicationEventPublisher;
@PostConstruct @PostConstruct
public void init() throws Exception { public void init() throws Exception {
...@@ -268,15 +273,19 @@ public class NacosDiscoveryProperties { ...@@ -268,15 +273,19 @@ public class NacosDiscoveryProperties {
} }
this.overrideFromEnv(environment); this.overrideFromEnv(environment);
if (nacosServiceManager.isNacosDiscoveryInfoChanged(this)) {
Properties properties = getNacosProperties(); applicationEventPublisher
this.namingService = createNamingService(properties); .publishEvent(new NacosDiscoveryInfoChangedEvent(this));
this.namingMaintainService = createMaintainService(properties); }
} }
@PreDestroy /**
public void destroy() { * recommend to use {@link NacosServiceManager#getNamingService(Properties)}.
* @return NamingService
*/
@Deprecated
public NamingService namingServiceInstance() {
return nacosServiceManager.getNamingService(this.getNacosProperties());
} }
public String getEndpoint() { public String getEndpoint() {
...@@ -483,6 +492,51 @@ public class NacosDiscoveryProperties { ...@@ -483,6 +492,51 @@ public class NacosDiscoveryProperties {
this.ephemeral = ephemeral; this.ephemeral = ephemeral;
} }
public boolean isFailFast() {
return failFast;
}
public void setFailFast(boolean failFast) {
this.failFast = failFast;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NacosDiscoveryProperties that = (NacosDiscoveryProperties) o;
return Objects.equals(serverAddr, that.serverAddr)
&& Objects.equals(username, that.username)
&& Objects.equals(password, that.password)
&& Objects.equals(endpoint, that.endpoint)
&& Objects.equals(namespace, that.namespace)
&& Objects.equals(logName, that.logName)
&& Objects.equals(service, that.service)
&& Objects.equals(clusterName, that.clusterName)
&& Objects.equals(group, that.group) && Objects.equals(ip, that.ip)
&& Objects.equals(port, that.port)
&& Objects.equals(networkInterface, that.networkInterface)
&& Objects.equals(accessKey, that.accessKey)
&& Objects.equals(secretKey, that.secretKey)
&& Objects.equals(heartBeatInterval, that.heartBeatInterval)
&& Objects.equals(heartBeatTimeout, that.heartBeatTimeout)
&& Objects.equals(failFast, that.failFast)
&& Objects.equals(ipDeleteTimeout, that.ipDeleteTimeout);
}
@Override
public int hashCode() {
return Objects.hash(serverAddr, username, password, endpoint, namespace,
watchDelay, logName, service, weight, clusterName, group,
namingLoadCacheAtStart, registerEnabled, ip, networkInterface, port,
secure, accessKey, secretKey, heartBeatInterval, heartBeatTimeout,
ipDeleteTimeout, instanceEnabled, ephemeral, failFast);
}
@Override @Override
public String toString() { public String toString() {
return "NacosDiscoveryProperties{" + "serverAddr='" + serverAddr + '\'' return "NacosDiscoveryProperties{" + "serverAddr='" + serverAddr + '\''
...@@ -496,7 +550,7 @@ public class NacosDiscoveryProperties { ...@@ -496,7 +550,7 @@ public class NacosDiscoveryProperties {
+ ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey + ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey
+ '\'' + ", secretKey='" + secretKey + '\'' + ", heartBeatInterval=" + '\'' + ", secretKey='" + secretKey + '\'' + ", heartBeatInterval="
+ heartBeatInterval + ", heartBeatTimeout=" + heartBeatTimeout + heartBeatInterval + ", heartBeatTimeout=" + heartBeatTimeout
+ ", ipDeleteTimeout=" + ipDeleteTimeout + '}'; + ", ipDeleteTimeout=" + ipDeleteTimeout + ", failFast=" + failFast + '}';
} }
public void overrideFromEnv(Environment env) { public void overrideFromEnv(Environment env) {
...@@ -546,16 +600,7 @@ public class NacosDiscoveryProperties { ...@@ -546,16 +600,7 @@ public class NacosDiscoveryProperties {
} }
} }
public NamingService namingServiceInstance() { public Properties getNacosProperties() {
return namingService;
}
@Deprecated
public NamingMaintainService namingMaintainServiceInstance() {
return namingMaintainService;
}
private Properties getNacosProperties() {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put(SERVER_ADDR, serverAddr); properties.put(SERVER_ADDR, serverAddr);
properties.put(USERNAME, Objects.toString(username, "")); properties.put(USERNAME, Objects.toString(username, ""));
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author yuhuangbin
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosServiceAutoConfiguration {
@Bean
public NacosServiceManager nacosServiceManager() {
return new NacosServiceManager();
}
}
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos;
import java.util.Objects;
import java.util.Properties;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.event.EventListener;
import static com.alibaba.nacos.api.NacosFactory.createMaintainService;
import static com.alibaba.nacos.api.NacosFactory.createNamingService;
import static org.springframework.beans.BeanUtils.copyProperties;
/**
* @author yuhuangbin
*/
public class NacosServiceManager {
private static final Logger log = LoggerFactory.getLogger(NacosServiceManager.class);
private NacosDiscoveryProperties nacosDiscoveryPropertiesCache;
private NamingService namingService;
private NamingMaintainService namingMaintainService;
public NamingService getNamingService(Properties properties) {
if (Objects.isNull(this.namingService)) {
buildNamingService(properties);
}
return namingService;
}
public NamingMaintainService getNamingMaintainService(Properties properties) {
if (Objects.isNull(namingMaintainService)) {
buildNamingMaintainService(properties);
}
return namingMaintainService;
}
public boolean isNacosDiscoveryInfoChanged(
NacosDiscoveryProperties nacosDiscoveryProperties) {
if (Objects.isNull(nacosDiscoveryPropertiesCache)
|| this.nacosDiscoveryPropertiesCache.equals(nacosDiscoveryProperties)) {
return false;
}
copyProperties(nacosDiscoveryProperties, nacosDiscoveryPropertiesCache);
return true;
}
private NamingMaintainService buildNamingMaintainService(Properties properties) {
if (Objects.isNull(namingMaintainService)) {
synchronized (NacosServiceManager.class) {
if (Objects.isNull(namingMaintainService)) {
namingMaintainService = createNamingMaintainService(properties);
}
}
}
return namingMaintainService;
}
private NamingService buildNamingService(Properties properties) {
if (Objects.isNull(namingService)) {
synchronized (NacosServiceManager.class) {
if (Objects.isNull(namingService)) {
namingService = createNewNamingService(properties);
}
}
}
return namingService;
}
private NamingService createNewNamingService(Properties properties) {
try {
return createNamingService(properties);
}
catch (NacosException e) {
throw new RuntimeException(e);
}
}
private NamingMaintainService createNamingMaintainService(Properties properties) {
try {
return createMaintainService(properties);
}
catch (NacosException e) {
throw new RuntimeException(e);
}
}
public void nacosServiceShutDown() throws NacosException {
if (Objects.nonNull(this.namingService)) {
this.namingService.shutDown();
this.namingService = null;
}
if (Objects.nonNull(this.namingMaintainService)) {
this.namingMaintainService.shutDown();
this.namingMaintainService = null;
}
}
@EventListener
public void onInstancePreRegisteredEvent(
InstancePreRegisteredEvent instancePreRegisteredEvent) {
Registration registration = instancePreRegisteredEvent.getRegistration();
if (Objects.isNull(nacosDiscoveryPropertiesCache)
&& registration instanceof NacosRegistration) {
NacosDiscoveryProperties nacosDiscoveryProperties = ((NacosRegistration) registration)
.getNacosDiscoveryProperties();
nacosDiscoveryPropertiesCache = new NacosDiscoveryProperties();
copyProperties(nacosDiscoveryProperties, nacosDiscoveryPropertiesCache);
}
}
}
...@@ -18,6 +18,7 @@ package com.alibaba.cloud.nacos.discovery; ...@@ -18,6 +18,7 @@ package com.alibaba.cloud.nacos.discovery;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
...@@ -41,8 +42,9 @@ public class NacosDiscoveryAutoConfiguration { ...@@ -41,8 +42,9 @@ public class NacosDiscoveryAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public NacosServiceDiscovery nacosServiceDiscovery( public NacosServiceDiscovery nacosServiceDiscovery(
NacosDiscoveryProperties discoveryProperties) { NacosDiscoveryProperties discoveryProperties,
return new NacosServiceDiscovery(discoveryProperties); NacosServiceManager nacosServiceManager) {
return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
} }
} }
...@@ -18,8 +18,8 @@ package com.alibaba.cloud.nacos.discovery; ...@@ -18,8 +18,8 @@ package com.alibaba.cloud.nacos.discovery;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
...@@ -31,7 +31,6 @@ import org.springframework.cloud.client.discovery.DiscoveryClient; ...@@ -31,7 +31,6 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
/** /**
* @author xiaojing * @author xiaojing
...@@ -56,9 +55,9 @@ public class NacosDiscoveryClientConfiguration { ...@@ -56,9 +55,9 @@ public class NacosDiscoveryClientConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled", @ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled",
matchIfMissing = true) matchIfMissing = true)
public NacosWatch nacosWatch(NacosDiscoveryProperties nacosDiscoveryProperties, public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager,
ObjectProvider<TaskScheduler> taskScheduler) { NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosWatch(nacosDiscoveryProperties, taskScheduler); return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties);
} }
} }
...@@ -23,7 +23,9 @@ import java.util.Map; ...@@ -23,7 +23,9 @@ import java.util.Map;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceInstance; import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView; import com.alibaba.nacos.api.naming.pojo.ListView;
...@@ -36,8 +38,12 @@ public class NacosServiceDiscovery { ...@@ -36,8 +38,12 @@ public class NacosServiceDiscovery {
private NacosDiscoveryProperties discoveryProperties; private NacosDiscoveryProperties discoveryProperties;
public NacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties) { private NacosServiceManager nacosServiceManager;
public NacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties,
NacosServiceManager nacosServiceManager) {
this.discoveryProperties = discoveryProperties; this.discoveryProperties = discoveryProperties;
this.nacosServiceManager = nacosServiceManager;
} }
/** /**
...@@ -48,8 +54,8 @@ public class NacosServiceDiscovery { ...@@ -48,8 +54,8 @@ public class NacosServiceDiscovery {
*/ */
public List<ServiceInstance> getInstances(String serviceId) throws NacosException { public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
String group = discoveryProperties.getGroup(); String group = discoveryProperties.getGroup();
List<Instance> instances = discoveryProperties.namingServiceInstance() List<Instance> instances = namingService().selectInstances(serviceId, group,
.selectInstances(serviceId, group, true); true);
return hostToServiceInstanceList(instances, serviceId); return hostToServiceInstanceList(instances, serviceId);
} }
...@@ -60,8 +66,8 @@ public class NacosServiceDiscovery { ...@@ -60,8 +66,8 @@ public class NacosServiceDiscovery {
*/ */
public List<String> getServices() throws NacosException { public List<String> getServices() throws NacosException {
String group = discoveryProperties.getGroup(); String group = discoveryProperties.getGroup();
ListView<String> services = discoveryProperties.namingServiceInstance() ListView<String> services = namingService().getServicesOfServer(1,
.getServicesOfServer(1, Integer.MAX_VALUE, group); Integer.MAX_VALUE, group);
return services.getData(); return services.getData();
} }
...@@ -105,4 +111,9 @@ public class NacosServiceDiscovery { ...@@ -105,4 +111,9 @@ public class NacosServiceDiscovery {
return nacosServiceInstance; return nacosServiceInstance;
} }
private NamingService namingService() {
return nacosServiceManager
.getNamingService(discoveryProperties.getNacosProperties());
}
} }
...@@ -16,60 +16,73 @@ ...@@ -16,60 +16,73 @@
package com.alibaba.cloud.nacos.discovery; package com.alibaba.cloud.nacos.discovery;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent; import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.SmartLifecycle; import org.springframework.context.SmartLifecycle;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/** /**
* @author xiaojing * @author xiaojing
* @author yuhuangbin
* @author pengfei.lu
*/ */
public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycle { public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycle, DisposableBean {
private static final Logger log = LoggerFactory.getLogger(NacosWatch.class); private static final Logger log = LoggerFactory.getLogger(NacosWatch.class);
private final NacosDiscoveryProperties properties; private Map<String, EventListener> listenerMap = new ConcurrentHashMap<>(16);
private final TaskScheduler taskScheduler; private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicLong nacosWatchIndex = new AtomicLong(0); private final AtomicLong nacosWatchIndex = new AtomicLong(0);
private final AtomicBoolean running = new AtomicBoolean(false);
private ApplicationEventPublisher publisher; private ApplicationEventPublisher publisher;
private ScheduledFuture<?> watchFuture; private ScheduledFuture<?> watchFuture;
public NacosWatch(NacosDiscoveryProperties properties) { private NacosServiceManager nacosServiceManager;
this(properties, getTaskScheduler());
} private final NacosDiscoveryProperties properties;
private final ThreadPoolTaskScheduler taskScheduler;
public NacosWatch(NacosDiscoveryProperties properties, TaskScheduler taskScheduler) { public NacosWatch(NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties properties) {
this.nacosServiceManager = nacosServiceManager;
this.properties = properties; this.properties = properties;
this.taskScheduler = taskScheduler; this.taskScheduler = getTaskScheduler();
} }
/** @Deprecated
* The constructor with {@link NacosDiscoveryProperties} bean and the optional. public NacosWatch(NacosServiceManager nacosServiceManager,
* {@link TaskScheduler} bean NacosDiscoveryProperties properties,
* @param properties {@link NacosDiscoveryProperties} bean ObjectProvider<ThreadPoolTaskScheduler> taskScheduler) {
* @param taskScheduler the optional {@link TaskScheduler} bean this.nacosServiceManager = nacosServiceManager;
* @since 2.2.0 this.properties = properties;
*/ this.taskScheduler = taskScheduler.stream().findAny()
public NacosWatch(NacosDiscoveryProperties properties, .orElseGet(NacosWatch::getTaskScheduler);
ObjectProvider<TaskScheduler> taskScheduler) {
this(properties, taskScheduler.getIfAvailable(NacosWatch::getTaskScheduler));
} }
private static ThreadPoolTaskScheduler getTaskScheduler() { private static ThreadPoolTaskScheduler getTaskScheduler() {
...@@ -98,20 +111,76 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl ...@@ -98,20 +111,76 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
@Override @Override
public void start() { public void start() {
if (this.running.compareAndSet(false, true)) { if (this.running.compareAndSet(false, true)) {
EventListener eventListener = listenerMap.computeIfAbsent(buildKey(),
event -> new EventListener() {
@Override
public void onEvent(Event event) {
if (event instanceof NamingEvent) {
List<Instance> instances = ((NamingEvent) event)
.getInstances();
Optional<Instance> instanceOptional = selectCurrentInstance(
instances);
instanceOptional.ifPresent(currentInstance -> {
resetIfNeeded(currentInstance);
});
}
}
});
NamingService namingService = nacosServiceManager
.getNamingService(properties.getNacosProperties());
try {
namingService.subscribe(properties.getService(), properties.getGroup(),
Arrays.asList(properties.getClusterName()), eventListener);
}
catch (Exception e) {
log.error("namingService subscribe failed, properties:{}", properties, e);
}
this.watchFuture = this.taskScheduler.scheduleWithFixedDelay( this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(
this::nacosServicesWatch, this.properties.getWatchDelay()); this::nacosServicesWatch, this.properties.getWatchDelay());
} }
} }
private String buildKey() {
return String.join(":", properties.getService(), properties.getGroup());
}
private void resetIfNeeded(Instance instance) {
if (!properties.getMetadata().equals(instance.getMetadata())) {
properties.setMetadata(instance.getMetadata());
}
}
private Optional<Instance> selectCurrentInstance(List<Instance> instances) {
return instances.stream()
.filter(instance -> properties.getIp().equals(instance.getIp())
&& properties.getPort() == instance.getPort())
.findFirst();
}
@Override @Override
public void stop() { public void stop() {
if (this.running.compareAndSet(true, false) && this.watchFuture != null) { if (this.running.compareAndSet(true, false)) {
if (this.watchFuture != null) {
// shutdown current user-thread, // shutdown current user-thread,
// then the other daemon-threads will terminate automatic. // then the other daemon-threads will terminate automatic.
((ThreadPoolTaskScheduler) this.taskScheduler).shutdown(); this.taskScheduler.shutdown();
this.watchFuture.cancel(true); this.watchFuture.cancel(true);
} }
EventListener eventListener = listenerMap.get(buildKey());
try {
NamingService namingService = nacosServiceManager
.getNamingService(properties.getNacosProperties());
namingService.unsubscribe(properties.getService(), properties.getGroup(),
Arrays.asList(properties.getClusterName()), eventListener);
}
catch (Exception e) {
log.error("namingService unsubscribe failed, properties:{}", properties,
e);
}
}
} }
@Override @Override
...@@ -132,4 +201,8 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl ...@@ -132,4 +201,8 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
} }
@Override
public void destroy() {
this.stop();
}
} }
...@@ -31,6 +31,16 @@ import org.springframework.boot.actuate.health.HealthIndicator; ...@@ -31,6 +31,16 @@ import org.springframework.boot.actuate.health.HealthIndicator;
*/ */
public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator { public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator {
/**
* status up.
*/
private static final String STATUS_UP = "UP";
/**
* status down.
*/
private static final String STATUS_DOWN = "DOWN";
private final NamingService namingService; private final NamingService namingService;
public NacosDiscoveryHealthIndicator(NamingService namingService) { public NacosDiscoveryHealthIndicator(NamingService namingService) {
...@@ -44,10 +54,10 @@ public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator { ...@@ -44,10 +54,10 @@ public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator {
// Set the status to Builder // Set the status to Builder
builder.status(status); builder.status(status);
switch (status) { switch (status) {
case "UP": case STATUS_UP:
builder.up(); builder.up();
break; break;
case "DOWN": case STATUS_DOWN:
builder.down(); builder.down();
break; break;
default: default:
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.alibaba.cloud.nacos.discovery.configclient; package com.alibaba.cloud.nacos.discovery.configclient;
import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration; import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration; import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration;
import com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration; import com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration;
...@@ -36,7 +37,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -36,7 +37,7 @@ import org.springframework.context.annotation.Configuration;
matchIfMissing = false) matchIfMissing = false)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ NacosDiscoveryAutoConfiguration.class, @ImportAutoConfiguration({ NacosDiscoveryAutoConfiguration.class,
NacosDiscoveryClientConfiguration.class, NacosServiceAutoConfiguration.class, NacosDiscoveryClientConfiguration.class,
NacosReactiveDiscoveryClientConfiguration.class }) NacosReactiveDiscoveryClientConfiguration.class })
public class NacosDiscoveryClientConfigServiceBootstrapConfiguration { public class NacosDiscoveryClientConfigServiceBootstrapConfiguration {
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.discovery.logging;
import com.alibaba.nacos.client.logging.NacosLogging;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
/**
* Reload nacos log configuration file, after
* {@link org.springframework.boot.context.logging.LoggingApplicationListener}.
*
* @author mai.jh
*/
public class NacosLoggingListener implements GenericApplicationListener {
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
Class<?> type = resolvableType.getRawClass();
if (type != null) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type);
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
NacosLogging.getInstance().loadConfiguration();
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 21;
}
}
...@@ -22,7 +22,9 @@ import java.util.List; ...@@ -22,7 +22,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo; import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -35,15 +37,19 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; ...@@ -35,15 +37,19 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
* *
* @author xiaojing * @author xiaojing
*/ */
@Endpoint(id = "nacos-discovery") @Endpoint(id = "nacosdiscovery")
public class NacosDiscoveryEndpoint { public class NacosDiscoveryEndpoint {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryEndpoint.class); .getLogger(NacosDiscoveryEndpoint.class);
private NacosServiceManager nacosServiceManager;
private NacosDiscoveryProperties nacosDiscoveryProperties; private NacosDiscoveryProperties nacosDiscoveryProperties;
public NacosDiscoveryEndpoint(NacosDiscoveryProperties nacosDiscoveryProperties) { public NacosDiscoveryEndpoint(NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosServiceManager = nacosServiceManager;
this.nacosDiscoveryProperties = nacosDiscoveryProperties; this.nacosDiscoveryProperties = nacosDiscoveryProperties;
} }
...@@ -55,11 +61,17 @@ public class NacosDiscoveryEndpoint { ...@@ -55,11 +61,17 @@ public class NacosDiscoveryEndpoint {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
result.put("NacosDiscoveryProperties", nacosDiscoveryProperties); result.put("NacosDiscoveryProperties", nacosDiscoveryProperties);
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); NamingService namingService = nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties());
List<ServiceInfo> subscribe = Collections.emptyList(); List<ServiceInfo> subscribe = Collections.emptyList();
try { try {
subscribe = namingService.getSubscribeServices(); subscribe = namingService.getSubscribeServices();
for (ServiceInfo serviceInfo : subscribe) {
List<Instance> instances = namingService.getAllInstances(
serviceInfo.getName(), serviceInfo.getGroupName());
serviceInfo.setHosts(instances);
}
} }
catch (Exception e) { catch (Exception e) {
log.error("get subscribe services from nacos fail,", e); log.error("get subscribe services from nacos fail,", e);
......
...@@ -16,8 +16,11 @@ ...@@ -16,8 +16,11 @@
package com.alibaba.cloud.nacos.endpoint; package com.alibaba.cloud.nacos.endpoint;
import java.util.Properties;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.actuate.health.NacosDiscoveryHealthIndicator; import com.alibaba.cloud.nacos.discovery.actuate.health.NacosDiscoveryHealthIndicator;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
...@@ -26,7 +29,6 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint; ...@@ -26,7 +29,6 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -44,18 +46,20 @@ public class NacosDiscoveryEndpointAutoConfiguration { ...@@ -44,18 +46,20 @@ public class NacosDiscoveryEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnAvailableEndpoint @ConditionalOnAvailableEndpoint
public NacosDiscoveryEndpoint nacosDiscoveryEndpoint( public NacosDiscoveryEndpoint nacosDiscoveryEndpoint(
NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) { NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosDiscoveryEndpoint(nacosDiscoveryProperties); return new NacosDiscoveryEndpoint(nacosServiceManager, nacosDiscoveryProperties);
} }
@Bean @Bean
@ConditionalOnEnabledHealthIndicator("nacos-discovery") @ConditionalOnEnabledHealthIndicator("nacos-discovery")
public HealthIndicator nacosDiscoveryHealthIndicator( public HealthIndicator nacosDiscoveryHealthIndicator(
NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) { NacosDiscoveryProperties nacosDiscoveryProperties) {
Properties nacosProperties = nacosDiscoveryProperties.getNacosProperties();
return new NacosDiscoveryHealthIndicator( return new NacosDiscoveryHealthIndicator(
nacosDiscoveryProperties.namingServiceInstance()); nacosServiceManager.getNamingService(nacosProperties));
} }
} }
...@@ -14,31 +14,25 @@ ...@@ -14,31 +14,25 @@
* limitations under the License. * limitations under the License.
*/ */
package com.alibaba.cloud.nacos.parser; package com.alibaba.cloud.nacos.event;
import java.util.LinkedHashMap; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import java.util.Map;
import org.springframework.beans.factory.config.YamlMapFactoryBean; import org.springframework.context.ApplicationEvent;
import org.springframework.core.io.ByteArrayResource;
/** /**
* @author zkz * @author yuhuangbin
*/ */
public class NacosDataYamlParser extends AbstractNacosDataParser { public class NacosDiscoveryInfoChangedEvent extends ApplicationEvent {
public NacosDataYamlParser() { public NacosDiscoveryInfoChangedEvent(
super(",yml,yaml,"); NacosDiscoveryProperties nacosDiscoveryProperties) {
super(nacosDiscoveryProperties);
} }
@Override @Override
protected Map<String, Object> doParse(String data) { public NacosDiscoveryProperties getSource() {
YamlMapFactoryBean yamlFactory = new YamlMapFactoryBean(); return (NacosDiscoveryProperties) super.getSource();
yamlFactory.setResources(new ByteArrayResource(data.getBytes()));
Map<String, Object> result = new LinkedHashMap<>();
flattenedMap(result, yamlFactory.getObject(), EMPTY_STRING);
return result;
} }
} }
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.alibaba.cloud.nacos.registry; package com.alibaba.cloud.nacos.registry;
import com.alibaba.cloud.nacos.event.NacosDiscoveryInfoChangedEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -23,6 +24,7 @@ import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegis ...@@ -23,6 +24,7 @@ import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegis
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.event.EventListener;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -102,4 +104,14 @@ public class NacosAutoServiceRegistration ...@@ -102,4 +104,14 @@ public class NacosAutoServiceRegistration
return StringUtils.isEmpty(appName) ? super.getAppName() : appName; return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
} }
@EventListener
public void onNacosDiscoveryInfoChangedEvent(NacosDiscoveryInfoChangedEvent event) {
restart();
}
private void restart() {
this.stop();
this.start();
}
} }
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
package com.alibaba.cloud.nacos.registry; package com.alibaba.cloud.nacos.registry;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys; import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
...@@ -58,12 +58,16 @@ public class NacosRegistration implements Registration, ServiceInstance { ...@@ -58,12 +58,16 @@ public class NacosRegistration implements Registration, ServiceInstance {
*/ */
public static final String MANAGEMENT_ENDPOINT_BASE_PATH = "management.endpoints.web.base-path"; public static final String MANAGEMENT_ENDPOINT_BASE_PATH = "management.endpoints.web.base-path";
private List<NacosRegistrationCustomizer> registrationCustomizers;
private NacosDiscoveryProperties nacosDiscoveryProperties; private NacosDiscoveryProperties nacosDiscoveryProperties;
private ApplicationContext context; private ApplicationContext context;
public NacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties, public NacosRegistration(List<NacosRegistrationCustomizer> registrationCustomizers,
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) { ApplicationContext context) {
this.registrationCustomizers = registrationCustomizers;
this.nacosDiscoveryProperties = nacosDiscoveryProperties; this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.context = context; this.context = context;
} }
...@@ -105,6 +109,17 @@ public class NacosRegistration implements Registration, ServiceInstance { ...@@ -105,6 +109,17 @@ public class NacosRegistration implements Registration, ServiceInstance {
metadata.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT, metadata.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT,
nacosDiscoveryProperties.getIpDeleteTimeout().toString()); nacosDiscoveryProperties.getIpDeleteTimeout().toString());
} }
customize(registrationCustomizers, this);
}
private static void customize(
List<NacosRegistrationCustomizer> registrationCustomizers,
NacosRegistration registration) {
if (registrationCustomizers != null) {
for (NacosRegistrationCustomizer customizer : registrationCustomizers) {
customizer.customize(registration);
}
}
} }
@Override @Override
...@@ -157,10 +172,6 @@ public class NacosRegistration implements Registration, ServiceInstance { ...@@ -157,10 +172,6 @@ public class NacosRegistration implements Registration, ServiceInstance {
return nacosDiscoveryProperties; return nacosDiscoveryProperties;
} }
public NamingService getNacosNamingService() {
return nacosDiscoveryProperties.namingServiceInstance();
}
@Override @Override
public String toString() { public String toString() {
return "NacosRegistration{" + "nacosDiscoveryProperties=" return "NacosRegistration{" + "nacosDiscoveryProperties="
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.registry;
/**
* @author L.cm
*/
public interface NacosRegistrationCustomizer {
/**
* customize NacosRegistration.
* @param registration NacosRegistration
*/
void customize(NacosRegistration registration);
}
...@@ -17,8 +17,11 @@ ...@@ -17,8 +17,11 @@
package com.alibaba.cloud.nacos.registry; package com.alibaba.cloud.nacos.registry;
import java.util.List; import java.util.List;
import java.util.Properties;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -37,12 +40,20 @@ import static org.springframework.util.ReflectionUtils.rethrowRuntimeException; ...@@ -37,12 +40,20 @@ import static org.springframework.util.ReflectionUtils.rethrowRuntimeException;
*/ */
public class NacosServiceRegistry implements ServiceRegistry<Registration> { public class NacosServiceRegistry implements ServiceRegistry<Registration> {
private static final String STATUS_UP = "UP";
private static final String STATUS_DOWN = "DOWN";
private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class); private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);
private final NacosDiscoveryProperties nacosDiscoveryProperties; private final NacosDiscoveryProperties nacosDiscoveryProperties;
public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) { private final NacosServiceManager nacosServiceManager;
public NacosServiceRegistry(NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties; this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.nacosServiceManager = nacosServiceManager;
} }
@Override @Override
...@@ -65,12 +76,16 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> { ...@@ -65,12 +76,16 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
instance.getIp(), instance.getPort()); instance.getIp(), instance.getPort());
} }
catch (Exception e) { catch (Exception e) {
if (nacosDiscoveryProperties.isFailFast()) {
log.error("nacos registry, {} register failed...{},", serviceId, log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e); registration.toString(), e);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
rethrowRuntimeException(e); rethrowRuntimeException(e);
} }
else {
log.warn("Failfast is false. {} register failed...{},", serviceId,
registration.toString(), e);
}
}
} }
@Override @Override
...@@ -101,13 +116,19 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> { ...@@ -101,13 +116,19 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
@Override @Override
public void close() { public void close() {
try {
nacosServiceManager.nacosServiceShutDown();
}
catch (NacosException e) {
log.error("Nacos namingService shutDown failed", e);
}
} }
@Override @Override
public void setStatus(Registration registration, String status) { public void setStatus(Registration registration, String status) {
if (!status.equalsIgnoreCase("UP") && !status.equalsIgnoreCase("DOWN")) { if (!STATUS_UP.equalsIgnoreCase(status)
&& !STATUS_DOWN.equalsIgnoreCase(status)) {
log.warn("can't support status {},please choose UP or DOWN", status); log.warn("can't support status {},please choose UP or DOWN", status);
return; return;
} }
...@@ -116,7 +137,7 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> { ...@@ -116,7 +137,7 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
Instance instance = getNacosInstanceFromRegistration(registration); Instance instance = getNacosInstanceFromRegistration(registration);
if (status.equalsIgnoreCase("DOWN")) { if (STATUS_DOWN.equalsIgnoreCase(status)) {
instance.setEnabled(false); instance.setEnabled(false);
} }
else { else {
...@@ -124,8 +145,9 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> { ...@@ -124,8 +145,9 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
} }
try { try {
nacosDiscoveryProperties.namingMaintainServiceInstance() Properties nacosProperties = nacosDiscoveryProperties.getNacosProperties();
.updateInstance(serviceId, instance); nacosServiceManager.getNamingMaintainService(nacosProperties).updateInstance(
serviceId, nacosDiscoveryProperties.getGroup(), instance);
} }
catch (Exception e) { catch (Exception e) {
throw new RuntimeException("update nacos instance status fail", e); throw new RuntimeException("update nacos instance status fail", e);
...@@ -137,9 +159,10 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> { ...@@ -137,9 +159,10 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
public Object getStatus(Registration registration) { public Object getStatus(Registration registration) {
String serviceName = registration.getServiceId(); String serviceName = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
try { try {
List<Instance> instances = nacosDiscoveryProperties.namingServiceInstance() List<Instance> instances = namingService().getAllInstances(serviceName,
.getAllInstances(serviceName); group);
for (Instance instance : instances) { for (Instance instance : instances) {
if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp()) if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp())
&& instance.getPort() == nacosDiscoveryProperties.getPort()) { && instance.getPort() == nacosDiscoveryProperties.getPort()) {
...@@ -166,7 +189,8 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> { ...@@ -166,7 +189,8 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
} }
private NamingService namingService() { private NamingService namingService() {
return nacosDiscoveryProperties.namingServiceInstance(); return nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties());
} }
} }
...@@ -16,10 +16,14 @@ ...@@ -16,10 +16,14 @@
package com.alibaba.cloud.nacos.registry; package com.alibaba.cloud.nacos.registry;
import java.util.List;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration; import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
...@@ -47,16 +51,19 @@ public class NacosServiceRegistryAutoConfiguration { ...@@ -47,16 +51,19 @@ public class NacosServiceRegistryAutoConfiguration {
@Bean @Bean
public NacosServiceRegistry nacosServiceRegistry( public NacosServiceRegistry nacosServiceRegistry(
NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) { NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties); return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);
} }
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration( public NacosRegistration nacosRegistration(
ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
NacosDiscoveryProperties nacosDiscoveryProperties, NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) { ApplicationContext context) {
return new NacosRegistration(nacosDiscoveryProperties, context); return new NacosRegistration(registrationCustomizers.getIfAvailable(),
nacosDiscoveryProperties, context);
} }
@Bean @Bean
......
...@@ -20,14 +20,15 @@ import java.util.List; ...@@ -20,14 +20,15 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig; import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer; import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -47,6 +48,9 @@ public class NacosRule extends AbstractLoadBalancerRule { ...@@ -47,6 +48,9 @@ public class NacosRule extends AbstractLoadBalancerRule {
@Autowired @Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties; private NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired
private NacosServiceManager nacosServiceManager;
@Override @Override
public Server choose(Object key) { public Server choose(Object key) {
try { try {
...@@ -55,8 +59,8 @@ public class NacosRule extends AbstractLoadBalancerRule { ...@@ -55,8 +59,8 @@ public class NacosRule extends AbstractLoadBalancerRule {
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer(); DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
String name = loadBalancer.getName(); String name = loadBalancer.getName();
NamingService namingService = nacosDiscoveryProperties NamingService namingService = nacosServiceManager
.namingServiceInstance(); .getNamingService(nacosDiscoveryProperties.getNacosProperties());
List<Instance> instances = namingService.selectInstances(name, group, true); List<Instance> instances = namingService.selectInstances(name, group, true);
if (CollectionUtils.isEmpty(instances)) { if (CollectionUtils.isEmpty(instances)) {
LOGGER.warn("no instance in service {}", name); LOGGER.warn("no instance in service {}", name);
......
...@@ -5,6 +5,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ ...@@ -5,6 +5,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\ com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\ com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\ com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\
com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.context.ApplicationListener=\
com.alibaba.cloud.nacos.discovery.logging.NacosLoggingListener
...@@ -22,6 +22,7 @@ import java.util.LinkedList; ...@@ -22,6 +22,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Instance;
...@@ -60,16 +61,19 @@ public class NacosServiceDiscoveryTest { ...@@ -60,16 +61,19 @@ public class NacosServiceDiscoveryTest {
NacosDiscoveryProperties nacosDiscoveryProperties = mock( NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class); NacosDiscoveryProperties.class);
NacosServiceManager nacosServiceManager = mock(NacosServiceManager.class);
NamingService namingService = mock(NamingService.class); NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService); when(nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties()))
.thenReturn(namingService);
when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT"); when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT");
when(namingService.selectInstances(eq(serviceName), eq("DEFAULT"), eq(true))) when(namingService.selectInstances(eq(serviceName), eq("DEFAULT"), eq(true)))
.thenReturn(instances); .thenReturn(instances);
NacosServiceDiscovery serviceDiscovery = new NacosServiceDiscovery( NacosServiceDiscovery serviceDiscovery = new NacosServiceDiscovery(
nacosDiscoveryProperties); nacosDiscoveryProperties, nacosServiceManager);
List<ServiceInstance> serviceInstances = serviceDiscovery List<ServiceInstance> serviceInstances = serviceDiscovery
.getInstances(serviceName); .getInstances(serviceName);
...@@ -99,16 +103,19 @@ public class NacosServiceDiscoveryTest { ...@@ -99,16 +103,19 @@ public class NacosServiceDiscoveryTest {
NacosDiscoveryProperties nacosDiscoveryProperties = mock( NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class); NacosDiscoveryProperties.class);
NacosServiceManager nacosServiceManager = mock(NacosServiceManager.class);
NamingService namingService = mock(NamingService.class); NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService); when(nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties()))
.thenReturn(namingService);
when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT"); when(nacosDiscoveryProperties.getGroup()).thenReturn("DEFAULT");
when(namingService.getServicesOfServer(eq(1), eq(Integer.MAX_VALUE), when(namingService.getServicesOfServer(eq(1), eq(Integer.MAX_VALUE),
eq("DEFAULT"))).thenReturn(nacosServices); eq("DEFAULT"))).thenReturn(nacosServices);
NacosServiceDiscovery serviceDiscovery = new NacosServiceDiscovery( NacosServiceDiscovery serviceDiscovery = new NacosServiceDiscovery(
nacosDiscoveryProperties); nacosDiscoveryProperties, nacosServiceManager);
List<String> services = serviceDiscovery.getServices(); List<String> services = serviceDiscovery.getServices();
......
...@@ -22,6 +22,7 @@ import java.util.Map; ...@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration; import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration;
import com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpoint; import com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpoint;
import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.NacosFactory;
...@@ -68,9 +69,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen ...@@ -68,9 +69,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.discovery.accessKey=test-accessKey", "spring.cloud.nacos.discovery.accessKey=test-accessKey",
"spring.cloud.nacos.discovery.ip=8.8.8.8", "spring.cloud.nacos.discovery.ip=8.8.8.8",
"spring.cloud.nacos.discovery.secretKey=test-secretKey", "spring.cloud.nacos.discovery.secretKey=test-secretKey",
"spring.cloud.nacos.discovery.heart-beat-interval=3", "spring.cloud.nacos.discovery.heart-beat-interval=3000",
"spring.cloud.nacos.discovery.heart-beat-timeout=6", "spring.cloud.nacos.discovery.heart-beat-timeout=6000",
"spring.cloud.nacos.discovery.ip-delete-timeout=9" }, "spring.cloud.nacos.discovery.ip-delete-timeout=9000" },
webEnvironment = RANDOM_PORT) webEnvironment = RANDOM_PORT)
public class NacosAutoServiceRegistrationTests { public class NacosAutoServiceRegistrationTests {
...@@ -86,6 +87,9 @@ public class NacosAutoServiceRegistrationTests { ...@@ -86,6 +87,9 @@ public class NacosAutoServiceRegistrationTests {
@Autowired @Autowired
private NacosDiscoveryProperties properties; private NacosDiscoveryProperties properties;
@Autowired
private NacosServiceManager nacosServiceManager;
@Autowired @Autowired
private InetUtils inetUtils; private InetUtils inetUtils;
...@@ -182,15 +186,15 @@ public class NacosAutoServiceRegistrationTests { ...@@ -182,15 +186,15 @@ public class NacosAutoServiceRegistrationTests {
} }
private void checkoutNacosDiscoveryHeartBeatInterval() { private void checkoutNacosDiscoveryHeartBeatInterval() {
assertThat(properties.getHeartBeatInterval()).isEqualTo(Integer.valueOf(3)); assertThat(properties.getHeartBeatInterval()).isEqualTo(Integer.valueOf(3000));
} }
private void checkoutNacosDiscoveryHeartBeatTimeout() { private void checkoutNacosDiscoveryHeartBeatTimeout() {
assertThat(properties.getHeartBeatTimeout()).isEqualTo(Integer.valueOf(6)); assertThat(properties.getHeartBeatTimeout()).isEqualTo(Integer.valueOf(6000));
} }
private void checkoutNacosDiscoveryIpDeleteTimeout() { private void checkoutNacosDiscoveryIpDeleteTimeout() {
assertThat(properties.getIpDeleteTimeout()).isEqualTo(Integer.valueOf(9)); assertThat(properties.getIpDeleteTimeout()).isEqualTo(Integer.valueOf(9000));
} }
private void checkoutNacosDiscoveryServiceName() { private void checkoutNacosDiscoveryServiceName() {
...@@ -207,7 +211,7 @@ public class NacosAutoServiceRegistrationTests { ...@@ -207,7 +211,7 @@ public class NacosAutoServiceRegistrationTests {
private void checkoutEndpoint() throws Exception { private void checkoutEndpoint() throws Exception {
NacosDiscoveryEndpoint nacosDiscoveryEndpoint = new NacosDiscoveryEndpoint( NacosDiscoveryEndpoint nacosDiscoveryEndpoint = new NacosDiscoveryEndpoint(
properties); nacosServiceManager, properties);
Map<String, Object> map = nacosDiscoveryEndpoint.nacosDiscovery(); Map<String, Object> map = nacosDiscoveryEndpoint.nacosDiscovery();
assertThat(properties).isEqualTo(map.get("NacosDiscoveryProperties")); assertThat(properties).isEqualTo(map.get("NacosDiscoveryProperties"));
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.registry;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration;
import com.alibaba.nacos.api.NacosFactory;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author L.cm
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosFactory.class })
@SpringBootTest(classes = NacosRegistrationCustomizerTest.TestConfig.class,
properties = { "spring.application.name=myTestService1",
"spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848" },
webEnvironment = RANDOM_PORT)
public class NacosRegistrationCustomizerTest {
@Autowired
private NacosAutoServiceRegistration nacosAutoServiceRegistration;
static {
try {
Method method = PowerMockito.method(NacosFactory.class, "createNamingService",
Properties.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return new MockNamingService();
}
});
}
catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void contextLoads() throws Exception {
NacosRegistration registration = nacosAutoServiceRegistration.getRegistration();
Map<String, String> metadata = registration.getMetadata();
Assert.assertEquals("test1", metadata.get("test1"));
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
NacosDiscoveryClientConfiguration.class,
NacosServiceRegistryAutoConfiguration.class })
public static class TestConfig {
@Bean
public NacosRegistrationCustomizer nacosRegistrationCustomizer() {
return registration -> {
Map<String, String> metadata = registration.getMetadata();
metadata.put("test1", "test1");
};
}
}
}
...@@ -40,7 +40,8 @@ import org.springframework.test.context.junit4.SpringRunner; ...@@ -40,7 +40,8 @@ import org.springframework.test.context.junit4.SpringRunner;
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosRibbonClientPropertyOverrideTests.TestConfiguration.class, @SpringBootTest(classes = NacosRibbonClientPropertyOverrideTests.TestConfiguration.class,
properties = { "spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848", properties = { "spring.cloud.nacos.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.username=nacos", "spring.cloud.nacos.password=nacos",
"spring.cloud.nacos.discovery.port=18080", "spring.cloud.nacos.discovery.port=18080",
"spring.cloud.nacos.discovery.service=remoteApp", "spring.cloud.nacos.discovery.service=remoteApp",
"localApp.ribbon.NIWSServerListClassName=" "localApp.ribbon.NIWSServerListClassName="
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -37,7 +37,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties ...@@ -37,7 +37,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** /**
...@@ -66,23 +65,6 @@ public class SentinelWebAutoConfiguration implements WebMvcConfigurer { ...@@ -66,23 +65,6 @@ public class SentinelWebAutoConfiguration implements WebMvcConfigurer {
@Autowired @Autowired
private Optional<RequestOriginParser> requestOriginParserOptional; private Optional<RequestOriginParser> requestOriginParserOptional;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (!sentinelWebInterceptorOptional.isPresent()) {
return;
}
SentinelProperties.Filter filterConfig = properties.getFilter();
registry.addInterceptor(sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info(
"[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.",
filterConfig.getUrlPatterns());
}
@Bean @Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", @ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled",
matchIfMissing = true) matchIfMissing = true)
...@@ -122,4 +104,11 @@ public class SentinelWebAutoConfiguration implements WebMvcConfigurer { ...@@ -122,4 +104,11 @@ public class SentinelWebAutoConfiguration implements WebMvcConfigurer {
return sentinelWebMvcConfig; return sentinelWebMvcConfig;
} }
@Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled",
matchIfMissing = true)
public SentinelWebMvcConfigurer sentinelWebMvcConfigurer() {
return new SentinelWebMvcConfigurer();
}
} }
...@@ -14,53 +14,44 @@ ...@@ -14,53 +14,44 @@
* limitations under the License. * limitations under the License.
*/ */
package com.alibaba.cloud.nacos.parser; package com.alibaba.cloud.sentinel;
import java.io.BufferedReader; import java.util.Optional;
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedHashMap;
import java.util.Map;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** /**
* @author zkz * @author: chao.wu
*/ */
public class NacosDataPropertiesParser extends AbstractNacosDataParser { public class SentinelWebMvcConfigurer implements WebMvcConfigurer {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(NacosDataPropertiesParser.class); .getLogger(SentinelWebMvcConfigurer.class);
public NacosDataPropertiesParser() { @Autowired
super("properties"); private SentinelProperties sentinelProperties;
}
@Override @Autowired
protected Map<String, Object> doParse(String data) throws IOException { private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
Map<String, Object> result = new LinkedHashMap<>();
try (BufferedReader reader = new BufferedReader(new StringReader(data))) { @Override
for (String line = reader.readLine(); line != null; line = reader public void addInterceptors(InterceptorRegistry registry) {
.readLine()) { if (!sentinelWebInterceptorOptional.isPresent()) {
String dataLine = line.trim(); return;
if (StringUtils.isEmpty(dataLine) || dataLine.startsWith("#")) {
continue;
}
int index = dataLine.indexOf("=");
if (index == -1) {
log.warn("the config data is invalid {}", dataLine);
continue;
}
String key = dataLine.substring(0, index);
String value = dataLine.substring(index + 1);
result.put(key.trim(), value.trim());
}
} }
return result; SentinelProperties.Filter filterConfig = sentinelProperties.getFilter();
registry.addInterceptor(sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info(
"[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.",
filterConfig.getUrlPatterns());
} }
} }
...@@ -86,13 +86,23 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor ...@@ -86,13 +86,23 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
Tracer.trace( Tracer.trace(
new IllegalStateException("RestTemplate ErrorHandler has error")); new IllegalStateException("RestTemplate ErrorHandler has error"));
} }
return response;
} }
catch (Throwable e) { catch (Throwable e) {
if (!BlockException.isBlockException(e)) { if (BlockException.isBlockException(e)) {
Tracer.trace(e); return handleBlockException(request, body, execution, (BlockException) e);
} }
else { else {
return handleBlockException(request, body, execution, (BlockException) e); Tracer.traceEntry(e, hostEntry);
if (e instanceof IOException) {
throw (IOException) e;
}
else if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
else {
throw new IOException(e);
}
} }
} }
finally { finally {
...@@ -103,7 +113,6 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor ...@@ -103,7 +113,6 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
hostEntry.exit(); hostEntry.exit();
} }
} }
return response;
} }
private ClientHttpResponse handleBlockException(HttpRequest request, byte[] body, private ClientHttpResponse handleBlockException(HttpRequest request, byte[] body,
......
...@@ -25,7 +25,7 @@ import com.alibaba.csp.sentinel.datasource.AbstractDataSource; ...@@ -25,7 +25,7 @@ import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider; import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
import com.alibaba.csp.sentinel.transport.HeartbeatSender; import com.alibaba.csp.sentinel.transport.HeartbeatSender;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.function.Tuple2; import com.alibaba.csp.sentinel.transport.endpoint.Endpoint;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.AbstractHealthIndicator;
...@@ -84,8 +84,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator { ...@@ -84,8 +84,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
// Check health of Dashboard // Check health of Dashboard
boolean dashboardUp = true; boolean dashboardUp = true;
List<Tuple2<String, Integer>> consoleServerList = TransportConfig List<Endpoint> consoleServerList = TransportConfig.getConsoleServerList();
.getConsoleServerList();
if (CollectionUtils.isEmpty(consoleServerList)) { if (CollectionUtils.isEmpty(consoleServerList)) {
// If Dashboard isn't configured, it's OK and mark the status of Dashboard // If Dashboard isn't configured, it's OK and mark the status of Dashboard
// with UNKNOWN. // with UNKNOWN.
...@@ -105,7 +104,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator { ...@@ -105,7 +104,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
// If failed to send heartbeat message, means that the Dashboard is DOWN // If failed to send heartbeat message, means that the Dashboard is DOWN
dashboardUp = false; dashboardUp = false;
detailMap.put("dashboard", detailMap.put("dashboard",
new Status(Status.DOWN.getCode(), String.format( new Status(Status.UNKNOWN.getCode(), String.format(
"the dashboard servers [%s] one of them can't be connected", "the dashboard servers [%s] one of them can't be connected",
consoleServerList))); consoleServerList)));
} }
...@@ -138,7 +137,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator { ...@@ -138,7 +137,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
// DOWN // DOWN
dataSourceUp = false; dataSourceUp = false;
dataSourceDetailMap.put(dataSourceBeanName, dataSourceDetailMap.put(dataSourceBeanName,
new Status(Status.DOWN.getCode(), e.getMessage())); new Status(Status.UNKNOWN.getCode(), e.getMessage()));
} }
} }
...@@ -147,7 +146,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator { ...@@ -147,7 +146,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
builder.up().withDetails(detailMap); builder.up().withDetails(detailMap);
} }
else { else {
builder.down().withDetails(detailMap); builder.unknown().withDetails(detailMap);
} }
} }
......
...@@ -80,25 +80,27 @@ public final class SentinelFeign { ...@@ -80,25 +80,27 @@ public final class SentinelFeign {
// using reflect get fallback and fallbackFactory properties from // using reflect get fallback and fallbackFactory properties from
// FeignClientFactoryBean because FeignClientFactoryBean is a package // FeignClientFactoryBean because FeignClientFactoryBean is a package
// level class, we can not use it in our package // level class, we can not use it in our package
Object feignClientFactoryBean = Builder.this.applicationContext Object feignClientFactoryBean = SentinelTargeterAspect
.getBean("&" + target.type().getName()); .getFeignClientFactoryBean();
if (feignClientFactoryBean != null) {
Class fallback = (Class) getFieldValue(feignClientFactoryBean, Class fallback = (Class) getFieldValue(feignClientFactoryBean,
"fallback"); "fallback");
Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean, Class fallbackFactory = (Class) getFieldValue(
"fallbackFactory"); feignClientFactoryBean, "fallbackFactory");
String beanName = (String) getFieldValue(feignClientFactoryBean, String beanName = (String) getFieldValue(feignClientFactoryBean,
"contextId"); "contextId");
if (!StringUtils.hasText(beanName)) { if (!StringUtils.hasText(beanName)) {
beanName = (String) getFieldValue(feignClientFactoryBean, "name"); beanName = (String) getFieldValue(feignClientFactoryBean,
"name");
} }
Object fallbackInstance; Object fallbackInstance;
FallbackFactory fallbackFactoryInstance; FallbackFactory fallbackFactoryInstance;
// check fallback and fallbackFactory properties // check fallback and fallbackFactory properties
if (void.class != fallback) { if (void.class != fallback) {
fallbackInstance = getFromContext(beanName, "fallback", fallback, fallbackInstance = getFromContext(beanName, "fallback",
target.type()); fallback, target.type());
return new SentinelInvocationHandler(target, dispatch, return new SentinelInvocationHandler(target, dispatch,
new FallbackFactory.Default(fallbackInstance)); new FallbackFactory.Default(fallbackInstance));
} }
...@@ -109,6 +111,7 @@ public final class SentinelFeign { ...@@ -109,6 +111,7 @@ public final class SentinelFeign {
return new SentinelInvocationHandler(target, dispatch, return new SentinelInvocationHandler(target, dispatch,
fallbackFactoryInstance); fallbackFactoryInstance);
} }
}
return new SentinelInvocationHandler(target, dispatch); return new SentinelInvocationHandler(target, dispatch);
} }
......
...@@ -41,4 +41,11 @@ public class SentinelFeignAutoConfiguration { ...@@ -41,4 +41,11 @@ public class SentinelFeignAutoConfiguration {
return SentinelFeign.builder(); return SentinelFeign.builder();
} }
@Bean
@ConditionalOnProperty(name = "feign.sentinel.enabled")
@ConditionalOnClass(name = "org.springframework.cloud.openfeign.Targeter")
public SentinelTargeterAspect sentinelTargeterAspect() {
return new SentinelTargeterAspect();
}
} }
...@@ -109,7 +109,7 @@ public class SentinelInvocationHandler implements InvocationHandler { ...@@ -109,7 +109,7 @@ public class SentinelInvocationHandler implements InvocationHandler {
catch (Throwable ex) { catch (Throwable ex) {
// fallback handle // fallback handle
if (!BlockException.isBlockException(ex)) { if (!BlockException.isBlockException(ex)) {
Tracer.trace(ex); Tracer.traceEntry(ex, entry);
} }
if (fallbackFactory != null) { if (fallbackFactory != null) {
try { try {
......
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.sentinel.feign;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
/**
* Record FeignClientFactoryBean to threadlocal, so that SentinelFeign can get it when
* creating SentinelInvocationHandler.
*
* @see com.alibaba.cloud.sentinel.feign.SentinelFeign.Builder
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
@Aspect
public class SentinelTargeterAspect {
private static final ThreadLocal<Object> FEIGN_CLIENT_FACTORY_BEAN = new ThreadLocal<>();
public static Object getFeignClientFactoryBean() {
return FEIGN_CLIENT_FACTORY_BEAN.get();
}
@Around("execution(* org.springframework.cloud.openfeign.Targeter.target(..))")
public Object process(ProceedingJoinPoint pjp) throws Throwable {
Object factory = pjp.getArgs()[0];
try {
FEIGN_CLIENT_FACTORY_BEAN.set(factory);
return pjp.proceed();
}
finally {
FEIGN_CLIENT_FACTORY_BEAN.remove();
}
}
}
...@@ -31,7 +31,8 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant; ...@@ -31,7 +31,8 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.function.Tuple2; import com.alibaba.csp.sentinel.transport.endpoint.Endpoint;
import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -134,8 +135,10 @@ public class SentinelAutoConfigurationTests { ...@@ -134,8 +135,10 @@ public class SentinelAutoConfigurationTests {
Map<String, Object> map = sentinelEndpoint.invoke(); Map<String, Object> map = sentinelEndpoint.invoke();
assertThat(map.get("logUsePid")).isEqualTo(Boolean.TRUE); assertThat(map.get("logUsePid")).isEqualTo(Boolean.TRUE);
assertThat(map.get("consoleServer").toString()).isEqualTo( assertThat(map.get("consoleServer").toString())
Arrays.asList(Tuple2.of("localhost", 8080), Tuple2.of("localhost", 8081)) .isEqualTo(Arrays
.asList(new Endpoint(Protocol.HTTP, "localhost", 8080),
new Endpoint(Protocol.HTTP, "localhost", 8081))
.toString()); .toString());
assertThat(map.get("clientPort")).isEqualTo("9999"); assertThat(map.get("clientPort")).isEqualTo("9999");
assertThat(map.get("heartbeatIntervalMs")).isEqualTo(20000L); assertThat(map.get("heartbeatIntervalMs")).isEqualTo(20000L);
...@@ -185,8 +188,10 @@ public class SentinelAutoConfigurationTests { ...@@ -185,8 +188,10 @@ public class SentinelAutoConfigurationTests {
@Test @Test
public void testSentinelSystemProperties() { public void testSentinelSystemProperties() {
assertThat(LogBase.isLogNameUsePid()).isEqualTo(true); assertThat(LogBase.isLogNameUsePid()).isEqualTo(true);
assertThat(TransportConfig.getConsoleServerList().toString()).isEqualTo( assertThat(TransportConfig.getConsoleServerList().toString())
Arrays.asList(Tuple2.of("localhost", 8080), Tuple2.of("localhost", 8081)) .isEqualTo(Arrays
.asList(new Endpoint(Protocol.HTTP, "localhost", 8080),
new Endpoint(Protocol.HTTP, "localhost", 8081))
.toString()); .toString());
assertThat(TransportConfig.getPort()).isEqualTo("9999"); assertThat(TransportConfig.getPort()).isEqualTo("9999");
assertThat(TransportConfig.getHeartbeatIntervalMs().longValue()) assertThat(TransportConfig.getHeartbeatIntervalMs().longValue())
......
...@@ -109,9 +109,9 @@ public class SentinelHealthIndicatorTests { ...@@ -109,9 +109,9 @@ public class SentinelHealthIndicatorTests {
Health health = sentinelHealthIndicator.health(); Health health = sentinelHealthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
assertThat(health.getDetails().get("dashboard")).isEqualTo( assertThat(health.getDetails().get("dashboard")).isEqualTo(new Status(
new Status(Status.DOWN.getCode(), "localhost:8080 can't be connected")); Status.UNKNOWN.getCode(), "localhost:8080 can't be connected"));
} }
@Test @Test
...@@ -163,13 +163,13 @@ public class SentinelHealthIndicatorTests { ...@@ -163,13 +163,13 @@ public class SentinelHealthIndicatorTests {
Health health = sentinelHealthIndicator.health(); Health health = sentinelHealthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
Map<String, Status> dataSourceDetailMap = (Map<String, Status>) health Map<String, Status> dataSourceDetailMap = (Map<String, Status>) health
.getDetails().get("dataSource"); .getDetails().get("dataSource");
assertThat(dataSourceDetailMap.get("ds1-sentinel-file-datasource")) assertThat(dataSourceDetailMap.get("ds1-sentinel-file-datasource"))
.isEqualTo(Status.UP); .isEqualTo(Status.UP);
assertThat(dataSourceDetailMap.get("ds2-sentinel-file-datasource")) assertThat(dataSourceDetailMap.get("ds2-sentinel-file-datasource"))
.isEqualTo(new Status(Status.DOWN.getCode(), "fileDataSource2 error")); .isEqualTo(new Status(Status.UNKNOWN.getCode(), "fileDataSource2 error"));
} }
} }
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId>
<version>2.2.8-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-timeloit-commons</artifactId>
<name>Spring Cloud Timeloit Commons</name>
</project>
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.commons.io;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* The Charsets constants, copy from apache commons-io.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public final class Charsets {
private Charsets() {
}
/**
* Constructs a sorted map from canonical charset names to charset objects required of
* every implementation of the Java platform.
* <p>
* From the Java documentation
* <a href="https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">
* Standard charsets</a>:
* </p>
* @return An immutable, case-insensitive map from canonical charset names to charset
* objects.
* @see Charset#availableCharsets()
*/
public static SortedMap<String, Charset> requiredCharsets() {
// maybe cache?
final TreeMap<String, Charset> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put(StandardCharsets.ISO_8859_1.name(), StandardCharsets.ISO_8859_1);
m.put(StandardCharsets.US_ASCII.name(), StandardCharsets.US_ASCII);
m.put(StandardCharsets.UTF_16.name(), StandardCharsets.UTF_16);
m.put(StandardCharsets.UTF_16BE.name(), StandardCharsets.UTF_16BE);
m.put(StandardCharsets.UTF_16LE.name(), StandardCharsets.UTF_16LE);
m.put(StandardCharsets.UTF_8.name(), StandardCharsets.UTF_8);
return Collections.unmodifiableSortedMap(m);
}
/**
* Returns the given Charset or the default Charset if the given Charset is null.
* @param charset A charset or null.
* @return the given Charset or the default Charset if the given Charset is null
*/
public static Charset toCharset(final Charset charset) {
return charset == null ? Charset.defaultCharset() : charset;
}
/**
* Returns a Charset for the named charset. If the name is null, return the default
* Charset.
* @param charset The name of the requested charset, may be null.
* @return a Charset for the named charset
* @throws java.nio.charset.UnsupportedCharsetException If the named charset is
* unavailable
*/
public static Charset toCharset(final String charset) {
return charset == null ? Charset.defaultCharset() : Charset.forName(charset);
}
/**
* CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
* <p>
* Every implementation of the Java platform is required to support this character
* encoding.
* </p>
*
* @see <a href=
* "https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>
* @deprecated Use Java 7's {@link StandardCharsets}
*/
@Deprecated
public static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
/**
* <p>
* Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of
* the Unicode character set.
* </p>
* <p>
* Every implementation of the Java platform is required to support this character
* encoding.
* </p>
*
* @see <a href=
* "https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>
* @deprecated Use Java 7's {@link StandardCharsets}
*/
@Deprecated
public static final Charset US_ASCII = StandardCharsets.US_ASCII;
/**
* <p>
* Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory
* initial byte-order mark (either order accepted on input, big-endian used on output)
* </p>
* <p>
* Every implementation of the Java platform is required to support this character
* encoding.
* </p>
*
* @see <a href=
* "https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>
* @deprecated Use Java 7's {@link StandardCharsets}
*/
@Deprecated
public static final Charset UTF_16 = StandardCharsets.UTF_16;
/**
* <p>
* Sixteen-bit Unicode Transformation Format, big-endian byte order.
* </p>
* <p>
* Every implementation of the Java platform is required to support this character
* encoding.
* </p>
*
* @see <a href=
* "https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>
* @deprecated Use Java 7's {@link StandardCharsets}
*/
@Deprecated
public static final Charset UTF_16BE = StandardCharsets.UTF_16BE;
/**
* <p>
* Sixteen-bit Unicode Transformation Format, little-endian byte order.
* </p>
* <p>
* Every implementation of the Java platform is required to support this character
* encoding.
* </p>
*
* @see <a href=
* "https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>
* @deprecated Use Java 7's {@link StandardCharsets}
*/
@Deprecated
public static final Charset UTF_16LE = StandardCharsets.UTF_16LE;
/**
* <p>
* Eight-bit Unicode Transformation Format.
* </p>
* <p>
* Every implementation of the Java platform is required to support this character
* encoding.
* </p>
*
* @see <a href=
* "https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard
* charsets</a>
* @deprecated Use Java 7's {@link StandardCharsets}
*/
@Deprecated
public static final Charset UTF_8 = StandardCharsets.UTF_8;
}
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.commons.io;
import java.io.*;
import java.nio.charset.Charset;
/**
* FileUtils. copy from apache commons-io.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public final class FileUtils {
private FileUtils() {
}
// -----------------------------------------------------------------------
/**
* Opens a {@link FileInputStream} for the specified file, providing better
* error messages than simply calling <code>new FileInputStream(file)</code>.
* <p>
* At the end of the method either the stream will be successfully opened, or an
* exception will have been thrown.
* <p>
* An exception is thrown if the file does not exist. An exception is thrown if the
* file object exists but is a directory. An exception is thrown if the file exists
* but cannot be read.
* @param file the file to open for input, must not be {@code null}
* @return a new {@link FileInputStream} for the specified file
* @throws FileNotFoundException if the file does not exist
* @throws IOException if the file object is a directory
* @throws IOException if the file cannot be read
* @since 1.3
*/
public static FileInputStream openInputStream(final File file) throws IOException {
if (file.exists()) {
if (file.isDirectory()) {
throw new IOException("File '" + file + "' exists but is a directory");
}
if (!file.canRead()) {
throw new IOException("File '" + file + "' cannot be read");
}
}
else {
throw new FileNotFoundException("File '" + file + "' does not exist");
}
return new FileInputStream(file);
}
// -----------------------------------------------------------------------
/**
* Reads the contents of a file into a String. The file is always closed.
* @param file the file to read, must not be {@code null}
* @param encoding the encoding to use, {@code null} means platform default
* @return the file contents, never {@code null}
* @throws IOException in case of an I/O error
*/
public static String readFileToString(final File file, final Charset encoding)
throws IOException {
try (InputStream in = openInputStream(file)) {
return IOUtils.toString(in, Charsets.toCharset(encoding));
}
}
/**
* Reads the contents of a file into a String. The file is always closed.
* @param file the file to read, must not be {@code null}
* @param encoding the encoding to use, {@code null} means platform default
* @return the file contents, never {@code null}
* @throws IOException in case of an I/O error
* @throws java.nio.charset.UnsupportedCharsetException thrown instead of
* {@link java.io .UnsupportedEncodingException} in version 2.2 if the encoding is not
* supported.
*/
public static String readFileToString(final File file, final String encoding)
throws IOException {
return readFileToString(file, Charsets.toCharset(encoding));
}
/**
* Reads the contents of a file into a String using the default encoding for the VM.
* The file is always closed.
* @param file the file to read, must not be {@code null}
* @return the file contents, never {@code null}
* @throws IOException in case of an I/O error
* @deprecated 2.5 use {@link #readFileToString(File, String)} instead (and specify
* the appropriate encoding)
*/
@Deprecated
public static String readFileToString(final File file) throws IOException {
return readFileToString(file, Charset.defaultCharset());
}
}
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.commons.io;
import java.io.*;
import java.nio.charset.Charset;
/**
* The IOUtils. copy from apache commons-io.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public final class IOUtils {
/**
* Represents the end-of-file (or stream).
* @since 2.5 (made public)
*/
public static final int EOF = -1;
/**
* The default buffer size ({@value}) to use for.
* {@link #copyLarge(InputStream, OutputStream)} and
* {@link #copyLarge(Reader, Writer)}
*/
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
private IOUtils() {
}
/**
* Gets the contents of an <code>InputStream</code> as a String using the specified
* character encoding.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
* </p>
* @param input the <code>InputStream</code> to read from
* @param encoding the encoding to use, null means platform default
* @return the requested String
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
* @since 2.3
*/
public static String toString(final InputStream input, final Charset encoding)
throws IOException {
try (StringBuilderWriter sw = new StringBuilderWriter()) {
copy(input, sw, encoding);
return sw.toString();
}
}
// copy from Reader
// -----------------------------------------------------------------------
/**
* Copies chars from a <code>Reader</code> to a <code>Writer</code>.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>.
* <p>
* Large streams (over 2GB) will return a chars copied value of <code>-1</code> after
* the copy has completed since the correct number of chars cannot be returned as an
* int. For large streams use the <code>copyLarge(Reader, Writer)</code> method.
* @param input the <code>Reader</code> to read from
* @param output the <code>Writer</code> to write to
* @return the number of characters copied, or -1 if &gt; Integer.MAX_VALUE
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 1.1
*/
public static int copy(final Reader input, final Writer output) throws IOException {
final long count = copyLarge(input, output);
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
/**
* Copies bytes from an <code>InputStream</code> to chars on a <code>Writer</code>
* using the specified character encoding.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
* <p>
* This method uses {@link InputStreamReader}.
* @param input the <code>InputStream</code> to read from
* @param output the <code>Writer</code> to write to
* @param inputEncoding the encoding to use for the input stream, null means platform
* default
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.3
*/
public static void copy(final InputStream input, final Writer output,
final Charset inputEncoding) throws IOException {
final InputStreamReader in = new InputStreamReader(input,
Charsets.toCharset(inputEncoding));
copy(in, output);
}
/**
* Copies bytes from an <code>InputStream</code> to an <code>OutputStream</code> using
* an internal buffer of the given size.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
* <p>
* @param input the <code>InputStream</code> to read from
* @param output the <code>OutputStream</code> to write to
* @param bufferSize the bufferSize used to copy from the input to the output
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.5
*/
public static long copy(final InputStream input, final OutputStream output,
final int bufferSize) throws IOException {
return copyLarge(input, output, new byte[bufferSize]);
}
/**
* Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>.
* <p>
* The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
* @param input the <code>Reader</code> to read from
* @param output the <code>Writer</code> to write to
* @return the number of characters copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 1.3
*/
public static long copyLarge(final Reader input, final Writer output)
throws IOException {
return copyLarge(input, output, new char[DEFAULT_BUFFER_SIZE]);
}
/**
* Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
* <p>
* This method uses the provided buffer, so there is no need to use a
* <code>BufferedReader</code>.
* <p>
* @param input the <code>Reader</code> to read from
* @param output the <code>Writer</code> to write to
* @param buffer the buffer to be used for the copy
* @return the number of characters copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.2
*/
public static long copyLarge(final Reader input, final Writer output,
final char[] buffer) throws IOException {
long count = 0;
int n;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
/**
* Copies bytes from a large (over 2GB) <code>InputStream</code> to an
* <code>OutputStream</code>.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
* <p>
* The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
* @param input the <code>InputStream</code> to read from
* @param output the <code>OutputStream</code> to write to
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 1.3
*/
public static long copyLarge(final InputStream input, final OutputStream output)
throws IOException {
return copy(input, output, DEFAULT_BUFFER_SIZE);
}
/**
* Copies bytes from a large (over 2GB) <code>InputStream</code> to an
* <code>OutputStream</code>.
* <p>
* This method uses the provided buffer, so there is no need to use a
* <code>BufferedInputStream</code>.
* <p>
* @param input the <code>InputStream</code> to read from
* @param output the <code>OutputStream</code> to write to
* @param buffer the buffer to use for the copy
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.2
*/
public static long copyLarge(final InputStream input, final OutputStream output,
final byte[] buffer) throws IOException {
long count = 0;
int n;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
}
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.commons.io;
import java.io.Serializable;
import java.io.Writer;
/**
* Copy from apache commons-io.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public class StringBuilderWriter extends Writer implements Serializable {
private static final long serialVersionUID = -146927496096066153L;
private final StringBuilder builder;
/**
* Constructs a new {@link StringBuilder} instance with default capacity.
*/
public StringBuilderWriter() {
this.builder = new StringBuilder();
}
/**
* Constructs a new {@link StringBuilder} instance with the specified capacity.
* @param capacity The initial capacity of the underlying {@link StringBuilder}
*/
public StringBuilderWriter(final int capacity) {
this.builder = new StringBuilder(capacity);
}
/**
* Constructs a new instance with the specified {@link StringBuilder}.
*
* <p>
* If {@code builder} is null a new instance with default capacity will be created.
* </p>
* @param builder The String builder. May be null.
*/
public StringBuilderWriter(final StringBuilder builder) {
this.builder = builder != null ? builder : new StringBuilder();
}
/**
* Appends a single character to this Writer.
* @param value The character to append
* @return This writer instance
*/
@Override
public Writer append(final char value) {
builder.append(value);
return this;
}
/**
* Appends a character sequence to this Writer.
* @param value The character to append
* @return This writer instance
*/
@Override
public Writer append(final CharSequence value) {
builder.append(value);
return this;
}
/**
* Appends a portion of a character sequence to the {@link StringBuilder}.
* @param value The character to append
* @param start The index of the first character
* @param end The index of the last character + 1
* @return This writer instance
*/
@Override
public Writer append(final CharSequence value, final int start, final int end) {
builder.append(value, start, end);
return this;
}
/**
* Closing this writer has no effect.
*/
@Override
public void close() {
// no-op
}
/**
* Flushing this writer has no effect.
*/
@Override
public void flush() {
// no-op
}
/**
* Writes a String to the {@link StringBuilder}.
* @param value The value to write
*/
@Override
public void write(final String value) {
if (value != null) {
builder.append(value);
}
}
/**
* Writes a portion of a character array to the {@link StringBuilder}.
* @param value The value to write
* @param offset The index of the first character
* @param length The number of characters to write
*/
@Override
public void write(final char[] value, final int offset, final int length) {
if (value != null) {
builder.append(value, offset, length);
}
}
/**
* Returns the underlying builder.
* @return The underlying builder
*/
public StringBuilder getBuilder() {
return builder;
}
/**
* Returns {@link StringBuilder#toString()}.
* @return The contents of the String builder.
*/
@Override
public String toString() {
return builder.toString();
}
}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
<dependencies> <dependencies>
<dependency>
<groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-timeloit-commons</artifactId>
</dependency>
<!--spring boot --> <!--spring boot -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
......
...@@ -132,7 +132,6 @@ public class DataSourcePropertiesConfiguration { ...@@ -132,7 +132,6 @@ public class DataSourcePropertiesConfiguration {
if (!ObjectUtils.isEmpty(field.get(this))) { if (!ObjectUtils.isEmpty(field.get(this))) {
return field.getName(); return field.getName();
} }
return null;
} }
catch (IllegalAccessException e) { catch (IllegalAccessException e) {
// won't happen // won't happen
......
...@@ -32,6 +32,8 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { ...@@ -32,6 +32,8 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
private String serverAddr; private String serverAddr;
private String contextPath;
private String username; private String username;
private String password; private String password;
...@@ -71,6 +73,14 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { ...@@ -71,6 +73,14 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
this.serverAddr = serverAddr; this.serverAddr = serverAddr;
} }
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getUsername() { public String getUsername() {
return username; return username;
} }
......
...@@ -86,9 +86,8 @@ public abstract class SentinelConverter<T extends Object> ...@@ -86,9 +86,8 @@ public abstract class SentinelConverter<T extends Object>
}); });
for (Object obj : sourceArray) { for (Object obj : sourceArray) {
String item = null;
try { try {
item = objectMapper.writeValueAsString(obj); String item = objectMapper.writeValueAsString(obj);
Optional.ofNullable(convertRule(item)) Optional.ofNullable(convertRule(item))
.ifPresent(convertRule -> ruleCollection.add(convertRule)); .ifPresent(convertRule -> ruleCollection.add(convertRule));
} }
......
...@@ -35,6 +35,8 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> ...@@ -35,6 +35,8 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
private String serverAddr; private String serverAddr;
private String contextPath;
private String username; private String username;
private String password; private String password;
...@@ -60,22 +62,27 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> ...@@ -60,22 +62,27 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr); properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr);
} }
else { else {
properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
}
if (!StringUtils.isEmpty(this.contextPath)) {
properties.setProperty(PropertyKeyConst.CONTEXT_PATH, this.contextPath);
}
if (!StringUtils.isEmpty(this.accessKey)) {
properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey); properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey);
}
if (!StringUtils.isEmpty(this.secretKey)) {
properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey); properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey);
properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
} }
if (!StringUtils.isEmpty(this.namespace)) { if (!StringUtils.isEmpty(this.namespace)) {
properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace); properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace);
} }
if (!StringUtils.isEmpty(this.username)) { if (!StringUtils.isEmpty(this.username)) {
properties.setProperty(PropertyKeyConst.USERNAME, this.username); properties.setProperty(PropertyKeyConst.USERNAME, this.username);
} }
if (!StringUtils.isEmpty(this.password)) { if (!StringUtils.isEmpty(this.password)) {
properties.setProperty(PropertyKeyConst.PASSWORD, this.password); properties.setProperty(PropertyKeyConst.PASSWORD, this.password);
} }
return new NacosDataSource(properties, groupId, dataId, converter); return new NacosDataSource(properties, groupId, dataId, converter);
} }
...@@ -92,6 +99,14 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> ...@@ -92,6 +99,14 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
this.serverAddr = serverAddr; this.serverAddr = serverAddr;
} }
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getUsername() { public String getUsername() {
return username; return username;
} }
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
package com.alibaba.cloud.sentinel.datasource.factorybean; package com.alibaba.cloud.sentinel.datasource.factorybean;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource; import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBean;
......
...@@ -39,6 +39,8 @@ public class NacosDataSourceFactoryBeanTests { ...@@ -39,6 +39,8 @@ public class NacosDataSourceFactoryBeanTests {
private String serverAddr = "localhost:8848"; private String serverAddr = "localhost:8848";
private String contextPath = "/my-nacos";
private String accessKey = "ak"; private String accessKey = "ak";
private String secretKey = "sk"; private String secretKey = "sk";
...@@ -56,6 +58,7 @@ public class NacosDataSourceFactoryBeanTests { ...@@ -56,6 +58,7 @@ public class NacosDataSourceFactoryBeanTests {
factoryBean.setDataId(dataId); factoryBean.setDataId(dataId);
factoryBean.setGroupId(groupId); factoryBean.setGroupId(groupId);
factoryBean.setServerAddr(serverAddr); factoryBean.setServerAddr(serverAddr);
factoryBean.setContextPath(contextPath);
factoryBean.setConverter(converter); factoryBean.setConverter(converter);
NacosDataSource nacosDataSource = mock(NacosDataSource.class); NacosDataSource nacosDataSource = mock(NacosDataSource.class);
...@@ -69,6 +72,7 @@ public class NacosDataSourceFactoryBeanTests { ...@@ -69,6 +72,7 @@ public class NacosDataSourceFactoryBeanTests {
assertThat(factoryBean.getDataId()).isEqualTo(dataId); assertThat(factoryBean.getDataId()).isEqualTo(dataId);
assertThat(factoryBean.getGroupId()).isEqualTo(groupId); assertThat(factoryBean.getGroupId()).isEqualTo(groupId);
assertThat(factoryBean.getServerAddr()).isEqualTo(serverAddr); assertThat(factoryBean.getServerAddr()).isEqualTo(serverAddr);
assertThat(factoryBean.getContextPath()).isEqualTo(contextPath);
} }
@Test @Test
......
...@@ -31,11 +31,13 @@ public class NacosDataSourcePropertiesTests { ...@@ -31,11 +31,13 @@ public class NacosDataSourcePropertiesTests {
public void testNacosWithAddr() { public void testNacosWithAddr() {
NacosDataSourceProperties nacosDataSourceProperties = new NacosDataSourceProperties(); NacosDataSourceProperties nacosDataSourceProperties = new NacosDataSourceProperties();
nacosDataSourceProperties.setServerAddr("127.0.0.1:8848"); nacosDataSourceProperties.setServerAddr("127.0.0.1:8848");
nacosDataSourceProperties.setContextPath("/my-nacos");
nacosDataSourceProperties.setRuleType(RuleType.FLOW); nacosDataSourceProperties.setRuleType(RuleType.FLOW);
nacosDataSourceProperties.setDataId("sentinel"); nacosDataSourceProperties.setDataId("sentinel");
nacosDataSourceProperties.setGroupId("custom-group"); nacosDataSourceProperties.setGroupId("custom-group");
nacosDataSourceProperties.setDataType("xml"); nacosDataSourceProperties.setDataType("xml");
assertThat(nacosDataSourceProperties.getContextPath()).isEqualTo("/my-nacos");
assertThat(nacosDataSourceProperties.getGroupId()).isEqualTo("custom-group"); assertThat(nacosDataSourceProperties.getGroupId()).isEqualTo("custom-group");
assertThat(nacosDataSourceProperties.getDataId()).isEqualTo("sentinel"); assertThat(nacosDataSourceProperties.getDataId()).isEqualTo("sentinel");
assertThat(nacosDataSourceProperties.getDataType()).isEqualTo("xml"); assertThat(nacosDataSourceProperties.getDataType()).isEqualTo("xml");
......
...@@ -19,13 +19,13 @@ package com.alibaba.cloud.sentinel.datasource; ...@@ -19,13 +19,13 @@ package com.alibaba.cloud.sentinel.datasource;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import com.alibaba.cloud.commons.io.FileUtils;
import com.alibaba.cloud.sentinel.datasource.converter.JsonConverter; import com.alibaba.cloud.sentinel.datasource.converter.JsonConverter;
import com.alibaba.cloud.sentinel.datasource.converter.XmlConverter; import com.alibaba.cloud.sentinel.datasource.converter.XmlConverter;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.apache.commons.io.FileUtils;
import org.junit.Test; import org.junit.Test;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
......
# Sentinel Spring Cloud Zuul Adapter
Zuul does not provide rateLimit function, If use default `SentinelRibbonFilter` route filter. it wrapped by Hystrix Command. so only provide Service level
circuit protect.
Sentinel can provide `ServiceId` level and `API Path` level flow control for spring cloud zuul gateway service.
*Note*: this project is for zuul 1.
## How to use
1. Add maven dependency
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>x.y.z</version>
</dependency>
```
2. Set application.property
```
// default value is false
spring.cloud.sentinel.zuul.enabled=true
```
## How it works
As Zuul run as per thread per connection block model, we add filters around `route Filter` to trace sentinel statistics.
- `SentinelPreFilter`: Get an entry of resource,the first order is **ServiceId**, then **API Path**.
- `SentinelPostFilter`: When success response,exit entry.
- `SentinelErrorFilter`: When get an `Exception`, trace the exception and exit context.
the order of Filter can be changed by configuration:
```
spring.cloud.sentinel.zuul.order.post=0
spring.cloud.sentinel.zuul.order.pre=10000
spring.cloud.sentinel.zuul.order.error=-1
```
Filters create structure like:
```bash
EntranceNode: machine-root(t:3 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
-EntranceNode: coke(t:2 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
--coke(t:2 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
---/coke/uri(t:0 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
-EntranceNode: sentinel_default_context(t:0 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
-EntranceNode: book(t:1 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
--book(t:1 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
---/book/uri(t:0 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0)
```
`book` and `coke` are serviceId.
`---/book/uri` is api path, the real uri is `/uri`.
## Integration with Sentinel DashBord
Start [Sentinel DashBord](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0).
## Rule config with dataSource
Sentinel has full rule config features. see [Dynamic-Rule-Configuration](https://github.com/alibaba/Sentinel/wiki/Dynamic-Rule-Configuration)
## Custom Fallbacks
Implements `SentinelFallbackProvider` to define your own Fallback Provider when Sentinel Block Exception throwing for different rout. the default
Fallback Provider is `DefaultBlockFallbackProvider`.
By default Fallback route is `ServiveId + URI PATH`, example `/book/coke`, first `book` is serviceId, `/uri` is URI PATH, so both
can be needed.
Here is an example:
```java
// custom provider
public class MyCokeServiceBlockFallbackProvider implements SentinelFallbackProvider {
private Logger logger = LoggerFactory.getLogger(DefaultBlockFallbackProvider.class);
// you can define root as service level
@Override
public String getRoute() {
return "/coke/uri";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
if (cause instanceof BlockException) {
logger.info("get in fallback block exception:{}", cause);
return response(HttpStatus.TOO_MANY_REQUESTS, route);
} else {
return response(HttpStatus.INTERNAL_SERVER_ERROR, route);
}
}
}
```
## Custom Request Origin Parser
By default this adapter use `DefaultRequestOriginParser` to parse sentinel origin.
```java
public class CustomRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// do custom logic.
return "";
}
}
```
## Custom UrlCleaner
By default this adapter use `DefaultUrlCleaner` to define uri resource.
```java
public class CustomUrlCleaner implements UrlCleaner {
@Override
public String clean(String originUrl) {
// do custom logic.
return originUrl;
}
}
```
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>spring-cloud-timeloit-starters</artifactId> <artifactId>spring-cloud-timeloit-starters</artifactId>
<groupId>com.timeloit.cloud</groupId> <groupId>com.timeloit.cloud</groupId>
<version>2.3.3-SNAPSHOT</version> <version>2.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -37,7 +37,7 @@ public final class ConfigConstants { ...@@ -37,7 +37,7 @@ public final class ConfigConstants {
/** /**
* ConfigurationProperties for {@link SentinelZuulProperties}. * ConfigurationProperties for {@link SentinelZuulProperties}.
*/ */
public static final String ZUUl_PREFIX = "spring.cloud.sentinel.zuul"; public static final String ZUUL_PREFIX = "spring.cloud.sentinel.zuul";
/** /**
* ConfigurationProperties for {@link SentinelGatewayProperties}. * ConfigurationProperties for {@link SentinelGatewayProperties}.
......
...@@ -47,7 +47,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -47,7 +47,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZuulServlet.class) @ConditionalOnClass(ZuulServlet.class)
@ConditionalOnProperty(prefix = ConfigConstants.ZUUl_PREFIX, name = "enabled", @ConditionalOnProperty(prefix = ConfigConstants.ZUUL_PREFIX, name = "enabled",
havingValue = "true", matchIfMissing = true) havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(SentinelZuulProperties.class) @EnableConfigurationProperties(SentinelZuulProperties.class)
public class SentinelZuulAutoConfiguration { public class SentinelZuulAutoConfiguration {
......
...@@ -28,7 +28,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty; ...@@ -28,7 +28,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
/** /**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a> * @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/ */
@ConfigurationProperties(prefix = ConfigConstants.ZUUl_PREFIX) @ConfigurationProperties(prefix = ConfigConstants.ZUUL_PREFIX)
public class SentinelZuulProperties { public class SentinelZuulProperties {
@NestedConfigurationProperty @NestedConfigurationProperty
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论