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

add module nacos-config and nacos-discovery

This commit is contained in:
flystar32
2018-09-15 11:54:53 +08:00
parent 967864fd17
commit 43d47ae71f
61 changed files with 4433 additions and 3 deletions

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.2.0.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<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</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</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</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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</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 org.springframework.cloud.alibaba.nacos;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@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,70 @@
/*
* 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 org.springframework.cloud.alibaba.nacos;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration;
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaojing
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent")
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class })
public class NacosDiscoveryAutoConfiguration {
@Bean
public NacosServiceRegistry nacosServiceRegistry() {
return new NacosServiceRegistry();
}
@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
return new NacosDiscoveryProperties();
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration() {
return new NacosRegistration();
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
ApplicationContext context, NacosServiceRegistry registry, NacosRegistration registration) {
return new NacosAutoServiceRegistration(context, registry, registration);
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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 org.springframework.cloud.alibaba.nacos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.*;
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 NacosDiscoveryClient implements DiscoveryClient {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosDiscoveryClient.class);
public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";
@Autowired
private NacosRegistration nacosRegistration;
@Override
public String description() {
return DESCRIPTION;
}
@Override
public List<ServiceInstance> getInstances(String serviceId) {
try {
NamingService namingService = nacosRegistration.getNacosNamingService();
List<Instance> instances = namingService.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<String, String>();
metadata.put("instanceId", instance.getInstanceId());
metadata.put("weight", instance.getWeight()+"");
metadata.put("healthy", instance.isHealthy()+"");
metadata.put("cluster", instance.getCluster()+"");
metadata.putAll(instance.getMetadata());
nacosServiceInstance.setMetadata(metadata);
return nacosServiceInstance;
}
private static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances,
String serviceId) {
List<ServiceInstance> result = new ArrayList<ServiceInstance>(instances.size());
for (Instance instance: instances) {
result.add(hostToServiceInstance(instance, serviceId));
}
return result;
}
@Override
public List<String> getServices() {
try {
NamingService namingService = nacosRegistration.getNacosNamingService();
ListView<String> services = namingService.getServicesOfServer(1, Integer.MAX_VALUE);
return services.getData();
}catch( Exception e){
LOGGER.error("get service name from nacos server fail,", e);
return Collections.emptyList();
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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 org.springframework.cloud.alibaba.nacos;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaojing
*/
@Configuration
@ConditionalOnMissingBean(DiscoveryClient.class)
@ConditionalOnNacosDiscoveryEnabled
@EnableConfigurationProperties
public class NacosDiscoveryClientAutoConfiguration {
@Bean
public DiscoveryClient nacosDiscoveryClient() {
return new NacosDiscoveryClient();
}
}

View File

@@ -0,0 +1,343 @@
/*
* 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 org.springframework.cloud.alibaba.nacos;
import com.fasterxml.jackson.annotation.JsonIgnore;
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 javax.annotation.PostConstruct;
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;
/**
* @author dungu.zpf
* @author xiaojing
*/
@ConfigurationProperties("spring.cloud.nacos.discovery")
public class NacosDiscoveryProperties {
/**
* nacos naming server address
*/
private String serverAddr;
/**
* nacos naming server endpoint
*/
private String endpoint;
/**
* nacos naming namespacetodo
*/
private String namespace;
/**
* nacos naming log file name
*/
private String logName;
/**
* service name to publish
*/
@Value("${spring.cloud.nacos.discovery.service:${spring.application.name:}}")
private String service;
/**
* weights for service instance
*/
private float weight = 1;
/**
* publish to which virtual clusterName
*/
private String clusterName = "DEFAULT";//todo default value is ?
/**
* extra metadata to publish
*/
private Map<String, String> metadata = new HashMap<>();
/**
* if you just want to subscribe, but don't want to publish your service, set it to
* false.
*/
private boolean registerEnabled = true;
/**
* The ip address your want to publish 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 publish
*/
private String networkInterface = "";
/**
* The port your want to publish 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 nacos discovery
*/
private String accessKey;
/**
* secret key for nacos discovery
*/
private String secretKey;
@Autowired
@JsonIgnore
private InetUtils inetUtils;
@PostConstruct
public void init() throws SocketException {
serverAddr = Objects.toString(serverAddr, "");
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 == networkInterface) {
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);
}
}
}
}
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 InetUtils getInetUtils() {
return inetUtils;
}
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;
}
@Override
public String toString() {
return "NacosDiscoveryProperties{" +
"serverAddr='" + serverAddr + '\'' +
", endpoint='" + endpoint + '\'' +
", namespace='" + namespace + '\'' +
", logName='" + logName + '\'' +
", service='" + service + '\'' +
", weight=" + weight +
", clusterName='" + clusterName + '\'' +
", 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.clusterName-name:}"));
}
if(StringUtils.isEmpty(this.getEndpoint())) {
this.setEndpoint(env.resolvePlaceholders("${spring.cloud.nacos.discovery.endpoint:}"));
}
}
}

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 org.springframework.cloud.alibaba.nacos;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import java.net.URI;
import java.util.Map;
/**
* @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,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 org.springframework.cloud.alibaba.nacos.endpoint;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
/**
* Endpoint for nacos discovery, get nacos properties and subscribed services
* @author xiaojing
*/
@Endpoint(id = "nacos-discovery")
public class NacosDiscoveryEndpoint {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosDiscoveryEndpoint.class);
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired
private NacosRegistration nacosRegistration;
/**
* @return nacos discovery endpoint
*/
@ReadOperation
public Map<String, Object> nacosDiscovery() {
Map<String, Object> result = new HashMap<>();
result.put("NacosDiscoveryProperties", nacosDiscoveryProperties);
NamingService namingService = nacosRegistration.getNacosNamingService();
List<ServiceInfo> subscribe = Collections.emptyList() ;
try{
subscribe = namingService.getSubscribeServices();
} catch (Exception e){
LOGGER.error("get subscribe services from nacos fail,", e);
}
result.put("subscribe",subscribe);
return result;
}
}

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 org.springframework.cloud.alibaba.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.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
/**
* @author xiaojing
*/
@ConditionalOnWebApplication
@ConditionalOnClass(Endpoint.class)
public class NacosDiscoveryEndpointAutoConfiguration {
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@Bean
public NacosDiscoveryEndpoint nacosDiscoveryEndpoint() {
return new NacosDiscoveryEndpoint();
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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 org.springframework.cloud.alibaba.nacos.registry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
/**
* @author xiaojing
*/
public class NacosAutoServiceRegistration
implements AutoServiceRegistration, SmartLifecycle, Ordered {
private static final Logger logger = LoggerFactory.getLogger(NacosAutoServiceRegistration.class);
@Autowired
private NacosRegistration registration;
private int order = 0;
private AtomicBoolean running = new AtomicBoolean(false);
private AtomicInteger port = new AtomicInteger(0);
private ApplicationContext context;
private ServiceRegistry serviceRegistry;
public NacosAutoServiceRegistration(ApplicationContext context,
ServiceRegistry<NacosRegistration> serviceRegistry,
NacosRegistration registration) {
this.context = context;
this.serviceRegistry = serviceRegistry;
this.registration = registration;
}
@Override
public void start() {
if (this.port.get() != 0) {
this.registration.setPort(port.get());
}
if (!this.running.get() && this.registration.getPort() > 0) {
this.serviceRegistry.register(this.registration);
this.context
.publishEvent(new InstanceRegisteredEvent(this, this.registration));
this.running.set(true);
}
}
@Override
public void stop() {
this.serviceRegistry.deregister(this.registration);
this.running.set(false);
}
@Override
public boolean isRunning() {
return this.running.get();
}
@Override
public int getPhase() {
return 0;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable callback) {
this.stop();
callback.run();
}
@Override
public int getOrder() {
return this.order;
}
@EventListener(ServletWebServerInitializedEvent.class)
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
int localPort = event.getWebServer().getPort();
if (this.port.get() == 0) {
logger.info("Updating port to {}", localPort);
this.port.compareAndSet(0, localPort);
start();
}
}
@EventListener({ ContextClosedEvent.class })
public void onApplicationEvent(ContextClosedEvent event) {
if (event.getApplicationContext() == this.context) {
this.stop();
}
}
}

View File

@@ -0,0 +1,142 @@
/*
* 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 org.springframework.cloud.alibaba.nacos.registry;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.core.env.Environment;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import javax.annotation.PostConstruct;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import static com.alibaba.nacos.api.PropertyKeyConst.*;
/**
* @author xiaojing
*/
public class NacosRegistration implements Registration, ServiceInstance {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
private NamingService nacosNamingService;
@Autowired
private Environment environment;
@PostConstruct
public void init() {
nacosDiscoveryProperties.overrideFromEnv(environment);
Properties properties = new Properties();
properties.put(SERVER_ADDR, nacosDiscoveryProperties.getServerAddr());
properties.put(NAMESPACE, nacosDiscoveryProperties.getNamespace());
properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, nacosDiscoveryProperties.getLogName());
properties.put(ENDPOINT, nacosDiscoveryProperties.getEndpoint());
properties.put(ACCESS_KEY,nacosDiscoveryProperties.getAccessKey());
properties.put(SECRET_KEY,nacosDiscoveryProperties.getSecretKey());
properties.put(CLUSTER_NAME,nacosDiscoveryProperties.getClusterName());
try {
nacosNamingService = NacosFactory.createNamingService(properties);
}
catch (Exception e) {
}
}
@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) {
if (nacosDiscoveryProperties.getPort() < 0) {
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 nacosNamingService;
}
public void setNacosNamingService(NamingService nacosNamingService) {
this.nacosNamingService = nacosNamingService;
}
public void setNacosDiscoveryProperties(
NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
}
@Override
public String toString() {
return "NacosRegistration{" +
"nacosDiscoveryProperties=" + nacosDiscoveryProperties +
", nacosNamingService=" + nacosNamingService +
'}';
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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 org.springframework.cloud.alibaba.nacos.registry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Cluster;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author xiaojing
*/
public class NacosServiceRegistry implements ServiceRegistry<NacosRegistration> {
private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);
@Override
public void register(NacosRegistration registration) {
if (!registration.isRegisterEnabled()) {
logger.info("Nacos Registration is disabled...");
return;
}
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No service to register for nacos client...");
return;
}
NamingService namingService = registration.getNacosNamingService();
String serviceId = registration.getServiceId();
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight(registration.getRegisterWeight());
instance.setCluster(new Cluster(registration.getCluster()));
try {
namingService.registerInstance(serviceId, instance);
logger.info("nacos registry, {} {}:{} register finished", serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
logger.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
}
}
@Override
public void deregister(NacosRegistration registration) {
logger.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No dom to de-register for nacos client...");
return;
}
NamingService namingService = registration.getNacosNamingService();
String serviceId = registration.getServiceId();
try {
namingService.deregisterInstance(serviceId, registration.getHost(),
registration.getPort(), registration.getCluster());
}
catch (Exception e) {
logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
logger.info("De-registration finished.");
}
@Override
public void close() {
}
@Override
public void setStatus(NacosRegistration registration, String status) {
// nacos doesn't support set status of a particular registration.
}
@Override
public <T> T getStatus(NacosRegistration registration) {
// nacos doesn't support query status of a particular registration.
return null;
}
}

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 org.springframework.cloud.alibaba.nacos.ribbon;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnProperty(value = "ribbon.nacos.enabled", matchIfMissing = true)
public @interface ConditionalOnRibbonNacos {
}

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 org.springframework.cloud.alibaba.nacos.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* integrated Ribbon by default
* @author xiaojing
*/
@Configuration
@ConditionalOnRibbonNacos
public class NacosRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<Server> ribbonServerList(IClientConfig config) {
NacosServerList serverList = new NacosServerList(config.getClientName());
return serverList;
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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 org.springframework.cloud.alibaba.nacos.ribbon;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author xiaojing
*/
public class NacosServerList implements ServerList<Server> {
@Autowired
private NacosRegistration registration;
private String service;
public NacosServerList() {
}
public NacosServerList(String service) {
this.service = service;
}
@Override
public List<Server> getInitialListOfServers() {
try {
List<Instance> instances = registration.getNacosNamingService().selectInstances(service,true);
return hostsToServerList(instances);
}
catch (Exception e) {
throw new IllegalStateException("Can not get nacos hosts, service=" + service, e);
}
}
@Override
public List<Server> getUpdatedListOfServers() {
return getInitialListOfServers();
}
private Server hostToServer(Instance instance) {
Server server = new Server(instance.getIp(), instance.getPort());
return server;
}
private List<Server> hostsToServerList(List<Instance> instances) {
List<Server> result = new ArrayList<Server>(instances.size());
for (Instance instance : instances) {
if (instance.isHealthy()) {
result.add(hostToServer(instance));
}
}
return result;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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 org.springframework.cloud.alibaba.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;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} that sets up Ribbon for Nacos.
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnRibbonNacos
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = NacosRibbonClientConfiguration.class)
public class RibbonNacosAutoConfiguration {
}

View File

@@ -0,0 +1,6 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.nacos.NacosDiscoveryAutoConfiguration,\
org.springframework.cloud.alibaba.nacos.ribbon.RibbonNacosAutoConfiguration,\
org.springframework.cloud.alibaba.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration
org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
org.springframework.cloud.alibaba.nacos.NacosDiscoveryClientAutoConfiguration

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 org.springframework.cloud.alibaba.nacos;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author xiaojing
*/
public class NacosDiscoveryAutoConfigurationTests {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(NacosDiscoveryTestConfiguration.class,
NacosDiscoveryAutoConfiguration.class))
.withPropertyValues("spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080")
.withPropertyValues("spring.cloud.nacos.discovery.port=18080")
.withPropertyValues("spring.cloud.nacos.discovery.service=myapp");
@Test
public void testProperties() {
this.contextRunner.run(context -> {
NacosDiscoveryProperties properties = context
.getBean(NacosDiscoveryProperties.class);
assertThat(properties.getPort()).isEqualTo(18080);
assertThat(properties.getServerAddr()).isEqualTo("127.0.0.1:8080");
assertThat(properties.getService()).isEqualTo("myapp");
});
}
@Test
public void nacosRegistration() {
this.contextRunner.run(context -> {
NacosRegistration nacosRegistration = context
.getBean(NacosRegistration.class);
assertThat(nacosRegistration.getPort()).isEqualTo(18080);
assertThat(nacosRegistration.getServiceId()).isEqualTo("myapp");
assertThat(nacosRegistration.getRegisterWeight()).isEqualTo(1F);
});
}
@Configuration
@AutoConfigureBefore(NacosDiscoveryAutoConfiguration.class)
static class NacosDiscoveryTestConfiguration {
@Bean
AutoServiceRegistrationProperties autoServiceRegistrationProperties() {
return new AutoServiceRegistrationProperties();
}
@Bean
InetUtils inetUtils() {
return new InetUtils(new InetUtilsProperties());
}
}
}

View File

@@ -0,0 +1,67 @@
package org.springframework.cloud.alibaba.nacos.ribbon;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
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 static org.assertj.core.api.Assertions.assertThat;
/**
* Created by yizhan on 2018/9/14.
*/
public class NacosRibbonClientConfigurationTests {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(NacosRibbonTestConfiguration.class,
NacosRibbonClientConfiguration.class,
RibbonNacosAutoConfiguration.class))
.withPropertyValues("spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080")
.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.getService()).isEqualTo("myapp");
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
static class NacosRibbonTestConfiguration {
@Bean
IClientConfig iClientConfig(){
//return new IClientConfig.Builder().s.build();
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.setClientName("myapp");
return config;
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
}