1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

Merge code from upstream

This commit is contained in:
ly
2019-07-23 21:40:11 +08:00
parent af09456b7d
commit 1de313079c
475 changed files with 40536 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.9.1.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
<name>Spring Cloud Alibaba Nacos Discovery</name>
<dependencies>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 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
*
* http://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.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.enabled", matchIfMissing = true)
public @interface ConditionalOnNacosDiscoveryEnabled {
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 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
*
* http://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.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.alibaba.cloud.nacos.registry.NacosServiceRegistry;
/**
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class })
public class NacosDiscoveryAutoConfiguration {
@Bean
public NacosServiceRegistry nacosServiceRegistry(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
return new NacosRegistration(nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
}

View File

@@ -0,0 +1,459 @@
/*
* Copyright (C) 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
*
* http://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 static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
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_PORT;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.naming.NamingMaintainFactory;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
/**
* @author dungu.zpf
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConfigurationProperties("spring.cloud.nacos.discovery")
public class NacosDiscoveryProperties {
private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryProperties.class);
/**
* nacos discovery server address
*/
private String serverAddr;
/**
* the domain name of a service, through which the server address can be dynamically
* obtained.
*/
private String endpoint;
/**
* namespace, separation registry of different environments.
*/
private String namespace;
/**
* watch delay,duration to pull new service from nacos server.
*/
private long watchDelay = 30000;
/**
* nacos naming log file name
*/
private String logName;
/**
* service name to registry
*/
@Value("${spring.cloud.nacos.discovery.service:${spring.application.name:}}")
private String service;
/**
* weight for service instance, the larger the value, the larger the weight.
*/
private float weight = 1;
/**
* cluster name for nacos server.
*/
private String clusterName = "DEFAULT";
/**
* naming load from local cache at application start. true is load
*/
private String namingLoadCacheAtStart = "false";
/**
* extra metadata to register.
*/
private Map<String, String> metadata = new HashMap<>();
/**
* if you just want to subscribe, but don't want to register your service, set it to
* false.
*/
private boolean registerEnabled = true;
/**
* The ip address your want to register for your service instance, needn't to set it
* if the auto detect ip works well.
*/
private String ip;
/**
* which network interface's ip you want to register
*/
private String networkInterface = "";
/**
* The port your want to register for your service instance, needn't to set it if the
* auto detect port works well
*/
private int port = -1;
/**
* whether your service is a https service
*/
private boolean secure = false;
/**
* access key for namespace.
*/
private String accessKey;
/**
* secret key for namespace.
*/
private String secretKey;
@Autowired
private InetUtils inetUtils;
@Autowired
private Environment environment;
private NamingService namingService;
private NamingMaintainService namingMaintainService;
@PostConstruct
public void init() throws SocketException {
metadata.put(PreservedMetadataKeys.REGISTER_SOURCE, "SPRING_CLOUD");
if (secure) {
metadata.put("secure", "true");
}
serverAddr = Objects.toString(serverAddr, "");
if (serverAddr.lastIndexOf("/") != -1) {
serverAddr = serverAddr.substring(0, serverAddr.length() - 1);
}
endpoint = Objects.toString(endpoint, "");
namespace = Objects.toString(namespace, "");
logName = Objects.toString(logName, "");
if (StringUtils.isEmpty(ip)) {
// traversing network interfaces if didn't specify a interface
if (StringUtils.isEmpty(networkInterface)) {
ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
}
else {
NetworkInterface netInterface = NetworkInterface
.getByName(networkInterface);
if (null == netInterface) {
throw new IllegalArgumentException(
"no such interface " + networkInterface);
}
Enumeration<InetAddress> inetAddress = netInterface.getInetAddresses();
while (inetAddress.hasMoreElements()) {
InetAddress currentAddress = inetAddress.nextElement();
if (currentAddress instanceof Inet4Address
&& !currentAddress.isLoopbackAddress()) {
ip = currentAddress.getHostAddress();
break;
}
}
if (StringUtils.isEmpty(ip)) {
throw new RuntimeException("cannot find available ip from"
+ " network interface " + networkInterface);
}
}
}
this.overrideFromEnv(environment);
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getLogName() {
return logName;
}
public void setLogName(String logName) {
this.logName = logName;
}
public void setInetUtils(InetUtils inetUtils) {
this.inetUtils = inetUtils;
}
public float getWeight() {
return weight;
}
public void setWeight(float weight) {
this.weight = weight;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public boolean isRegisterEnabled() {
return registerEnabled;
}
public void setRegisterEnabled(boolean registerEnabled) {
this.registerEnabled = registerEnabled;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getNetworkInterface() {
return networkInterface;
}
public void setNetworkInterface(String networkInterface) {
this.networkInterface = networkInterface;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isSecure() {
return secure;
}
public void setSecure(boolean secure) {
this.secure = secure;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getNamingLoadCacheAtStart() {
return namingLoadCacheAtStart;
}
public void setNamingLoadCacheAtStart(String namingLoadCacheAtStart) {
this.namingLoadCacheAtStart = namingLoadCacheAtStart;
}
public long getWatchDelay() {
return watchDelay;
}
public void setWatchDelay(long watchDelay) {
this.watchDelay = watchDelay;
}
@Override
public String toString() {
return "NacosDiscoveryProperties{" + "serverAddr='" + serverAddr + '\''
+ ", endpoint='" + endpoint + '\'' + ", namespace='" + namespace + '\''
+ ", watchDelay=" + watchDelay + ", logName='" + logName + '\''
+ ", service='" + service + '\'' + ", weight=" + weight
+ ", clusterName='" + clusterName + '\'' + ", namingLoadCacheAtStart='"
+ namingLoadCacheAtStart + '\'' + ", metadata=" + metadata
+ ", registerEnabled=" + registerEnabled + ", ip='" + ip + '\''
+ ", networkInterface='" + networkInterface + '\'' + ", port=" + port
+ ", secure=" + secure + ", accessKey='" + accessKey + '\''
+ ", secretKey='" + secretKey + '\'' + '}';
}
public void overrideFromEnv(Environment env) {
if (StringUtils.isEmpty(this.getServerAddr())) {
this.setServerAddr(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.server-addr:}"));
}
if (StringUtils.isEmpty(this.getNamespace())) {
this.setNamespace(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.namespace:}"));
}
if (StringUtils.isEmpty(this.getAccessKey())) {
this.setAccessKey(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.access-key:}"));
}
if (StringUtils.isEmpty(this.getSecretKey())) {
this.setSecretKey(env
.resolvePlaceholders("${spring.cloud.nacos.discovery.secret-key:}"));
}
if (StringUtils.isEmpty(this.getLogName())) {
this.setLogName(
env.resolvePlaceholders("${spring.cloud.nacos.discovery.log-name:}"));
}
if (StringUtils.isEmpty(this.getClusterName())) {
this.setClusterName(env.resolvePlaceholders(
"${spring.cloud.nacos.discovery.cluster-name:}"));
}
if (StringUtils.isEmpty(this.getEndpoint())) {
this.setEndpoint(
env.resolvePlaceholders("${spring.cloud.nacos.discovery.endpoint:}"));
}
}
public NamingService namingServiceInstance() {
if (null != namingService) {
return namingService;
}
try {
namingService = NacosFactory.createNamingService(getNacosProperties());
}
catch (Exception e) {
log.error("create naming service error!properties={},e=,", this, e);
return null;
}
return namingService;
}
public NamingMaintainService namingMaintainServiceInstance() {
if (null != namingMaintainService) {
return namingMaintainService;
}
try {
namingMaintainService = NamingMaintainFactory
.createMaintainService(getNacosProperties());
}
catch (Exception e) {
log.error("create naming service error!properties={},e=,", this, e);
return null;
}
return namingMaintainService;
}
private Properties getNacosProperties() {
Properties properties = new Properties();
properties.put(SERVER_ADDR, serverAddr);
properties.put(NAMESPACE, namespace);
properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, logName);
if (endpoint.contains(":")) {
int index = endpoint.indexOf(":");
properties.put(ENDPOINT, endpoint.substring(0, index));
properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
}
else {
properties.put(ENDPOINT, endpoint);
}
properties.put(ACCESS_KEY, accessKey);
properties.put(SECRET_KEY, secretKey);
properties.put(CLUSTER_NAME, clusterName);
properties.put(NAMING_LOAD_CACHE_AT_START, namingLoadCacheAtStart);
return properties;
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 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
*
* http://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.net.URI;
import java.util.Map;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
/**
* @author xiaojing
*/
public class NacosServiceInstance implements ServiceInstance {
private String serviceId;
private String host;
private int port;
private boolean secure;
private Map<String, String> metadata;
@Override
public String getServiceId() {
return serviceId;
}
@Override
public String getHost() {
return host;
}
@Override
public int getPort() {
return port;
}
@Override
public boolean isSecure() {
return secure;
}
@Override
public URI getUri() {
return DefaultServiceInstance.getUri(this);
}
@Override
public Map<String, String> getMetadata() {
return metadata;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
public void setSecure(boolean secure) {
this.secure = secure;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 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
*
* http://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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
/**
* @author xiaojing
* @author renhaojun
*/
public class NacosDiscoveryClient implements DiscoveryClient {
private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryClient.class);
public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";
private NacosDiscoveryProperties discoveryProperties;
public NacosDiscoveryClient(NacosDiscoveryProperties discoveryProperties) {
this.discoveryProperties = discoveryProperties;
}
@Override
public String description() {
return DESCRIPTION;
}
@Override
public List<ServiceInstance> getInstances(String serviceId) {
try {
List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, true);
return hostToServiceInstanceList(instances, serviceId);
}
catch (Exception e) {
throw new RuntimeException(
"Can not get hosts from nacos server. serviceId: " + serviceId, e);
}
}
private static ServiceInstance hostToServiceInstance(Instance instance,
String serviceId) {
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
nacosServiceInstance.setHost(instance.getIp());
nacosServiceInstance.setPort(instance.getPort());
nacosServiceInstance.setServiceId(serviceId);
Map<String, String> metadata = new HashMap<>();
metadata.put("nacos.instanceId", instance.getInstanceId());
metadata.put("nacos.weight", instance.getWeight() + "");
metadata.put("nacos.healthy", instance.isHealthy() + "");
metadata.put("nacos.cluster", instance.getClusterName() + "");
metadata.putAll(instance.getMetadata());
nacosServiceInstance.setMetadata(metadata);
if (metadata.containsKey("secure")) {
boolean secure = Boolean.parseBoolean(metadata.get("secure"));
nacosServiceInstance.setSecure(secure);
}
return nacosServiceInstance;
}
private static List<ServiceInstance> hostToServiceInstanceList(
List<Instance> instances, String serviceId) {
List<ServiceInstance> result = new ArrayList<>(instances.size());
for (Instance instance : instances) {
result.add(hostToServiceInstance(instance, serviceId));
}
return result;
}
@Override
public List<String> getServices() {
try {
ListView<String> services = discoveryProperties.namingServiceInstance()
.getServicesOfServer(1, Integer.MAX_VALUE);
return services.getData();
}
catch (Exception e) {
log.error("get service name from nacos server fail,", e);
return Collections.emptyList();
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 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
*
* http://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;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
/**
* @author xiaojing
*/
@Configuration
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class,
CommonsClientAutoConfiguration.class })
public class NacosDiscoveryClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
return new NacosDiscoveryProperties();
}
@Bean
public DiscoveryClient nacosDiscoveryClient(
NacosDiscoveryProperties discoveryProperties) {
return new NacosDiscoveryClient(discoveryProperties);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled", matchIfMissing = true)
public NacosWatch nacosWatch(NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosWatch(nacosDiscoveryProperties);
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 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
*
* http://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;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.SmartLifecycle;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.listener.EventListener;
/**
* @author xiaojing
*/
public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycle {
private static final Logger log = LoggerFactory.getLogger(NacosWatch.class);
private final NacosDiscoveryProperties properties;
private final TaskScheduler taskScheduler;
private final AtomicLong nacosWatchIndex = new AtomicLong(0);
private final AtomicBoolean running = new AtomicBoolean(false);
private ApplicationEventPublisher publisher;
private ScheduledFuture<?> watchFuture;
private Set<String> cacheServices = new HashSet<>();
private HashMap<String, EventListener> subscribeListeners = new HashMap<>();
public NacosWatch(NacosDiscoveryProperties properties) {
this(properties, getTaskScheduler());
}
public NacosWatch(NacosDiscoveryProperties properties, TaskScheduler taskScheduler) {
this.properties = properties;
this.taskScheduler = taskScheduler;
}
private static ThreadPoolTaskScheduler getTaskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
return taskScheduler;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable callback) {
this.stop();
callback.run();
}
@Override
public void start() {
if (this.running.compareAndSet(false, true)) {
this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(
this::nacosServicesWatch, this.properties.getWatchDelay());
}
}
@Override
public void stop() {
if (this.running.compareAndSet(true, false) && this.watchFuture != null) {
this.watchFuture.cancel(true);
}
}
@Override
public boolean isRunning() {
return false;
}
@Override
public int getPhase() {
return 0;
}
public void nacosServicesWatch() {
// nacos doesn't support watch now , publish an event every 30 seconds.
this.publisher.publishEvent(
new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement()));
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 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
*
* http://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.configclient;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.config.server.config.ConfigServerProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
/**
* Extra configuration for config server if it happens to be registered with Nacos.
*
* @author JevonYang
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({ NacosDiscoveryProperties.class, ConfigServerProperties.class })
public class NacosConfigServerAutoConfiguration {
@Autowired(required = false)
private NacosDiscoveryProperties properties;
@Autowired(required = false)
private ConfigServerProperties server;
@PostConstruct
public void init() {
if (this.properties == null || this.server == null) {
return;
}
String prefix = this.server.getPrefix();
if (StringUtils.hasText(prefix) && !StringUtils
.hasText(this.properties.getMetadata().get("configPath"))) {
this.properties.getMetadata().put("configPath", prefix);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 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
*
* http://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.configclient;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
/**
* Helper for config client that wants to lookup the config server via discovery.
*
* @author JevonYang
*/
@ConditionalOnClass(ConfigServicePropertySourceLocator.class)
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false)
@Configuration
@ImportAutoConfiguration({ NacosDiscoveryClientAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public class NacosDiscoveryClientConfigServiceBootstrapConfiguration {
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 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
*
* http://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.endpoint;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
/**
* Endpoint for nacos discovery, get nacos properties and subscribed services
* @author xiaojing
*/
@Endpoint(id = "nacos-discovery")
public class NacosDiscoveryEndpoint {
private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryEndpoint.class);
private NacosDiscoveryProperties nacosDiscoveryProperties;
public NacosDiscoveryEndpoint(NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
}
/**
* @return nacos discovery endpoint
*/
@ReadOperation
public Map<String, Object> nacosDiscovery() {
Map<String, Object> result = new HashMap<>();
result.put("NacosDiscoveryProperties", nacosDiscoveryProperties);
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
List<ServiceInfo> subscribe = Collections.emptyList();
try {
subscribe = namingService.getSubscribeServices();
}
catch (Exception e) {
log.error("get subscribe services from nacos fail,", e);
}
result.put("subscribe", subscribe);
return result;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 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
*
* http://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.endpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
/**
* @author xiaojing
*/
@Configuration
@ConditionalOnClass(Endpoint.class)
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public NacosDiscoveryEndpoint nacosDiscoveryEndpoint(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosDiscoveryEndpoint(nacosDiscoveryProperties);
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 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
*
* http://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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<Registration> {
private static final Logger log = LoggerFactory
.getLogger(NacosAutoServiceRegistration.class);
private NacosRegistration registration;
public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
}
@Deprecated
public void setPort(int port) {
getPort().set(port);
}
@Override
protected NacosRegistration getRegistration() {
if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
this.registration.setPort(this.getPort().get());
}
Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
return this.registration;
}
@Override
protected NacosRegistration getManagementRegistration() {
return null;
}
@Override
protected void register() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
log.debug("Registration disabled.");
return;
}
if (this.registration.getPort() < 0) {
this.registration.setPort(getPort().get());
}
super.register();
}
@Override
protected void registerManagement() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
return;
}
super.registerManagement();
}
@Override
protected Object getConfiguration() {
return this.registration.getNacosDiscoveryProperties();
}
@Override
protected boolean isEnabled() {
return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
@Override
@SuppressWarnings("deprecation")
protected String getAppName() {
String appName = registration.getNacosDiscoveryProperties().getService();
return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 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
*
* http://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.net.URI;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.ManagementServerPortUtils;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
/**
* @author xiaojing
*/
public class NacosRegistration implements Registration, ServiceInstance {
public static final String MANAGEMENT_PORT = "management.port";
public static final String MANAGEMENT_CONTEXT_PATH = "management.context-path";
public static final String MANAGEMENT_ADDRESS = "management.address";
public static final String MANAGEMENT_ENDPOINT_BASE_PATH = "management.endpoints.web.base-path";
private NacosDiscoveryProperties nacosDiscoveryProperties;
private ApplicationContext context;
public NacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.context = context;
}
@PostConstruct
public void init() {
Map<String, String> metadata = nacosDiscoveryProperties.getMetadata();
Environment env = context.getEnvironment();
String endpointBasePath = env.getProperty(MANAGEMENT_ENDPOINT_BASE_PATH);
if (!StringUtils.isEmpty(endpointBasePath)) {
metadata.put(MANAGEMENT_ENDPOINT_BASE_PATH, endpointBasePath);
}
Integer managementPort = ManagementServerPortUtils.getPort(context);
if (null != managementPort) {
metadata.put(MANAGEMENT_PORT, managementPort.toString());
String contextPath = env
.getProperty("management.server.servlet.context-path");
String address = env.getProperty("management.server.address");
if (!StringUtils.isEmpty(contextPath)) {
metadata.put(MANAGEMENT_CONTEXT_PATH, contextPath);
}
if (!StringUtils.isEmpty(address)) {
metadata.put(MANAGEMENT_ADDRESS, address);
}
}
}
@Override
public String getServiceId() {
return nacosDiscoveryProperties.getService();
}
@Override
public String getHost() {
return nacosDiscoveryProperties.getIp();
}
@Override
public int getPort() {
return nacosDiscoveryProperties.getPort();
}
public void setPort(int port) {
this.nacosDiscoveryProperties.setPort(port);
}
@Override
public boolean isSecure() {
return nacosDiscoveryProperties.isSecure();
}
@Override
public URI getUri() {
return DefaultServiceInstance.getUri(this);
}
@Override
public Map<String, String> getMetadata() {
return nacosDiscoveryProperties.getMetadata();
}
public boolean isRegisterEnabled() {
return nacosDiscoveryProperties.isRegisterEnabled();
}
public String getCluster() {
return nacosDiscoveryProperties.getClusterName();
}
public float getRegisterWeight() {
return nacosDiscoveryProperties.getWeight();
}
public NacosDiscoveryProperties getNacosDiscoveryProperties() {
return nacosDiscoveryProperties;
}
public NamingService getNacosNamingService() {
return nacosDiscoveryProperties.namingServiceInstance();
}
@Override
public String toString() {
return "NacosRegistration{" + "nacosDiscoveryProperties="
+ nacosDiscoveryProperties + '}';
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 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
*
* http://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.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);
private final NacosDiscoveryProperties nacosDiscoveryProperties;
private final NamingService namingService;
public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.namingService = nacosDiscoveryProperties.namingServiceInstance();
}
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
String serviceId = registration.getServiceId();
Instance instance = getNacosInstanceFromRegistration(registration);
try {
namingService.registerInstance(serviceId, instance);
log.info("nacos registry, {} {}:{} register finished", serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
}
}
@Override
public void deregister(Registration registration) {
log.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No dom to de-register for nacos client...");
return;
}
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
String serviceId = registration.getServiceId();
try {
namingService.deregisterInstance(serviceId, registration.getHost(),
registration.getPort(), nacosDiscoveryProperties.getClusterName());
}
catch (Exception e) {
log.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
log.info("De-registration finished.");
}
@Override
public void close() {
}
@Override
public void setStatus(Registration registration, String status) {
if (!status.equalsIgnoreCase("UP") && !status.equalsIgnoreCase("DOWN")) {
log.warn("can't support status {},please choose UP or DOWN", status);
return;
}
String serviceId = registration.getServiceId();
Instance instance = getNacosInstanceFromRegistration(registration);
if (status.equalsIgnoreCase("DOWN")) {
instance.setEnabled(false);
}
else {
instance.setEnabled(true);
}
try {
nacosDiscoveryProperties.namingMaintainServiceInstance()
.updateInstance(serviceId, instance);
}
catch (Exception e) {
throw new RuntimeException("update nacos instance status fail", e);
}
}
@Override
public Object getStatus(Registration registration) {
String serviceName = registration.getServiceId();
try {
List<Instance> instances = nacosDiscoveryProperties.namingServiceInstance()
.getAllInstances(serviceName);
for (Instance instance : instances) {
if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp())
&& instance.getPort() == nacosDiscoveryProperties.getPort())
return instance.isEnabled() ? "UP" : "DOWN";
}
}
catch (Exception e) {
log.error("get all instance of {} error,", serviceName, e);
}
return null;
}
private Instance getNacosInstanceFromRegistration(Registration registration) {
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight(nacosDiscoveryProperties.getWeight());
instance.setClusterName(nacosDiscoveryProperties.getClusterName());
instance.setMetadata(registration.getMetadata());
return instance;
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnProperty(value = "ribbon.nacos.enabled", matchIfMissing = true)
public @interface ConditionalOnRibbonNacos {
}

View File

@@ -0,0 +1,21 @@
package com.alibaba.cloud.nacos.ribbon;
import java.util.List;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
/**
* @author itmuch.com
*/
public class ExtendBalancer extends Balancer {
/**
* 根据权重,随机选择实例
*
* @param instances 实例列表
* @return 选择的实例
*/
public static Instance getHostByRandomWeight2(List<Instance> instances) {
return getHostByRandomWeight(instances);
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
/**
* integrated Ribbon by default
* @author xiaojing
*/
@Configuration
@ConditionalOnRibbonNacos
public class NacosRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config,
NacosDiscoveryProperties nacosDiscoveryProperties) {
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public NacosServerIntrospector nacosServerIntrospector() {
return new NacosServerIntrospector();
}
}

View File

@@ -0,0 +1,78 @@
package com.alibaba.cloud.nacos.ribbon;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
/**
* Supports preferentially calling the ribbon load balancing rules of the same cluster
* instance.
*
* @author itmuch.com
*/
public class NacosRule extends AbstractLoadBalancerRule {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosRule.class);
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public Server choose(Object key) {
try {
String clusterName = this.nacosDiscoveryProperties.getClusterName();
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
String name = loadBalancer.getName();
NamingService namingService = this.nacosDiscoveryProperties
.namingServiceInstance();
List<Instance> instances = namingService.selectInstances(name, true);
if (CollectionUtils.isEmpty(instances)) {
LOGGER.warn("no instance in service {}", name);
return null;
}
List<Instance> instancesToChoose = instances;
if (StringUtils.isNotBlank(clusterName)) {
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> Objects.equals(clusterName,
instance.getClusterName()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(sameClusterInstances)) {
instancesToChoose = sameClusterInstances;
}
else {
LOGGER.warn(
"A cross-cluster call occursname = {}, clusterName = {}, instance = {}",
name, clusterName, instances);
}
}
Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);
return new NacosServer(instance);
}
catch (Exception e) {
LOGGER.warn("NacosRule error", e);
return null;
}
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import java.util.Map;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.loadbalancer.Server;
/**
* @author xiaojing
* @author pbting
*/
public class NacosServer extends Server {
private final MetaInfo metaInfo;
private final Instance instance;
private final Map<String, String> metadata;
public NacosServer(final Instance instance) {
super(instance.getIp(), instance.getPort());
this.instance = instance;
this.metaInfo = new MetaInfo() {
@Override
public String getAppName() {
return instance.getServiceName();
}
@Override
public String getServerGroup() {
return null;
}
@Override
public String getServiceIdForDiscovery() {
return null;
}
@Override
public String getInstanceId() {
return instance.getInstanceId();
}
};
this.metadata = instance.getMetadata();
}
@Override
public MetaInfo getMetaInfo() {
return metaInfo;
}
public Instance getInstance() {
return instance;
}
public Map<String, String> getMetadata() {
return metadata;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import java.util.Map;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
import com.netflix.loadbalancer.Server;
/**
* @author xiaojing
*/
public class NacosServerIntrospector extends DefaultServerIntrospector {
@Override
public Map<String, String> getMetadata(Server server) {
if (server instanceof NacosServer) {
return ((NacosServer) server).getMetadata();
}
return super.getMetadata(server);
}
@Override
public boolean isSecure(Server server) {
if (server instanceof NacosServer) {
return Boolean.valueOf(((NacosServer) server).getMetadata().get("secure"));
}
return super.isSecure(server);
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
/**
* @author xiaojing
* @author renhaojun
*/
public class NacosServerList extends AbstractServerList<NacosServer> {
private NacosDiscoveryProperties discoveryProperties;
private String serviceId;
public NacosServerList(NacosDiscoveryProperties discoveryProperties) {
this.discoveryProperties = discoveryProperties;
}
@Override
public List<NacosServer> getInitialListOfServers() {
return getServers();
}
@Override
public List<NacosServer> getUpdatedListOfServers() {
return getServers();
}
private List<NacosServer> getServers() {
try {
List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, true);
return instancesToServerList(instances);
}
catch (Exception e) {
throw new IllegalStateException(
"Can not get service instances from nacos, serviceId=" + serviceId,
e);
}
}
private List<NacosServer> instancesToServerList(List<Instance> instances) {
List<NacosServer> result = new ArrayList<>();
if (null == instances) {
return result;
}
for (Instance instance : instances) {
result.add(new NacosServer(instance));
}
return result;
}
public String getServiceId() {
return serviceId;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.serviceId = iClientConfig.getClientName();
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} that sets up Ribbon for Nacos.
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnRibbonNacos
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = NacosRibbonClientConfiguration.class)
public class RibbonNacosAutoConfiguration {
}

View File

@@ -0,0 +1,26 @@
{"properties": [
{
"name": "spring.cloud.nacos.discovery.service",
"type": "java.lang.String",
"defaultValue": "${spring.application.name}",
"description": "the service name to register, default value is ${spring.application.name}."
},
{
"name": "spring.cloud.nacos.discovery.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "enable nacos discovery or not."
},
{
"name": "spring.cloud.nacos.discovery.namingLoadCacheAtStart",
"type": "java.lang.Boolean",
"defaultValue": "false",
"description": "naming load from local cache at application start ."
},
{
"name": "spring.cloud.nacos.discovery.watch.enabled",
"type": "java.lang.Boolean",
"defaultValue": "true",
"description": "enable nacos discovery watch or not ."
}
]}

View File

@@ -0,0 +1,8 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration,\
com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration,\
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 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
*
* http://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 static com.alibaba.cloud.nacos.test.NacosMockTest.serviceInstance;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.springframework.cloud.client.ServiceInstance;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
/**
* @author xiaojing
*/
public class NacosDiscoveryClientTests {
private String host = "123.123.123.123";
private int port = 8888;
private String serviceName = "test-service";
@Test
public void testGetServers() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
HashMap<String, String> map = new HashMap<>();
map.put("test-key", "test-value");
map.put("secure", "true");
instances.add(serviceInstance(serviceName, false, host, port, map));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.selectInstances(eq(serviceName), eq(true)))
.thenReturn(instances);
NacosDiscoveryClient discoveryClient = new NacosDiscoveryClient(
nacosDiscoveryProperties);
List<ServiceInstance> serviceInstances = discoveryClient
.getInstances(serviceName);
assertThat(serviceInstances.size()).isEqualTo(1);
ServiceInstance serviceInstance = serviceInstances.get(0);
assertThat(serviceInstance.getServiceId()).isEqualTo(serviceName);
assertThat(serviceInstance.getHost()).isEqualTo(host);
assertThat(serviceInstance.getPort()).isEqualTo(port);
assertThat(serviceInstance.isSecure()).isEqualTo(true);
assertThat(serviceInstance.getUri().toString())
.isEqualTo(getUri(serviceInstance));
assertThat(serviceInstance.getMetadata().get("test-key")).isEqualTo("test-value");
}
@Test
public void testGetAllService() throws Exception {
ListView<String> nacosServices = new ListView<>();
nacosServices.setData(new LinkedList<>());
nacosServices.getData().add(serviceName + "1");
nacosServices.getData().add(serviceName + "2");
nacosServices.getData().add(serviceName + "3");
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
NacosDiscoveryClient discoveryClient = new NacosDiscoveryClient(
nacosDiscoveryProperties);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.getServicesOfServer(eq(1), eq(Integer.MAX_VALUE)))
.thenReturn(nacosServices);
List<String> services = discoveryClient.getServices();
assertThat(services.size()).isEqualTo(3);
assertThat(services.contains(serviceName + "1"));
assertThat(services.contains(serviceName + "2"));
assertThat(services.contains(serviceName + "3"));
}
private String getUri(ServiceInstance instance) {
if (instance.isSecure()) {
return "https://" + host + ":" + port;
}
return "http://" + host + ":" + port;
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 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
*
* http://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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import org.junit.Test;
import org.junit.runner.RunWith;
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.cloud.commons.util.InetUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
/**
* @author xiaojing
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosAutoServiceRegistrationIpNetworkInterfaceTests.TestConfig.class, properties = {
"spring.application.name=myTestService1",
"spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848" }, webEnvironment = RANDOM_PORT)
public class NacosAutoServiceRegistrationIpNetworkInterfaceTests {
@Autowired
private NacosRegistration registration;
@Autowired
private NacosAutoServiceRegistration nacosAutoServiceRegistration;
@Autowired
private NacosDiscoveryProperties properties;
@Autowired
private InetUtils inetUtils;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosRegistration was not created", registration);
assertNotNull("NacosDiscoveryProperties was not created", properties);
assertNotNull("NacosAutoServiceRegistration was not created",
nacosAutoServiceRegistration);
checkoutNacosDiscoveryServiceIP();
}
private void checkoutNacosDiscoveryServiceIP() {
assertEquals("NacosDiscoveryProperties service IP was wrong",
getIPFromNetworkInterface(TestConfig.netWorkInterfaceName),
registration.getHost());
}
private String getIPFromNetworkInterface(String networkInterface) {
if (!TestConfig.hasValidNetworkInterface) {
return inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
}
try {
NetworkInterface netInterface = NetworkInterface.getByName(networkInterface);
Enumeration<InetAddress> inetAddress = netInterface.getInetAddresses();
while (inetAddress.hasMoreElements()) {
InetAddress currentAddress = inetAddress.nextElement();
if (currentAddress instanceof Inet4Address
&& !currentAddress.isLoopbackAddress()) {
return currentAddress.getHostAddress();
}
}
return networkInterface;
}
catch (Exception e) {
return networkInterface;
}
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public static class TestConfig {
static boolean hasValidNetworkInterface = false;
static String netWorkInterfaceName;
static {
try {
Enumeration<NetworkInterface> enumeration = NetworkInterface
.getNetworkInterfaces();
while (enumeration.hasMoreElements() && !hasValidNetworkInterface) {
NetworkInterface networkInterface = enumeration.nextElement();
Enumeration<InetAddress> inetAddress = networkInterface
.getInetAddresses();
while (inetAddress.hasMoreElements()) {
InetAddress currentAddress = inetAddress.nextElement();
if (currentAddress instanceof Inet4Address
&& !currentAddress.isLoopbackAddress()) {
hasValidNetworkInterface = true;
netWorkInterfaceName = networkInterface.getName();
System.setProperty(
"spring.cloud.nacos.discovery.network-interface",
networkInterface.getName());
break;
}
}
}
}
catch (Exception e) {
}
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 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
*
* http://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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import org.junit.Test;
import org.junit.runner.RunWith;
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.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
/**
* @author xiaojing
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosAutoServiceRegistrationIpTests.TestConfig.class, properties = {
"spring.application.name=myTestService1",
"spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.discovery.ip=123.123.123.123" }, webEnvironment = RANDOM_PORT)
public class NacosAutoServiceRegistrationIpTests {
@Autowired
private NacosRegistration registration;
@Autowired
private NacosAutoServiceRegistration nacosAutoServiceRegistration;
@Autowired
private NacosDiscoveryProperties properties;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosRegistration was not created", registration);
assertNotNull("NacosDiscoveryProperties was not created", properties);
assertNotNull("NacosAutoServiceRegistration was not created",
nacosAutoServiceRegistration);
checkoutNacosDiscoveryServiceIP();
}
private void checkoutNacosDiscoveryServiceIP() {
assertEquals("NacosDiscoveryProperties service IP was wrong", "123.123.123.123",
registration.getHost());
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public static class TestConfig {
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 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
*
* http://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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import org.junit.Test;
import org.junit.runner.RunWith;
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.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
/**
* @author xiaojing
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosAutoServiceRegistrationManagementPortTests.TestConfig.class, properties = {
"spring.application.name=myTestService1", "management.server.port=8888",
"management.server.servlet.context-path=/test-context-path",
"spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.discovery.port=8888" }, webEnvironment = RANDOM_PORT)
public class NacosAutoServiceRegistrationManagementPortTests {
@Autowired
private NacosRegistration registration;
@Autowired
private NacosAutoServiceRegistration nacosAutoServiceRegistration;
@Autowired
private NacosDiscoveryProperties properties;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosRegistration was not created", registration);
assertNotNull("NacosDiscoveryProperties was not created", properties);
assertNotNull("NacosAutoServiceRegistration was not created",
nacosAutoServiceRegistration);
checkoutNacosDiscoveryManagementData();
}
private void checkoutNacosDiscoveryManagementData() {
assertEquals("NacosDiscoveryProperties management port was wrong", "8888",
properties.getMetadata().get(NacosRegistration.MANAGEMENT_PORT));
assertEquals("NacosDiscoveryProperties management context path was wrong",
"/test-context-path",
properties.getMetadata().get(NacosRegistration.MANAGEMENT_CONTEXT_PATH));
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public static class TestConfig {
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 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
*
* http://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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import org.junit.Test;
import org.junit.runner.RunWith;
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.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
/**
* @author xiaojing
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosAutoServiceRegistrationPortTests.TestConfig.class, properties = {
"spring.application.name=myTestService1",
"spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.discovery.port=8888" }, webEnvironment = RANDOM_PORT)
public class NacosAutoServiceRegistrationPortTests {
@Autowired
private NacosRegistration registration;
@Autowired
private NacosAutoServiceRegistration nacosAutoServiceRegistration;
@Autowired
private NacosDiscoveryProperties properties;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosRegistration was not created", registration);
assertNotNull("NacosDiscoveryProperties was not created", properties);
assertNotNull("NacosAutoServiceRegistration was not created",
nacosAutoServiceRegistration);
checkoutNacosDiscoveryServicePort();
}
private void checkoutNacosDiscoveryServicePort() {
assertEquals("NacosDiscoveryProperties service Port was wrong", 8888,
registration.getPort());
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public static class TestConfig {
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright (C) 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
*
* http://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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
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.boot.web.server.LocalServerPort;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
import com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpoint;
/**
* @author xiaojing
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosAutoServiceRegistrationTests.TestConfig.class, properties = {
"spring.application.name=myTestService1",
"spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.discovery.endpoint=test-endpoint",
"spring.cloud.nacos.discovery.namespace=test-namespace",
"spring.cloud.nacos.discovery.log-name=test-logName",
"spring.cloud.nacos.discovery.weight=2",
"spring.cloud.nacos.discovery.clusterName=test-cluster",
"spring.cloud.nacos.discovery.namingLoadCacheAtStart=true",
"spring.cloud.nacos.discovery.secure=true",
"spring.cloud.nacos.discovery.accessKey=test-accessKey",
"spring.cloud.nacos.discovery.secretKey=test-secretKey" }, webEnvironment = RANDOM_PORT)
public class NacosAutoServiceRegistrationTests {
@Autowired
private NacosRegistration registration;
@Autowired
private NacosAutoServiceRegistration nacosAutoServiceRegistration;
@LocalServerPort
private int port;
@Autowired
private NacosDiscoveryProperties properties;
@Autowired
private InetUtils inetUtils;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosRegistration was not created", registration);
assertNotNull("NacosDiscoveryProperties was not created", properties);
assertNotNull("NacosAutoServiceRegistration was not created",
nacosAutoServiceRegistration);
checkoutNacosDiscoveryServerAddr();
checkoutNacosDiscoveryEndpoint();
checkoutNacosDiscoveryNamespace();
checkoutNacosDiscoveryLogName();
checkoutNacosDiscoveryWeight();
checkoutNacosDiscoveryClusterName();
checkoutNacosDiscoveryCache();
checkoutNacosDiscoverySecure();
checkoutNacosDiscoveryAccessKey();
checkoutNacosDiscoverySecrectKey();
checkoutNacosDiscoveryServiceName();
checkoutNacosDiscoveryServiceIP();
checkoutNacosDiscoveryServicePort();
checkAutoRegister();
checkoutEndpoint();
}
private void checkAutoRegister() {
assertTrue("Nacos Auto Registration was not start",
nacosAutoServiceRegistration.isRunning());
}
private void checkoutNacosDiscoveryServerAddr() {
assertEquals("NacosDiscoveryProperties server address was wrong",
"127.0.0.1:8848", properties.getServerAddr());
}
private void checkoutNacosDiscoveryEndpoint() {
assertEquals("NacosDiscoveryProperties endpoint was wrong", "test-endpoint",
properties.getEndpoint());
}
private void checkoutNacosDiscoveryNamespace() {
assertEquals("NacosDiscoveryProperties namespace was wrong", "test-namespace",
properties.getNamespace());
}
private void checkoutNacosDiscoveryLogName() {
assertEquals("NacosDiscoveryProperties logName was wrong", "test-logName",
properties.getLogName());
}
private void checkoutNacosDiscoveryWeight() {
assertEquals(2, properties.getWeight(), 0.00000001);
}
private void checkoutNacosDiscoveryClusterName() {
assertEquals("NacosDiscoveryProperties cluster was wrong", "test-cluster",
properties.getClusterName());
}
private void checkoutNacosDiscoveryCache() {
assertEquals("NacosDiscoveryProperties naming load cache was wrong", "true",
properties.getNamingLoadCacheAtStart());
}
private void checkoutNacosDiscoverySecure() {
assertEquals("NacosDiscoveryProperties is secure was wrong", true,
properties.isSecure());
assertEquals("NacosDiscoveryProperties is secure was wrong", "true",
properties.getMetadata().get("secure"));
}
private void checkoutNacosDiscoveryAccessKey() {
assertEquals("NacosDiscoveryProperties is access key was wrong", "test-accessKey",
properties.getAccessKey());
}
private void checkoutNacosDiscoverySecrectKey() {
assertEquals("NacosDiscoveryProperties is secret key was wrong", "test-secretKey",
properties.getSecretKey());
}
private void checkoutNacosDiscoveryServiceName() {
assertEquals("NacosDiscoveryProperties service name was wrong", "myTestService1",
properties.getService());
}
private void checkoutNacosDiscoveryServiceIP() {
assertEquals("NacosDiscoveryProperties service IP was wrong",
inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(),
registration.getHost());
}
private void checkoutNacosDiscoveryServicePort() {
assertEquals("NacosDiscoveryProperties service Port was wrong", port,
registration.getPort());
}
private void checkoutEndpoint() throws Exception {
NacosDiscoveryEndpoint nacosDiscoveryEndpoint = new NacosDiscoveryEndpoint(
properties);
Map<String, Object> map = nacosDiscoveryEndpoint.nacosDiscovery();
assertEquals(map.get("NacosDiscoveryProperties"), properties);
assertEquals(map.get("subscribe").toString(),
properties.namingServiceInstance().getSubscribeServices().toString());
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
public static class TestConfig {
}
}

View File

@@ -0,0 +1,63 @@
package com.alibaba.cloud.nacos.ribbon;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
/**
* @author xiaojing
*/
public class NacosRibbonClientConfigurationTests {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(NacosRibbonTestConfiguration.class,
NacosRibbonClientConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class,
RibbonNacosAutoConfiguration.class))
.withPropertyValues("spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848")
.withPropertyValues("spring.cloud.nacos.discovery.port=18080")
.withPropertyValues("spring.cloud.nacos.discovery.service=myapp");
@Test
public void testProperties() {
this.contextRunner.run(context -> {
NacosServerList serverList = context.getBean(NacosServerList.class);
assertThat(serverList.getServiceId()).isEqualTo("myapp");
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
static class NacosRibbonTestConfiguration {
@Bean
IClientConfig iClientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.setClientName("myapp");
return config;
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 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
*
* http://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.ribbon;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.test.NacosMockTest;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
/**
* @author xiaojing
*/
public class NacosServerListTests {
@Test
@SuppressWarnings("unchecked")
public void testEmptyInstancesReturnsEmptyList() throws Exception {
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.selectInstances(anyString(), eq(true))).thenReturn(null);
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
List<NacosServer> servers = serverList.getInitialListOfServers();
assertThat(servers).isEmpty();
}
@Test
@SuppressWarnings("unchecked")
public void testGetServers() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
instances.add(NacosMockTest.serviceInstance("test-service", false,
Collections.emptyMap()));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.selectInstances(eq("test-service"), eq(true)))
.thenReturn(instances);
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(clientConfig);
List<NacosServer> servers = serverList.getInitialListOfServers();
assertThat(servers).hasSize(1);
servers = serverList.getUpdatedListOfServers();
assertThat(servers).hasSize(1);
}
@Test
@SuppressWarnings("unchecked")
public void testGetServersWithInstanceStatus() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
HashMap<String, String> map1 = new HashMap<>();
map1.put("instanceNum", "1");
HashMap<String, String> map2 = new HashMap<>();
map2.put("instanceNum", "2");
instances.add(NacosMockTest.serviceInstance("test-service", false, map1));
instances.add(NacosMockTest.serviceInstance("test-service", true, map2));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.selectInstances(eq("test-service"), eq(true)))
.thenReturn(instances.stream().filter(Instance::isHealthy)
.collect(Collectors.toList()));
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(clientConfig);
List<NacosServer> servers = serverList.getInitialListOfServers();
assertThat(servers).hasSize(1);
NacosServer nacosServer = servers.get(0);
assertThat(nacosServer.getMetaInfo().getInstanceId())
.isEqualTo(instances.get(1).getInstanceId());
assertThat(nacosServer.getMetadata()).isEqualTo(map2);
assertThat(nacosServer.getInstance().isHealthy()).isEqualTo(true);
assertThat(nacosServer.getInstance().getServiceName()).isEqualTo("test-service");
assertThat(nacosServer.getInstance().getMetadata().get("instanceNum"))
.isEqualTo("2");
}
@Test
public void testUpdateServers() throws Exception {
ArrayList<Instance> instances = new ArrayList<>();
HashMap<String, String> map = new HashMap<>();
map.put("instanceNum", "1");
instances.add(NacosMockTest.serviceInstance("test-service", true, map));
NacosDiscoveryProperties nacosDiscoveryProperties = mock(
NacosDiscoveryProperties.class);
NamingService namingService = mock(NamingService.class);
when(nacosDiscoveryProperties.namingServiceInstance()).thenReturn(namingService);
when(namingService.selectInstances(eq("test-service"), eq(true)))
.thenReturn(instances.stream().filter(Instance::isHealthy)
.collect(Collectors.toList()));
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(clientConfig);
List<NacosServer> servers = serverList.getUpdatedListOfServers();
assertThat(servers).hasSize(1);
assertThat(servers.get(0).getInstance().isHealthy()).isEqualTo(true);
assertThat(servers.get(0).getInstance().getMetadata().get("instanceNum"))
.isEqualTo("1");
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 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
*
* http://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.test;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author xiaojing
*/
@Configuration
public class CommonTestConfig {
@Bean
@LoadBalanced
RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 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
*
* http://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.test;
import java.util.Map;
import java.util.UUID;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author xiaojing
*/
public class NacosMockTest {
public static Instance serviceInstance(String serviceName, boolean isHealthy,
Map<String, String> metadata) {
Instance instance = new Instance();
instance.setInstanceId(UUID.randomUUID().toString());
instance.setServiceName(serviceName);
instance.setHealthy(isHealthy);
instance.setMetadata(metadata);
return instance;
}
public static Instance serviceInstance(String serviceName, boolean isHealthy,
String host, int port, Map<String, String> metadata) {
Instance instance = new Instance();
instance.setIp(host);
instance.setPort(port);
instance.setServiceName(serviceName);
instance.setHealthy(isHealthy);
instance.setMetadata(metadata);
return instance;
}
}