mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4190fbba61 | |||
| 248cd7696b | |||
| a20c665497 | |||
| fe00047ea6 | |||
| dec10f17fe | |||
| 0c3e7294d8 | |||
| eea48c73cc | |||
| 6c0edee13e | |||
| fd8a6a6f6c | |||
| 344fc8be51 | |||
| b264579012 | |||
| f64d794017 | |||
| 573e8ed6c5 | |||
| 0567f0f4e1 | |||
| 4dd45a4709 | |||
| 17b3b7f858 | |||
| 0c35595b44 | |||
| 076a1648a2 | |||
| 71036479a1 | |||
| 447171de80 | |||
| 802958b218 | |||
| 0e38870735 | |||
| abdd0d29cb | |||
| 625b44e185 | |||
| c19bd51584 | |||
| 569f3f02c1 | |||
| ac0712d330 | |||
| 62b289f3ff | |||
| 2f3460f3f5 | |||
| 43a79105e0 | |||
| bcc262db15 | |||
| e8de5cc8aa | |||
| 8f008191ad | |||
| e26ef50af4 | |||
| 359b3ea522 | |||
| 336476b15d | |||
| fa49d5f03c | |||
| 9abfee6737 | |||
| 956acad43e | |||
| 7316db75be | |||
| b5b26481bd | |||
| 6540555920 | |||
| 1934c4760d | |||
| 25689b800e | |||
| 11f8f02de6 | |||
| 9fb88da84c | |||
| 29b955fffb | |||
| 6617c9aef8 | |||
| 96a3807721 | |||
| 1710d827fb | |||
| d96b0759f4 | |||
| 5135916175 | |||
| c07701d98e |
+1
-1
@@ -70,7 +70,7 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>2.2.2.RELEASE</version>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -71,7 +71,7 @@ These artifacts are available from Maven Central and Spring Release repository v
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>2.2.2.RELEASE</version>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
<properties>
|
||||
<!-- Project revision -->
|
||||
<revision>2.2.3-SNAPSHOT</revision>
|
||||
<revision>2.2.4.RELEASE</revision>
|
||||
|
||||
<!-- Dependency Versions -->
|
||||
<spring-cloud-commons.version>2.2.5.RELEASE</spring-cloud-commons.version>
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
<description>Spring Cloud Alibaba Dependencies</description>
|
||||
|
||||
<properties>
|
||||
<revision>2.2.3.RELEASE</revision>
|
||||
<revision>2.2.4.RELEASE</revision>
|
||||
<sentinel.version>1.8.0</sentinel.version>
|
||||
<seata.version>1.3.0</seata.version>
|
||||
<nacos.client.version>1.3.3</nacos.client.version>
|
||||
<nacos.client.version>1.4.1</nacos.client.version>
|
||||
<nacos.config.version>0.8.0</nacos.config.version>
|
||||
<spring.context.support.version>1.0.10</spring.context.support.version>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>2.2.3.RELEASE</version>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -8,7 +8,7 @@ If you’re a Maven Central user, add our BOM to your pom.xml <dependencyManagem
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>2.2.3.RELEASE</version>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
== Introduction
|
||||
|
||||
Spring Cloud Alibaba aims to provide a one-stop solution for microservices development. This prjoect includes the required components for developing distributed applications and services, so that developers can develop distributed applications easily with the Spring Cloud programming models.
|
||||
Spring Cloud Alibaba aims to provide a one-stop solution for microservices development. This project includes the required components for developing distributed applications and services, so that developers can develop distributed applications easily with the Spring Cloud programming models.
|
||||
|
||||
With Spring Cloud Alibaba, you only need to add a few annotations and configurations, and you will be able to use the distributed solutions of Alibaba for your applications, and build a distributed system of your own with Alibaba middleware.
|
||||
|
||||
@@ -16,4 +16,4 @@ The features of Spring Cloud Alibaba:
|
||||
8. **Alibaba Cloud SchedulerX**:accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds.
|
||||
9. **Alibaba Cloud SMS**: A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
|
||||
|
||||
Spring Cloud Alibaba also provide rich https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples[examples].
|
||||
Spring Cloud Alibaba also provide rich https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples[examples].
|
||||
|
||||
@@ -159,7 +159,7 @@ NOTE: Before you start the provider application, please start Nacos first. Refer
|
||||
==== Start a Consumer Application
|
||||
|
||||
It might not be as easy as starting a provider application, because the consumer needs to call the RESTful service of the provider. In this example, we will use the most primitive way, that is,
|
||||
combining the LoadBalanceClient and RestTemolate explicitly to access the RESTful service.
|
||||
combining the LoadBalanceClient and RestTemplate explicitly to access the RESTful service.
|
||||
You can refer to section 1.2 for pom.xml and application.properties configurations. The following is the sample code for starting a consumer application.
|
||||
|
||||
NOTE: You can also access the service by using RestTemplate and FeignClient with load balancing.
|
||||
|
||||
+73
-3
@@ -18,6 +18,7 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -34,7 +35,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -62,8 +65,12 @@ class UserConfig {
|
||||
|
||||
private String name;
|
||||
|
||||
private String hr;
|
||||
|
||||
private Map<String, Object> map;
|
||||
|
||||
private List<User> users;
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
@@ -88,10 +95,65 @@ class UserConfig {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(List<User> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public String getHr() {
|
||||
return hr;
|
||||
}
|
||||
|
||||
public void setHr(String hr) {
|
||||
this.hr = hr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserConfig{" + "age=" + age + ", name='" + name + '\'' + ", map=" + map
|
||||
+ '}';
|
||||
+ ", hr='" + hr + '\'' + ", users=" + users + '}';
|
||||
}
|
||||
|
||||
public static class User {
|
||||
|
||||
private String name;
|
||||
|
||||
private String hr;
|
||||
|
||||
private String avg;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getHr() {
|
||||
return hr;
|
||||
}
|
||||
|
||||
public void setHr(String hr) {
|
||||
this.hr = hr;
|
||||
}
|
||||
|
||||
public String getAvg() {
|
||||
return avg;
|
||||
}
|
||||
|
||||
public void setAvg(String avg) {
|
||||
this.avg = avg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" + "name='" + name + '\'' + ", hr=" + hr + ", avg=" + avg + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,7 +161,7 @@ class UserConfig {
|
||||
@Component
|
||||
class SampleRunner implements ApplicationRunner {
|
||||
|
||||
@Value("${user.name}")
|
||||
@Value("${user.name:zz}")
|
||||
String userName;
|
||||
|
||||
@Value("${user.age:25}")
|
||||
@@ -156,7 +218,10 @@ class SampleController {
|
||||
@Autowired
|
||||
private NacosConfigManager nacosConfigManager;
|
||||
|
||||
@Value("${user.name}")
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Value("${user.name:zz}")
|
||||
String userName;
|
||||
|
||||
@Value("${user.age:25}")
|
||||
@@ -168,6 +233,11 @@ class SampleController {
|
||||
+ userConfig + "!" + nacosConfigManager.getConfigService();
|
||||
}
|
||||
|
||||
@RequestMapping("/get/{name}")
|
||||
public String getValue(@PathVariable String name) {
|
||||
return String.valueOf(environment.getProperty(name));
|
||||
}
|
||||
|
||||
@RequestMapping("/bool")
|
||||
public boolean bool() {
|
||||
return (Boolean) (userConfig.getMap().get("2"));
|
||||
|
||||
+15
-8
@@ -5,19 +5,26 @@ spring.cloud.nacos.config.server-addr=127.0.0.1:8848
|
||||
spring.cloud.nacos.username=nacos
|
||||
spring.cloud.nacos.password=nacos
|
||||
|
||||
#spring.cloud.nacos.config.namespace=public
|
||||
spring.cloud.nacos.config.name=test-aaa
|
||||
spring.cloud.nacos.config.file-extension=yaml
|
||||
|
||||
#spring.cloud.nacos.config.refreshable-dataids=common.properties
|
||||
#spring.cloud.nacos.config.shared-data-ids=common.properties,base-common.properties
|
||||
spring.cloud.nacos.config.shared-configs[0]= common333.properties
|
||||
spring.cloud.nacos.config.shared-configs[1].data-id= common111.properties
|
||||
spring.cloud.nacos.config.shared-configs[1].group= GROUP_APP1
|
||||
spring.cloud.nacos.config.shared-configs[1].refresh= true
|
||||
spring.cloud.nacos.config.shared-configs[2]= common222.properties
|
||||
#spring.cloud.nacos.config.shared-configs[0]= common333.properties
|
||||
#spring.cloud.nacos.config.shared-configs[1].data-id= common111.properties
|
||||
#spring.cloud.nacos.config.shared-configs[1].group= GROUP_APP1
|
||||
#spring.cloud.nacos.config.shared-configs[1].refresh= true
|
||||
#spring.cloud.nacos.config.shared-configs[2]= common222.properties
|
||||
spring.cloud.nacos.config.shared-configs[0].data-id= test2.yaml
|
||||
spring.cloud.nacos.config.shared-configs[0].refresh=true
|
||||
|
||||
#spring.cloud.nacos.config.ext-config[0]=ext.properties
|
||||
spring.cloud.nacos.config.extension-configs[0].data-id= extension1.properties
|
||||
spring.cloud.nacos.config.extension-configs[0].refresh= true
|
||||
spring.cloud.nacos.config.extension-configs[1]= extension2.properties
|
||||
spring.cloud.nacos.config.extension-configs[2].data-id= extension3.json
|
||||
spring.cloud.nacos.config.extension-configs[0].refresh=true
|
||||
spring.cloud.nacos.config.extension-configs[1].data-id= test1.yml
|
||||
spring.cloud.nacos.config.extension-configs[1].refresh= true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ Metadata|spring.cloud.nacos.discovery.metadata||Extended data, Configure using M
|
||||
log name|spring.cloud.nacos.discovery.log-name||
|
||||
endpoint|spring.cloud.nacos.discovery.endpoint||The domain name of a service, through which the server address can be dynamically obtained.
|
||||
Integration Ribbon|ribbon.nacos.enabled|true|
|
||||
enabled|spring.cloud.nacos.discovery.enabled|true|The switch to enable or disable nacos service discovery
|
||||
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -83,7 +83,7 @@ public class RocketMQProduceApplication {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
if (this.bindingName.equals("output1")) {
|
||||
if ("output1".equals(this.bindingName)) {
|
||||
int count = 5;
|
||||
for (int index = 1; index <= count; index++) {
|
||||
String msgContent = "msg-" + index;
|
||||
@@ -98,7 +98,7 @@ public class RocketMQProduceApplication {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.bindingName.equals("output3")) {
|
||||
else if ("output3".equals(this.bindingName)) {
|
||||
int count = 20;
|
||||
for (int index = 1; index <= count; index++) {
|
||||
String msgContent = "pullMsg-" + index;
|
||||
|
||||
+2
@@ -5,6 +5,8 @@ spring.cloud.nacos.discovery.server-addr=localhost:8848
|
||||
|
||||
#feign.hystrix.enabled=true
|
||||
#feign.sentinel.enabled=true
|
||||
feign.client.config.default.connectTimeout=10000
|
||||
feign.client.config.default.readTimeout=10000
|
||||
|
||||
logging.level.io.seata=debug
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>order-service</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba Seata Example - Business Service</name>
|
||||
<name>Spring Cloud Starter Alibaba Seata Example - Order Service</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
@@ -53,4 +53,4 @@
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
+1
-2
@@ -20,7 +20,6 @@ import com.alibaba.cloud.examples.service.EchoService;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-08-01
|
||||
* <p>
|
||||
* sentinel 降级处理
|
||||
*/
|
||||
@@ -35,7 +34,7 @@ public class EchoServiceFallback implements EchoService {
|
||||
/**
|
||||
* 调用服务提供方的输出接口.
|
||||
* @param str 用户输入
|
||||
* @return
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String echo(String str) {
|
||||
|
||||
-1
@@ -22,7 +22,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-08-01
|
||||
*/
|
||||
@Component
|
||||
public class EchoServiceFallbackFactory implements FallbackFactory<EchoServiceFallback> {
|
||||
|
||||
-1
@@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-08-01
|
||||
* <p>
|
||||
* example feign client
|
||||
*/
|
||||
|
||||
-1
@@ -22,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-08-01
|
||||
*/
|
||||
@RestController
|
||||
public class EchoController {
|
||||
|
||||
+2
-2
@@ -41,10 +41,10 @@ public class ZuulConfiguration {
|
||||
|
||||
@Override
|
||||
public BlockResponse fallbackResponse(String route, Throwable cause) {
|
||||
if (route.equals("my-service3")) {
|
||||
if ("my-service3".equals(route)) {
|
||||
return new BlockResponse(433, "Sentinel Block3", route);
|
||||
}
|
||||
else if (route.equals("my-service4")) {
|
||||
else if ("my-service4".equals(route)) {
|
||||
return new BlockResponse(444, "my-service4", route);
|
||||
}
|
||||
else {
|
||||
|
||||
+2
-2
@@ -52,8 +52,8 @@ import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.servlet.HttpServletBean;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.substringAfter;
|
||||
import static org.apache.commons.lang3.StringUtils.substringBetween;
|
||||
import static org.apache.commons.lang.StringUtils.substringAfter;
|
||||
import static org.apache.commons.lang.StringUtils.substringBetween;
|
||||
import static org.springframework.web.util.UriComponentsBuilder.fromUriString;
|
||||
|
||||
@WebServlet(urlPatterns = "/dsc/*")
|
||||
|
||||
@@ -101,6 +101,12 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!--spring boot-->
|
||||
|
||||
<dependency>
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public final class ConfigConstants {
|
||||
/**
|
||||
* ConfigurationProperties for {@link SentinelZuulProperties}.
|
||||
*/
|
||||
public static final String ZUUl_PREFIX = "spring.cloud.sentinel.zuul";
|
||||
public static final String ZUUL_PREFIX = "spring.cloud.sentinel.zuul";
|
||||
|
||||
/**
|
||||
* ConfigurationProperties for {@link SentinelGatewayProperties}.
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(ZuulServlet.class)
|
||||
@ConditionalOnProperty(prefix = ConfigConstants.ZUUl_PREFIX, name = "enabled",
|
||||
@ConditionalOnProperty(prefix = ConfigConstants.ZUUL_PREFIX, name = "enabled",
|
||||
havingValue = "true", matchIfMissing = true)
|
||||
@EnableConfigurationProperties(SentinelZuulProperties.class)
|
||||
public class SentinelZuulAutoConfiguration {
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@ConfigurationProperties(prefix = ConfigConstants.ZUUl_PREFIX)
|
||||
@ConfigurationProperties(prefix = ConfigConstants.ZUUL_PREFIX)
|
||||
public class SentinelZuulProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
|
||||
+10
@@ -18,6 +18,8 @@ package com.alibaba.cloud.nacos;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureException;
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
@@ -73,6 +75,14 @@ public class NacosConfigManager {
|
||||
return service;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() throws NacosException {
|
||||
if (service != null) {
|
||||
service.shutDown();
|
||||
service = null;
|
||||
}
|
||||
}
|
||||
|
||||
public NacosConfigProperties getNacosConfigProperties() {
|
||||
return nacosConfigProperties;
|
||||
}
|
||||
|
||||
+30
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
@@ -58,6 +62,32 @@ public class NacosPropertySource extends MapPropertySource {
|
||||
this.isRefreshable = isRefreshable;
|
||||
}
|
||||
|
||||
NacosPropertySource(List<PropertySource<?>> propertySources, String group,
|
||||
String dataId, Date timestamp, boolean isRefreshable) {
|
||||
this(group, dataId, getSourceMap(group, dataId, propertySources), timestamp,
|
||||
isRefreshable);
|
||||
}
|
||||
|
||||
private static Map<String, Object> getSourceMap(String group, String dataId,
|
||||
List<PropertySource<?>> propertySources) {
|
||||
if (CollectionUtils.isEmpty(propertySources)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
// If only one, return the internal element, otherwise wrap it.
|
||||
if (propertySources.size() == 1) {
|
||||
PropertySource propertySource = propertySources.get(0);
|
||||
if (propertySource != null && propertySource.getSource() instanceof Map) {
|
||||
return (Map<String, Object>) propertySource.getSource();
|
||||
}
|
||||
}
|
||||
// If it is multiple, it will be returned as it is, and the internal elements
|
||||
// cannot be directly retrieved, so the user needs to implement the retrieval
|
||||
// logic by himself
|
||||
return Collections.singletonMap(
|
||||
String.join(NacosConfigProperties.COMMAS, dataId, group),
|
||||
propertySources);
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
+14
-15
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.parser.NacosDataParserHandler;
|
||||
@@ -27,6 +27,7 @@ import com.alibaba.nacos.api.exception.NacosException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -38,8 +39,6 @@ public class NacosPropertySourceBuilder {
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(NacosPropertySourceBuilder.class);
|
||||
|
||||
private static final Map<String, Object> EMPTY_MAP = new LinkedHashMap();
|
||||
|
||||
private ConfigService configService;
|
||||
|
||||
private long timeout;
|
||||
@@ -71,14 +70,15 @@ public class NacosPropertySourceBuilder {
|
||||
*/
|
||||
NacosPropertySource build(String dataId, String group, String fileExtension,
|
||||
boolean isRefreshable) {
|
||||
Map<String, Object> p = loadNacosData(dataId, group, fileExtension);
|
||||
NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId,
|
||||
p, new Date(), isRefreshable);
|
||||
List<PropertySource<?>> propertySources = loadNacosData(dataId, group,
|
||||
fileExtension);
|
||||
NacosPropertySource nacosPropertySource = new NacosPropertySource(propertySources,
|
||||
group, dataId, new Date(), isRefreshable);
|
||||
NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
|
||||
return nacosPropertySource;
|
||||
}
|
||||
|
||||
private Map<String, Object> loadNacosData(String dataId, String group,
|
||||
private List<PropertySource<?>> loadNacosData(String dataId, String group,
|
||||
String fileExtension) {
|
||||
String data = null;
|
||||
try {
|
||||
@@ -87,24 +87,23 @@ public class NacosPropertySourceBuilder {
|
||||
log.warn(
|
||||
"Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]",
|
||||
dataId, group);
|
||||
return EMPTY_MAP;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format(
|
||||
"Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId,
|
||||
group, data));
|
||||
}
|
||||
Map<String, Object> dataMap = NacosDataParserHandler.getInstance()
|
||||
.parseNacosData(data, fileExtension);
|
||||
return dataMap == null ? EMPTY_MAP : dataMap;
|
||||
return NacosDataParserHandler.getInstance().parseNacosData(dataId, data,
|
||||
fileExtension);
|
||||
}
|
||||
catch (NacosException e) {
|
||||
log.error("get data from Nacos error,dataId:{}, ", dataId, e);
|
||||
log.error("get data from Nacos error,dataId:{} ", dataId, e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("parse data from Nacos error,dataId:{},data:{},", dataId, data, e);
|
||||
log.error("parse data from Nacos error,dataId:{},data:{}", dataId, data, e);
|
||||
}
|
||||
return EMPTY_MAP;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-8
@@ -101,7 +101,6 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
loadSharedConfiguration(composite);
|
||||
loadExtConfiguration(composite);
|
||||
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
|
||||
|
||||
return composite;
|
||||
}
|
||||
|
||||
@@ -156,16 +155,15 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
private void loadNacosConfiguration(final CompositePropertySource composite,
|
||||
List<NacosConfigProperties.Config> configs) {
|
||||
for (NacosConfigProperties.Config config : configs) {
|
||||
String dataId = config.getDataId();
|
||||
String fileExtension = dataId.substring(dataId.lastIndexOf(DOT) + 1);
|
||||
loadNacosDataIfPresent(composite, dataId, config.getGroup(), fileExtension,
|
||||
loadNacosDataIfPresent(composite, config.getDataId(), config.getGroup(),
|
||||
NacosDataParserHandler.getInstance()
|
||||
.getFileExtension(config.getDataId()),
|
||||
config.isRefresh());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkConfiguration(List<NacosConfigProperties.Config> configs,
|
||||
String tips) {
|
||||
String[] dataIds = new String[configs.size()];
|
||||
for (int i = 0; i < configs.size(); i++) {
|
||||
String dataId = configs.get(i).getDataId();
|
||||
if (dataId == null || dataId.trim().length() == 0) {
|
||||
@@ -173,10 +171,7 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
"the [ spring.cloud.nacos.config.%s[%s] ] must give a dataId",
|
||||
tips, i));
|
||||
}
|
||||
dataIds[i] = dataId;
|
||||
}
|
||||
// Just decide that the current dataId must have a suffix
|
||||
NacosDataParserHandler.getInstance().checkDataId(dataIds);
|
||||
}
|
||||
|
||||
private void loadNacosDataIfPresent(final CompositePropertySource composite,
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
*
|
||||
* @author xiaojing
|
||||
*/
|
||||
@Endpoint(id = "nacos-config")
|
||||
@Endpoint(id = "nacosconfig")
|
||||
public class NacosConfigEndpoint {
|
||||
|
||||
private final NacosConfigProperties properties;
|
||||
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public abstract class AbstractNacosDataParser {
|
||||
|
||||
protected static final String DOT = ".";
|
||||
|
||||
protected static final String VALUE = "value";
|
||||
|
||||
protected static final String EMPTY_STRING = "";
|
||||
|
||||
private String extension;
|
||||
|
||||
private AbstractNacosDataParser nextParser;
|
||||
|
||||
protected AbstractNacosDataParser(String extension) {
|
||||
if (StringUtils.isEmpty(extension)) {
|
||||
throw new IllegalArgumentException("extension cannot be empty");
|
||||
}
|
||||
this.extension = extension.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dataId extensions.
|
||||
* @param extension file extension. json or xml or yml or yaml or properties
|
||||
* @return valid or not
|
||||
*/
|
||||
public final boolean checkFileExtension(String extension) {
|
||||
if (this.isLegal(extension.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
if (this.nextParser == null) {
|
||||
return false;
|
||||
}
|
||||
return this.nextParser.checkFileExtension(extension);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsing nacos configuration content.
|
||||
* @param data config data from Nacos
|
||||
* @param extension file extension. json or xml or yml or yaml or properties
|
||||
* @return result of Properties
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
public final Map<String, Object> parseNacosData(String data, String extension)
|
||||
throws IOException {
|
||||
if (extension == null || extension.length() < 1) {
|
||||
throw new IllegalStateException("The file extension cannot be empty");
|
||||
}
|
||||
if (this.isLegal(extension.toLowerCase())) {
|
||||
return this.doParse(data);
|
||||
}
|
||||
if (this.nextParser == null) {
|
||||
throw new IllegalStateException(getTips(extension));
|
||||
}
|
||||
return this.nextParser.parseNacosData(data, extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logic for parsing.
|
||||
* @param data config from Nacos
|
||||
* @return result of Properties
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
protected abstract Map<String, Object> doParse(String data) throws IOException;
|
||||
|
||||
protected AbstractNacosDataParser setNextParser(AbstractNacosDataParser nextParser) {
|
||||
this.nextParser = nextParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractNacosDataParser addNextParser(AbstractNacosDataParser nextParser) {
|
||||
if (this.nextParser == null) {
|
||||
this.nextParser = nextParser;
|
||||
}
|
||||
else {
|
||||
this.nextParser.addNextParser(nextParser);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean isLegal(String extension) {
|
||||
return this.extension.equalsIgnoreCase(extension)
|
||||
|| this.extension.contains(extension);
|
||||
}
|
||||
|
||||
protected void flattenedMap(Map<String, Object> result, Map<String, Object> dataMap,
|
||||
String parentKey) {
|
||||
Set<Map.Entry<String, Object>> entries = dataMap.entrySet();
|
||||
for (Iterator<Map.Entry<String, Object>> iterator = entries.iterator(); iterator
|
||||
.hasNext();) {
|
||||
Map.Entry<String, Object> entry = iterator.next();
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
|
||||
String fullKey = StringUtils.isEmpty(parentKey) ? key : key.startsWith("[")
|
||||
? parentKey.concat(key) : parentKey.concat(DOT).concat(key);
|
||||
|
||||
if (value instanceof Map) {
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
flattenedMap(result, map, fullKey);
|
||||
continue;
|
||||
}
|
||||
else if (value instanceof Collection) {
|
||||
int count = 0;
|
||||
Collection<Object> collection = (Collection<Object>) value;
|
||||
for (Object object : collection) {
|
||||
flattenedMap(result,
|
||||
Collections.singletonMap("[" + (count++) + "]", object),
|
||||
fullKey);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
result.put(fullKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the key ending in `value` if need.
|
||||
*/
|
||||
protected Map<String, Object> reloadMap(Map<String, Object> map) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> result = new LinkedHashMap<>(map);
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.contains(DOT)) {
|
||||
int idx = key.lastIndexOf(DOT);
|
||||
String suffix = key.substring(idx + 1);
|
||||
if (VALUE.equalsIgnoreCase(suffix)) {
|
||||
result.put(key.substring(0, idx), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getTips(String fileName) {
|
||||
return String.format(
|
||||
"[%s] must contains file extension with properties|yaml|yml|xml|json",
|
||||
fileName);
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.env.PropertySourceLoader;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static com.alibaba.cloud.nacos.parser.NacosDataParserHandler.DOT;
|
||||
|
||||
/**
|
||||
* Nacos-specific loader, If need to support other methods of parsing,you need to do the
|
||||
* following steps:
|
||||
* <p>
|
||||
* 1.inherit {@link AbstractPropertySourceLoader} ;<br/>
|
||||
* 2. define the file{@code spring.factories} and append
|
||||
* {@code org.springframework.boot.env.PropertySourceLoader=..}; <br/>
|
||||
* 3.the last step validate.
|
||||
* </p>
|
||||
* Notice the use of {@link NacosByteArrayResource} .
|
||||
*
|
||||
* @author zkz
|
||||
*/
|
||||
public abstract class AbstractPropertySourceLoader implements PropertySourceLoader {
|
||||
|
||||
/**
|
||||
* Prevent interference with other loaders.Nacos-specific loader, unless the reload
|
||||
* changes it.
|
||||
* @param name the root name of the property source. If multiple documents are loaded
|
||||
* an additional suffix should be added to the name for each source loaded.
|
||||
* @param resource the resource to load
|
||||
* @return if the resource can be loaded
|
||||
*/
|
||||
protected boolean canLoad(String name, Resource resource) {
|
||||
return resource instanceof NacosByteArrayResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the resource into one or more property sources. Implementations may either
|
||||
* return a list containing a single source, or in the case of a multi-document format
|
||||
* such as yaml a source for each document in the resource.
|
||||
* @param name the root name of the property source. If multiple documents are loaded
|
||||
* an additional suffix should be added to the name for each source loaded.
|
||||
* @param resource the resource to load
|
||||
* @return a list property sources
|
||||
* @throws IOException if the source cannot be loaded
|
||||
*/
|
||||
@Override
|
||||
public List<PropertySource<?>> load(String name, Resource resource)
|
||||
throws IOException {
|
||||
if (!canLoad(name, resource)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return this.doLoad(name, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the resource into one or more property sources. Implementations may either
|
||||
* return a list containing a single source, or in the case of a multi-document format
|
||||
* such as yaml a source for each document in the resource.
|
||||
* @param name the root name of the property source. If multiple documents are loaded
|
||||
* an additional suffix should be added to the name for each source loaded.
|
||||
* @param resource the resource to load
|
||||
* @return a list property sources
|
||||
* @throws IOException if the source cannot be loaded
|
||||
*/
|
||||
protected abstract List<PropertySource<?>> doLoad(String name, Resource resource)
|
||||
throws IOException;
|
||||
|
||||
protected void flattenedMap(Map<String, Object> result, Map<String, Object> dataMap,
|
||||
String parentKey) {
|
||||
if (dataMap == null || dataMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Set<Entry<String, Object>> entries = dataMap.entrySet();
|
||||
for (Iterator<Entry<String, Object>> iterator = entries.iterator(); iterator
|
||||
.hasNext();) {
|
||||
Map.Entry<String, Object> entry = iterator.next();
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
|
||||
String fullKey = StringUtils.isEmpty(parentKey) ? key : key.startsWith("[")
|
||||
? parentKey.concat(key) : parentKey.concat(DOT).concat(key);
|
||||
|
||||
if (value instanceof Map) {
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
flattenedMap(result, map, fullKey);
|
||||
continue;
|
||||
}
|
||||
else if (value instanceof Collection) {
|
||||
int count = 0;
|
||||
Collection<Object> collection = (Collection<Object>) value;
|
||||
for (Object object : collection) {
|
||||
flattenedMap(result,
|
||||
Collections.singletonMap("[" + (count++) + "]", object),
|
||||
fullKey);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
result.put(fullKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
/**
|
||||
* Nacos-specific resource.
|
||||
*
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosByteArrayResource extends ByteArrayResource {
|
||||
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* Create a new {@code ByteArrayResource}.
|
||||
* @param byteArray the byte array to wrap
|
||||
*/
|
||||
public NacosByteArrayResource(byte[] byteArray) {
|
||||
super(byteArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ByteArrayResource} with a description.
|
||||
* @param byteArray the byte array to wrap
|
||||
* @param description where the byte array comes from
|
||||
*/
|
||||
public NacosByteArrayResource(byte[] byteArray, String description) {
|
||||
super(byteArray, description);
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation always returns {@code null}, assuming that this resource type
|
||||
* does not have a filename.
|
||||
*/
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return null == this.filename ? this.getDescription() : this.filename;
|
||||
}
|
||||
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
* @author yuhuangbin
|
||||
*/
|
||||
public class NacosDataJsonParser extends AbstractNacosDataParser {
|
||||
|
||||
protected NacosDataJsonParser() {
|
||||
super("json");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> doParse(String data) throws IOException {
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> map = parseJSON2Map(data);
|
||||
return this.reloadMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON to Map.
|
||||
* @param json json data
|
||||
* @return the map convert by json string
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
private Map<String, Object> parseJSON2Map(String json) throws IOException {
|
||||
Map<String, Object> result = new LinkedHashMap<>(32);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, Object> nacosDataMap = mapper.readValue(json, LinkedHashMap.class);
|
||||
|
||||
if (CollectionUtils.isEmpty(nacosDataMap)) {
|
||||
return result;
|
||||
}
|
||||
flattenedMap(result, nacosDataMap, EMPTY_STRING);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+111
-35
@@ -17,63 +17,139 @@
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.env.OriginTrackedMapPropertySource;
|
||||
import org.springframework.boot.env.PropertySourceLoader;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public final class NacosDataParserHandler {
|
||||
|
||||
private AbstractNacosDataParser parser;
|
||||
/**
|
||||
* symbol: dot.
|
||||
*/
|
||||
public static final String DOT = ".";
|
||||
|
||||
/**
|
||||
* constant.
|
||||
*/
|
||||
public static final String VALUE = "value";
|
||||
|
||||
/**
|
||||
* default extension.
|
||||
*/
|
||||
public static final String DEFAULT_EXTENSION = "properties";
|
||||
|
||||
private static List<PropertySourceLoader> propertySourceLoaders;
|
||||
|
||||
private NacosDataParserHandler() {
|
||||
parser = this.createParser();
|
||||
propertySourceLoaders = SpringFactoriesLoader
|
||||
.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsing nacos configuration content.
|
||||
* @param data config from Nacos
|
||||
* @param extension file extension. json or xml or yml or yaml or properties
|
||||
* @return result of LinkedHashMap
|
||||
* @param configName name of nacos-config
|
||||
* @param configValue value from nacos-config
|
||||
* @param extension identifies the type of configValue
|
||||
* @return result of Map
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
public Map<String, Object> parseNacosData(String data, String extension)
|
||||
throws IOException {
|
||||
if (null == parser) {
|
||||
parser = this.createParser();
|
||||
public List<PropertySource<?>> parseNacosData(String configName, String configValue,
|
||||
String extension) throws IOException {
|
||||
if (StringUtils.isEmpty(configValue)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return parser.parseNacosData(data, extension);
|
||||
if (StringUtils.isEmpty(extension)) {
|
||||
extension = this.getFileExtension(configName);
|
||||
}
|
||||
for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) {
|
||||
if (!canLoadFileExtension(propertySourceLoader, extension)) {
|
||||
continue;
|
||||
}
|
||||
NacosByteArrayResource nacosByteArrayResource = new NacosByteArrayResource(
|
||||
configValue.getBytes(), configName);
|
||||
nacosByteArrayResource.setFilename(getFileName(configName, extension));
|
||||
List<PropertySource<?>> propertySourceList = propertySourceLoader
|
||||
.load(configName, nacosByteArrayResource);
|
||||
if (CollectionUtils.isEmpty(propertySourceList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return propertySourceList.stream().filter(Objects::nonNull)
|
||||
.map(propertySource -> {
|
||||
if (propertySource instanceof EnumerablePropertySource) {
|
||||
String[] propertyNames = ((EnumerablePropertySource) propertySource)
|
||||
.getPropertyNames();
|
||||
if (propertyNames != null && propertyNames.length > 0) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
Arrays.stream(propertyNames).forEach(name -> {
|
||||
map.put(name, propertySource.getProperty(name));
|
||||
});
|
||||
return new OriginTrackedMapPropertySource(
|
||||
propertySource.getName(), map, true);
|
||||
}
|
||||
}
|
||||
return propertySource;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* check the validity of file extensions in dataid.
|
||||
* @param dataIdAry array of dataId
|
||||
* @return dataId handle success or not
|
||||
* check the current extension can be processed.
|
||||
* @param loader the propertySourceLoader
|
||||
* @param extension file extension
|
||||
* @return if can match extension
|
||||
*/
|
||||
public boolean checkDataId(String... dataIdAry) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (String dataId : dataIdAry) {
|
||||
int idx = dataId.lastIndexOf(AbstractNacosDataParser.DOT);
|
||||
if (idx > 0 && idx < dataId.length() - 1) {
|
||||
String extension = dataId.substring(idx + 1);
|
||||
if (parser.checkFileExtension(extension)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add tips
|
||||
stringBuilder.append(dataId).append(",");
|
||||
}
|
||||
if (stringBuilder.length() > 0) {
|
||||
String result = stringBuilder.substring(0, stringBuilder.length() - 1);
|
||||
throw new IllegalStateException(AbstractNacosDataParser.getTips(result));
|
||||
}
|
||||
return true;
|
||||
private boolean canLoadFileExtension(PropertySourceLoader loader, String extension) {
|
||||
return Arrays.stream(loader.getFileExtensions())
|
||||
.anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(extension,
|
||||
fileExtension));
|
||||
}
|
||||
|
||||
private AbstractNacosDataParser createParser() {
|
||||
return new NacosDataPropertiesParser().addNextParser(new NacosDataYamlParser())
|
||||
.addNextParser(new NacosDataXmlParser())
|
||||
.addNextParser(new NacosDataJsonParser());
|
||||
/**
|
||||
* @param name filename
|
||||
* @return file extension, default {@code DEFAULT_EXTENSION} if don't get
|
||||
*/
|
||||
public String getFileExtension(String name) {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
return DEFAULT_EXTENSION;
|
||||
}
|
||||
int idx = name.lastIndexOf(DOT);
|
||||
if (idx > 0 && idx < name.length() - 1) {
|
||||
return name.substring(idx + 1);
|
||||
}
|
||||
return DEFAULT_EXTENSION;
|
||||
}
|
||||
|
||||
private String getFileName(String name, String extension) {
|
||||
if (StringUtils.isEmpty(extension)) {
|
||||
return name;
|
||||
}
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
return extension;
|
||||
}
|
||||
int idx = name.lastIndexOf(DOT);
|
||||
if (idx > 0 && idx < name.length() - 1) {
|
||||
String ext = name.substring(idx + 1);
|
||||
if (extension.equalsIgnoreCase(ext)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return name + DOT + extension;
|
||||
}
|
||||
|
||||
public static NacosDataParserHandler getInstance() {
|
||||
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataPropertiesParser extends AbstractNacosDataParser {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(NacosDataPropertiesParser.class);
|
||||
|
||||
public NacosDataPropertiesParser() {
|
||||
super("properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> doParse(String data) throws IOException {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new StringReader(data))) {
|
||||
for (String line = reader.readLine(); line != null; line = reader
|
||||
.readLine()) {
|
||||
String dataLine = line.trim();
|
||||
if (StringUtils.isEmpty(dataLine) || dataLine.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
int index = dataLine.indexOf("=");
|
||||
if (index == -1) {
|
||||
log.warn("the config data is invalid {}", dataLine);
|
||||
continue;
|
||||
}
|
||||
String key = dataLine.substring(0, index);
|
||||
String value = dataLine.substring(index + 1);
|
||||
result.put(key.trim(), value.trim());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.config.YamlMapFactoryBean;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataYamlParser extends AbstractNacosDataParser {
|
||||
|
||||
public NacosDataYamlParser() {
|
||||
super(",yml,yaml,");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> doParse(String data) {
|
||||
YamlMapFactoryBean yamlFactory = new YamlMapFactoryBean();
|
||||
yamlFactory.setResources(new ByteArrayResource(data.getBytes()));
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
flattenedMap(result, yamlFactory.getObject(), EMPTY_STRING);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.env.OriginTrackedMapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import static com.alibaba.cloud.nacos.parser.NacosDataParserHandler.DOT;
|
||||
import static com.alibaba.cloud.nacos.parser.NacosDataParserHandler.VALUE;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosJsonPropertySourceLoader extends AbstractPropertySourceLoader {
|
||||
|
||||
/**
|
||||
* Returns the file extensions that the loader supports (excluding the '.').
|
||||
* @return the file extensions
|
||||
*/
|
||||
@Override
|
||||
public String[] getFileExtensions() {
|
||||
return new String[] { "json" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the resource into one or more property sources. Implementations may either
|
||||
* return a list containing a single source, or in the case of a multi-document format
|
||||
* such as yaml a source for each document in the resource.
|
||||
* @param name the root name of the property source. If multiple documents are loaded
|
||||
* an additional suffix should be added to the name for each source loaded.
|
||||
* @param resource the resource to load
|
||||
* @return a list property sources
|
||||
* @throws IOException if the source cannot be loaded
|
||||
*/
|
||||
@Override
|
||||
protected List<PropertySource<?>> doLoad(String name, Resource resource)
|
||||
throws IOException {
|
||||
Map<String, Object> result = new LinkedHashMap<>(32);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, Object> nacosDataMap = mapper.readValue(resource.getInputStream(),
|
||||
LinkedHashMap.class);
|
||||
flattenedMap(result, nacosDataMap, null);
|
||||
return Collections.singletonList(
|
||||
new OriginTrackedMapPropertySource(name, this.reloadMap(result), true));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the key ending in `value` if need.
|
||||
*/
|
||||
protected Map<String, Object> reloadMap(Map<String, Object> map) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> result = new LinkedHashMap<>(map);
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.contains(DOT)) {
|
||||
int idx = key.lastIndexOf(DOT);
|
||||
String suffix = key.substring(idx + 1);
|
||||
if (VALUE.equalsIgnoreCase(suffix)) {
|
||||
result.put(key.substring(0, idx), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+61
-22
@@ -17,8 +17,9 @@
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
@@ -28,39 +29,76 @@ import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.springframework.boot.env.OriginTrackedMapPropertySource;
|
||||
import org.springframework.boot.env.PropertiesPropertySourceLoader;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* With relatively few usage scenarios, only simple parsing is performed to reduce jar
|
||||
* dependencies.
|
||||
* Parsing for XML requires overwriting the default
|
||||
* {@link PropertiesPropertySourceLoader}, because it internally rigorously validates
|
||||
* ({@conde DOCTYPE}) THE XML in a way that makes it difficult to customize the
|
||||
* configuration; at finally, make sure it's in the first place.
|
||||
*
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataXmlParser extends AbstractNacosDataParser {
|
||||
|
||||
public NacosDataXmlParser() {
|
||||
super("xml");
|
||||
}
|
||||
public class NacosXmlPropertySourceLoader extends AbstractPropertySourceLoader
|
||||
implements Ordered {
|
||||
|
||||
/**
|
||||
* Get the order value of this object.
|
||||
* <p>
|
||||
* Higher values are interpreted as lower priority. As a consequence, the object with
|
||||
* the lowest value has the highest priority (somewhat analogous to Servlet
|
||||
* {@code load-on-startup} values).
|
||||
* <p>
|
||||
* Same order values will result in arbitrary sort positions for the affected objects.
|
||||
* @return the order value
|
||||
* @see #HIGHEST_PRECEDENCE
|
||||
* @see #LOWEST_PRECEDENCE
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, Object> doParse(String data) throws IOException {
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> map = parseXml2Map(data);
|
||||
return this.reloadMap(map);
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseXml2Map(String xml) throws IOException {
|
||||
xml = xml.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll("\\t", "");
|
||||
/**
|
||||
* Returns the file extensions that the loader supports (excluding the '.').
|
||||
* @return the file extensions
|
||||
*/
|
||||
@Override
|
||||
public String[] getFileExtensions() {
|
||||
return new String[] { "xml" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the resource into one or more property sources. Implementations may either
|
||||
* return a list containing a single source, or in the case of a multi-document format
|
||||
* such as yaml a source for each document in the resource.
|
||||
* @param name the root name of the property source. If multiple documents are loaded
|
||||
* an additional suffix should be added to the name for each source loaded.
|
||||
* @param resource the resource to load
|
||||
* @return a list property sources
|
||||
* @throws IOException if the source cannot be loaded
|
||||
*/
|
||||
@Override
|
||||
protected List<PropertySource<?>> doLoad(String name, Resource resource)
|
||||
throws IOException {
|
||||
Map<String, Object> nacosDataMap = parseXml2Map(resource);
|
||||
return Collections.singletonList(
|
||||
new OriginTrackedMapPropertySource(name, nacosDataMap, true));
|
||||
|
||||
}
|
||||
|
||||
private Map<String, Object> parseXml2Map(Resource resource) throws IOException {
|
||||
Map<String, Object> map = new LinkedHashMap<>(32);
|
||||
try {
|
||||
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
|
||||
.newDocumentBuilder();
|
||||
Document document = documentBuilder
|
||||
.parse(new InputSource(new StringReader(xml)));
|
||||
Document document = documentBuilder.parse(resource.getInputStream());
|
||||
if (null == document) {
|
||||
return null;
|
||||
}
|
||||
@@ -89,7 +127,8 @@ public class NacosDataXmlParser extends AbstractNacosDataParser {
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = StringUtils.isEmpty(parentKey) ? name : parentKey + DOT + name;
|
||||
String key = StringUtils.isEmpty(parentKey) ? name
|
||||
: parentKey + NacosDataParserHandler.DOT + name;
|
||||
NamedNodeMap nodeMap = node.getAttributes();
|
||||
parseNodeAttr(nodeMap, map, key);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE && node.hasChildNodes()) {
|
||||
@@ -120,8 +159,8 @@ public class NacosDataXmlParser extends AbstractNacosDataParser {
|
||||
if (StringUtils.isEmpty(node.getNodeValue())) {
|
||||
continue;
|
||||
}
|
||||
map.put(String.join(DOT, parentKey, node.getNodeName()),
|
||||
node.getNodeValue());
|
||||
map.put(String.join(NacosDataParserHandler.DOT, parentKey,
|
||||
node.getNodeName()), node.getNodeValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -4,4 +4,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
|
||||
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
|
||||
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
|
||||
org.springframework.boot.env.PropertySourceLoader=\
|
||||
com.alibaba.cloud.nacos.parser.NacosJsonPropertySourceLoader,\
|
||||
com.alibaba.cloud.nacos.parser.NacosXmlPropertySourceLoader
|
||||
+2
-1
@@ -50,7 +50,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
*/
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PowerMockIgnore("javax.management.*")
|
||||
@PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*",
|
||||
"com.sun.org.apache.xerces.internal.jaxp.*", "org.w3c.dom.*" })
|
||||
@PowerMockRunnerDelegate(SpringRunner.class)
|
||||
@PrepareForTest({ NacosConfigService.class })
|
||||
@SpringBootTest(classes = NacosConfigurationNoSuffixTest.TestConfig.class, properties = {
|
||||
|
||||
+8
-4
@@ -49,7 +49,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
* @author zkz
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PowerMockIgnore("javax.management.*")
|
||||
@PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*",
|
||||
"com.sun.org.apache.xerces.internal.jaxp.*", "org.w3c.dom.*" })
|
||||
@PowerMockRunnerDelegate(SpringRunner.class)
|
||||
@PrepareForTest({ NacosConfigService.class })
|
||||
@SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, properties = {
|
||||
@@ -83,13 +84,15 @@ public class NacosConfigurationXmlJsonTest {
|
||||
throws Throwable {
|
||||
|
||||
if ("xmlApp.xml".equals(args[0]) && "test-group".equals(args[1])) {
|
||||
return "<top>\n" + " <first>one</first>\n"
|
||||
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<top>\n"
|
||||
+ " <first>one</first>\n"
|
||||
+ " <sencond value=\"two\">\n"
|
||||
+ " <third>three</third>\n" + " </sencond>\n"
|
||||
+ "</top>";
|
||||
}
|
||||
if ("test-name.xml".equals(args[0]) && "test-group".equals(args[1])) {
|
||||
return "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
|
||||
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
+ "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
|
||||
+ " <Service name=\"Catalina\"> \n"
|
||||
+ " <Connector value=\"第二个连接器\"> \n"
|
||||
+ " <open>开启服务</open> \n"
|
||||
@@ -108,7 +111,8 @@ public class NacosConfigurationXmlJsonTest {
|
||||
|
||||
if ("test-name-dev.xml".equals(args[0])
|
||||
&& "test-group".equals(args[1])) {
|
||||
return "<application android:label=\"@string/app_name\" android:icon=\"@drawable/osg\">\n"
|
||||
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
+ "<application android:label=\"@string/app_name\" android:icon=\"@drawable/osg\">\n"
|
||||
+ " <activity android:name=\".osgViewer\"\n"
|
||||
+ " android:label=\"@string/app_name\" android:screenOrientation=\"landscape\">\n"
|
||||
+ " <intent-filter>\n"
|
||||
|
||||
+3
-3
@@ -183,17 +183,17 @@ public class NacosDiscoveryProperties {
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* Heart beat interval. Time unit: second.
|
||||
* Heart beat interval. Time unit: millisecond.
|
||||
*/
|
||||
private Integer heartBeatInterval;
|
||||
|
||||
/**
|
||||
* Heart beat timeout. Time unit: second.
|
||||
* Heart beat timeout. Time unit: millisecond.
|
||||
*/
|
||||
private Integer heartBeatTimeout;
|
||||
|
||||
/**
|
||||
* Ip delete timeout. Time unit: second.
|
||||
* Ip delete timeout. Time unit: millisecond.
|
||||
*/
|
||||
private Integer ipDeleteTimeout;
|
||||
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ 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 org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
@@ -59,7 +59,7 @@ public class NacosDiscoveryClientConfiguration {
|
||||
matchIfMissing = true)
|
||||
public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager,
|
||||
NacosDiscoveryProperties nacosDiscoveryProperties,
|
||||
ObjectProvider<TaskScheduler> taskExecutorObjectProvider) {
|
||||
ObjectProvider<ThreadPoolTaskScheduler> taskExecutorObjectProvider) {
|
||||
return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties,
|
||||
taskExecutorObjectProvider);
|
||||
}
|
||||
|
||||
+6
-7
@@ -27,7 +27,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
|
||||
import com.alibaba.cloud.nacos.NacosServiceManager;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.listener.Event;
|
||||
import com.alibaba.nacos.api.naming.listener.EventListener;
|
||||
@@ -41,7 +40,6 @@ 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;
|
||||
|
||||
/**
|
||||
@@ -66,14 +64,15 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
|
||||
|
||||
private final NacosDiscoveryProperties properties;
|
||||
|
||||
private final TaskScheduler taskScheduler;
|
||||
private final ThreadPoolTaskScheduler taskScheduler;
|
||||
|
||||
public NacosWatch(NacosServiceManager nacosServiceManager,
|
||||
NacosDiscoveryProperties properties,
|
||||
ObjectProvider<TaskScheduler> taskScheduler) {
|
||||
ObjectProvider<ThreadPoolTaskScheduler> taskScheduler) {
|
||||
this.nacosServiceManager = nacosServiceManager;
|
||||
this.properties = properties;
|
||||
this.taskScheduler = taskScheduler.getIfAvailable(NacosWatch::getTaskScheduler);
|
||||
this.taskScheduler = taskScheduler.stream().findAny()
|
||||
.orElseGet(NacosWatch::getTaskScheduler);
|
||||
}
|
||||
|
||||
private static ThreadPoolTaskScheduler getTaskScheduler() {
|
||||
@@ -156,7 +155,7 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
|
||||
if (this.watchFuture != null) {
|
||||
// shutdown current user-thread,
|
||||
// then the other daemon-threads will terminate automatic.
|
||||
((ThreadPoolTaskScheduler) this.taskScheduler).shutdown();
|
||||
this.taskScheduler.shutdown();
|
||||
this.watchFuture.cancel(true);
|
||||
}
|
||||
|
||||
@@ -167,7 +166,7 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
|
||||
namingService.unsubscribe(properties.getService(), properties.getGroup(),
|
||||
Arrays.asList(properties.getClusterName()), eventListener);
|
||||
}
|
||||
catch (NacosException e) {
|
||||
catch (Exception e) {
|
||||
log.error("namingService unsubscribe failed, properties:{}", properties,
|
||||
e);
|
||||
}
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.discovery.configclient;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration;
|
||||
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
|
||||
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration;
|
||||
import com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration;
|
||||
@@ -36,7 +37,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
matchIfMissing = false)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration({ NacosDiscoveryAutoConfiguration.class,
|
||||
NacosDiscoveryClientConfiguration.class,
|
||||
NacosServiceAutoConfiguration.class, NacosDiscoveryClientConfiguration.class,
|
||||
NacosReactiveDiscoveryClientConfiguration.class })
|
||||
public class NacosDiscoveryClientConfigServiceBootstrapConfiguration {
|
||||
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
*
|
||||
* @author xiaojing
|
||||
*/
|
||||
@Endpoint(id = "nacos-discovery")
|
||||
@Endpoint(id = "nacosdiscovery")
|
||||
public class NacosDiscoveryEndpoint {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
|
||||
+9
-4
@@ -41,6 +41,10 @@ import static org.springframework.util.ReflectionUtils.rethrowRuntimeException;
|
||||
*/
|
||||
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
|
||||
|
||||
private static final String STATUS_UP = "UP";
|
||||
|
||||
private static final String STATUS_DOWN = "DOWN";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);
|
||||
|
||||
private final NacosDiscoveryProperties nacosDiscoveryProperties;
|
||||
@@ -119,7 +123,8 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
|
||||
@Override
|
||||
public void setStatus(Registration registration, String status) {
|
||||
|
||||
if (!status.equalsIgnoreCase("UP") && !status.equalsIgnoreCase("DOWN")) {
|
||||
if (!STATUS_UP.equalsIgnoreCase(status)
|
||||
&& !STATUS_DOWN.equalsIgnoreCase(status)) {
|
||||
log.warn("can't support status {},please choose UP or DOWN", status);
|
||||
return;
|
||||
}
|
||||
@@ -128,7 +133,7 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
|
||||
|
||||
Instance instance = getNacosInstanceFromRegistration(registration);
|
||||
|
||||
if (status.equalsIgnoreCase("DOWN")) {
|
||||
if (STATUS_DOWN.equalsIgnoreCase(status)) {
|
||||
instance.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
@@ -137,8 +142,8 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
|
||||
|
||||
try {
|
||||
Properties nacosProperties = nacosDiscoveryProperties.getNacosProperties();
|
||||
nacosServiceManager.getNamingMaintainService(nacosProperties)
|
||||
.updateInstance(serviceId, instance);
|
||||
nacosServiceManager.getNamingMaintainService(nacosProperties).updateInstance(
|
||||
serviceId, nacosDiscoveryProperties.getGroup(), instance);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("update nacos instance status fail", e);
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
|
||||
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
+6
-6
@@ -69,9 +69,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
"spring.cloud.nacos.discovery.accessKey=test-accessKey",
|
||||
"spring.cloud.nacos.discovery.ip=8.8.8.8",
|
||||
"spring.cloud.nacos.discovery.secretKey=test-secretKey",
|
||||
"spring.cloud.nacos.discovery.heart-beat-interval=3",
|
||||
"spring.cloud.nacos.discovery.heart-beat-timeout=6",
|
||||
"spring.cloud.nacos.discovery.ip-delete-timeout=9" },
|
||||
"spring.cloud.nacos.discovery.heart-beat-interval=3000",
|
||||
"spring.cloud.nacos.discovery.heart-beat-timeout=6000",
|
||||
"spring.cloud.nacos.discovery.ip-delete-timeout=9000" },
|
||||
webEnvironment = RANDOM_PORT)
|
||||
public class NacosAutoServiceRegistrationTests {
|
||||
|
||||
@@ -186,15 +186,15 @@ public class NacosAutoServiceRegistrationTests {
|
||||
}
|
||||
|
||||
private void checkoutNacosDiscoveryHeartBeatInterval() {
|
||||
assertThat(properties.getHeartBeatInterval()).isEqualTo(Integer.valueOf(3));
|
||||
assertThat(properties.getHeartBeatInterval()).isEqualTo(Integer.valueOf(3000));
|
||||
}
|
||||
|
||||
private void checkoutNacosDiscoveryHeartBeatTimeout() {
|
||||
assertThat(properties.getHeartBeatTimeout()).isEqualTo(Integer.valueOf(6));
|
||||
assertThat(properties.getHeartBeatTimeout()).isEqualTo(Integer.valueOf(6000));
|
||||
}
|
||||
|
||||
private void checkoutNacosDiscoveryIpDeleteTimeout() {
|
||||
assertThat(properties.getIpDeleteTimeout()).isEqualTo(Integer.valueOf(9));
|
||||
assertThat(properties.getIpDeleteTimeout()).isEqualTo(Integer.valueOf(9000));
|
||||
}
|
||||
|
||||
private void checkoutNacosDiscoveryServiceName() {
|
||||
|
||||
+7
-2
@@ -36,6 +36,7 @@ import io.seata.core.context.RootContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
@@ -156,11 +157,15 @@ public class SeataHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
|
||||
public K call() throws Exception {
|
||||
try {
|
||||
RequestContextHolder.setRequestAttributes(requestAttributes);
|
||||
RootContext.bind(xid);
|
||||
if (!StringUtils.isEmpty(xid)) {
|
||||
RootContext.bind(xid);
|
||||
}
|
||||
return actual.call();
|
||||
}
|
||||
finally {
|
||||
RootContext.unbind();
|
||||
if (!StringUtils.isEmpty(xid)) {
|
||||
RootContext.unbind();
|
||||
}
|
||||
RequestContextHolder.resetRequestAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
+119
-23
@@ -17,18 +17,25 @@
|
||||
package com.alibaba.cloud.dubbo.autoconfigure;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition;
|
||||
import com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapStartCommandLineRunner;
|
||||
import com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapWrapper;
|
||||
import com.alibaba.cloud.dubbo.bootstrap.event.DubboBootstrapStartedEvent;
|
||||
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
|
||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent;
|
||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
|
||||
import org.apache.dubbo.config.spring.ServiceBean;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -42,7 +49,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration;
|
||||
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
|
||||
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry;
|
||||
@@ -63,9 +72,11 @@ import static org.springframework.util.ObjectUtils.isEmpty;
|
||||
* Dubbo Service Registration Auto-{@link Configuration}.
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import({ DubboServiceRegistrationEventPublishingAspect.class })
|
||||
@Import({ DubboServiceRegistrationEventPublishingAspect.class,
|
||||
DubboBootstrapStartCommandLineRunner.class })
|
||||
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
|
||||
matchIfMissing = true)
|
||||
@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
|
||||
@@ -106,10 +117,42 @@ public class DubboServiceRegistrationAutoConfiguration {
|
||||
return new RegistryConfig(ADDRESS, PROTOCOL);
|
||||
}
|
||||
|
||||
private Map<ServiceRegistry<Registration>, Set<Registration>> registrations = new ConcurrentHashMap<>();
|
||||
|
||||
@EventListener(DubboBootstrapStartedEvent.class)
|
||||
public void onDubboBootstrapStarted(DubboBootstrapStartedEvent event) {
|
||||
if (!event.getSource().isReady()) {
|
||||
return;
|
||||
}
|
||||
registrations.forEach(
|
||||
(registry, registrations) -> registrations.forEach(registration -> {
|
||||
attachDubboMetadataServiceMetadata(registration);
|
||||
registry.register(registration);
|
||||
}));
|
||||
}
|
||||
|
||||
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
||||
public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
|
||||
Registration registration = event.getSource();
|
||||
attachDubboMetadataServiceMetadata(registration);
|
||||
if (!DubboBootstrap.getInstance().isReady()
|
||||
|| !DubboBootstrap.getInstance().isStarted()) {
|
||||
ServiceRegistry<Registration> registry = event.getRegistry();
|
||||
synchronized (registry) {
|
||||
registrations.putIfAbsent(registry, new HashSet<>());
|
||||
registrations.get(registry).add(registration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
attachDubboMetadataServiceMetadata(registration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EventListener(ServiceInstancePreDeregisteredEvent.class)
|
||||
public void onServiceInstancePreDeregistered(
|
||||
ServiceInstancePreDeregisteredEvent event) {
|
||||
ServiceRegistry<Registration> registry = event.getRegistry();
|
||||
registrations.remove(registry);
|
||||
}
|
||||
|
||||
private void attachDubboMetadataServiceMetadata(Registration registration) {
|
||||
@@ -132,21 +175,67 @@ public class DubboServiceRegistrationAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME)
|
||||
@Aspect
|
||||
class EurekaConfiguration implements SmartInitializingSingleton {
|
||||
|
||||
@Autowired
|
||||
private ObjectProvider<Collection<ServiceBean>> serviceBeans;
|
||||
|
||||
@EventListener(DubboBootstrapStartedEvent.class)
|
||||
public void onDubboBootstrapStarted(DubboBootstrapStartedEvent event) {
|
||||
DubboBootstrapWrapper wrapper = event.getSource();
|
||||
if (!wrapper.isReady()) {
|
||||
return;
|
||||
}
|
||||
registrations.forEach(
|
||||
(registry, registrations) -> registrations.removeIf(registration -> {
|
||||
if (!(registration instanceof EurekaRegistration)) {
|
||||
return false;
|
||||
}
|
||||
EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
|
||||
InstanceInfo instanceInfo = eurekaRegistration
|
||||
.getApplicationInfoManager().getInfo();
|
||||
|
||||
EurekaInstanceConfigBean config = (EurekaInstanceConfigBean) eurekaRegistration
|
||||
.getInstanceConfig();
|
||||
config.setInitialStatus(InstanceInfo.InstanceStatus.UP);
|
||||
|
||||
attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
|
||||
eurekaRegistration.getApplicationInfoManager()
|
||||
.registerAppMetadata(instanceInfo.getMetadata());
|
||||
eurekaRegistration.getApplicationInfoManager()
|
||||
.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
||||
public void onServiceInstancePreRegistered(
|
||||
ServiceInstancePreRegisteredEvent event) {
|
||||
Registration registration = event.getSource();
|
||||
EurekaRegistration eurekaRegistration = EurekaRegistration.class
|
||||
.cast(registration);
|
||||
InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager()
|
||||
.getInfo();
|
||||
attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
|
||||
if (!(registration instanceof EurekaRegistration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DubboBootstrap.getInstance().isReady()
|
||||
&& DubboBootstrap.getInstance().isStarted()) {
|
||||
EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
|
||||
InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager()
|
||||
.getInfo();
|
||||
|
||||
EurekaInstanceConfigBean config = (EurekaInstanceConfigBean) eurekaRegistration
|
||||
.getInstanceConfig();
|
||||
config.setInitialStatus(InstanceInfo.InstanceStatus.UP);
|
||||
|
||||
attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
|
||||
eurekaRegistration.getApplicationInfoManager()
|
||||
.registerAppMetadata(instanceInfo.getMetadata());
|
||||
}
|
||||
else {
|
||||
EurekaRegistration eurekaRegistration = (EurekaRegistration) registration;
|
||||
EurekaInstanceConfigBean config = (EurekaInstanceConfigBean) eurekaRegistration
|
||||
.getInstanceConfig();
|
||||
config.setInitialStatus(InstanceInfo.InstanceStatus.STARTING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,21 +260,28 @@ public class DubboServiceRegistrationAutoConfiguration {
|
||||
@AutoConfigureOrder
|
||||
class ConsulConfiguration {
|
||||
|
||||
/**
|
||||
* Handle the pre-registered event of {@link ServiceInstance} for Consul.
|
||||
* @param event {@link ServiceInstancePreRegisteredEvent}
|
||||
*/
|
||||
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
||||
public void onServiceInstancePreRegistered(
|
||||
ServiceInstancePreRegisteredEvent event) {
|
||||
Registration registration = event.getSource();
|
||||
Class<?> registrationClass = AopUtils.getTargetClass(registration);
|
||||
String registrationClassName = registrationClass.getName();
|
||||
if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME
|
||||
.equalsIgnoreCase(registrationClassName)) {
|
||||
ConsulRegistration consulRegistration = (ConsulRegistration) registration;
|
||||
attachURLsIntoMetadata(consulRegistration);
|
||||
@EventListener(DubboBootstrapStartedEvent.class)
|
||||
public void attachURLsIntoMetadataBeforeReRegist(
|
||||
DubboBootstrapStartedEvent event) {
|
||||
if (!event.getSource().isReady()) {
|
||||
return;
|
||||
}
|
||||
registrations.entrySet().removeIf(entry -> {
|
||||
Set<Registration> registrations = entry.getValue();
|
||||
registrations.removeIf(registration -> {
|
||||
Class<?> registrationClass = AopUtils.getTargetClass(registration);
|
||||
String registrationClassName = registrationClass.getName();
|
||||
return !CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME
|
||||
.equalsIgnoreCase(registrationClassName);
|
||||
});
|
||||
return registrations.isEmpty();
|
||||
});
|
||||
|
||||
registrations.forEach(
|
||||
(registry, registrations) -> registrations.forEach(registration -> {
|
||||
ConsulRegistration consulRegistration = (ConsulRegistration) registration;
|
||||
attachURLsIntoMetadata(consulRegistration);
|
||||
}));
|
||||
}
|
||||
|
||||
private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.dubbo.bootstrap;
|
||||
|
||||
import com.alibaba.cloud.dubbo.bootstrap.event.DubboBootstrapStartedEvent;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* publish Dubbo microsystem startup finish event.
|
||||
*
|
||||
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class DubboBootstrapStartCommandLineRunner
|
||||
implements CommandLineRunner, ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(
|
||||
ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
applicationEventPublisher.publishEvent(
|
||||
new DubboBootstrapStartedEvent(DubboBootstrapWrapper.getInstance()));
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.dubbo.bootstrap;
|
||||
|
||||
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
|
||||
|
||||
/**
|
||||
* Wrapper DubboBootstrap operation.
|
||||
*
|
||||
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
|
||||
*/
|
||||
public final class DubboBootstrapWrapper {
|
||||
|
||||
private DubboBootstrapWrapper() {
|
||||
}
|
||||
|
||||
private static final DubboBootstrapWrapper INSTANCE = new DubboBootstrapWrapper();
|
||||
|
||||
public static DubboBootstrapWrapper getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return DubboBootstrap.getInstance().isStarted()
|
||||
&& DubboBootstrap.getInstance().isReady()
|
||||
&& DubboBootstrap.getInstance().isInitialized();
|
||||
}
|
||||
|
||||
public DubboBootstrap getDubboBootstrap() {
|
||||
return DubboBootstrap.getInstance();
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.dubbo.bootstrap.event;
|
||||
|
||||
import com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapWrapper;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Dubbo microsytem start finish event, every thing is ready.
|
||||
*
|
||||
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
|
||||
*/
|
||||
public class DubboBootstrapStartedEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@code DubboBootstrapStartedEvent}.
|
||||
* @param source the object on which the event initially occurred or with which the
|
||||
* event is associated (never {@code null})
|
||||
*/
|
||||
public DubboBootstrapStartedEvent(DubboBootstrapWrapper source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DubboBootstrapWrapper getSource() {
|
||||
return (DubboBootstrapWrapper) super.getSource();
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -40,6 +40,7 @@ public abstract class AbstractHttpRequestMatcher implements HttpRequestMatcher {
|
||||
* <p>
|
||||
* For example {@code " || "} for URL patterns or {@code " && "} for param
|
||||
* expressions.
|
||||
* @return str
|
||||
*/
|
||||
protected abstract String getToStringInfix();
|
||||
|
||||
|
||||
+3
-3
@@ -77,7 +77,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
/**
|
||||
* Caches the IDs of {@link ApplicationListener}.
|
||||
*/
|
||||
private static final Set<String> registerListeners = new HashSet<>();
|
||||
private static final Set<String> REGISTER_LISTENERS = new HashSet<>();
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@@ -193,7 +193,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
private void registerServiceInstancesChangedEventListener(URL url,
|
||||
NotifyListener listener) {
|
||||
String listenerId = generateId(url);
|
||||
if (registerListeners.add(listenerId)) {
|
||||
if (REGISTER_LISTENERS.add(listenerId)) {
|
||||
applicationContext.addApplicationListener(
|
||||
new ApplicationListener<ServiceInstancesChangedEvent>() {
|
||||
@Override
|
||||
@@ -261,7 +261,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
String listenerId = generateId(url);
|
||||
// The metaservice will restart the new listener. It needs to be optimized
|
||||
// to see whether the original listener can be reused.
|
||||
this.registerListeners.remove(listenerId);
|
||||
REGISTER_LISTENERS.remove(listenerId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+23
-11
@@ -83,7 +83,7 @@ public class DubboCloudRegistry extends FailbackRegistry {
|
||||
/**
|
||||
* Caches the IDs of {@link ApplicationListener}.
|
||||
*/
|
||||
private static final Set<String> registerListeners = new HashSet<>();
|
||||
private static final Set<String> REGISTER_LISTENERS = new HashSet<>();
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@@ -215,7 +215,7 @@ public class DubboCloudRegistry extends FailbackRegistry {
|
||||
private void registerServiceInstancesChangedListener(URL url,
|
||||
ApplicationListener<ServiceInstancesChangedEvent> listener) {
|
||||
String listenerId = generateId(url);
|
||||
if (registerListeners.add(listenerId)) {
|
||||
if (REGISTER_LISTENERS.add(listenerId)) {
|
||||
applicationContext.addApplicationListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ public class DubboCloudRegistry extends FailbackRegistry {
|
||||
.map(templateURL -> templateURL.removeParameter(PID_KEY))
|
||||
.map(templateURL -> {
|
||||
String protocol = templateURL.getProtocol();
|
||||
int port = repository.getDubboProtocolPort(serviceInstance,
|
||||
Integer port = repository.getDubboProtocolPort(serviceInstance,
|
||||
protocol);
|
||||
if (Objects.equals(templateURL.getHost(), host)
|
||||
&& Objects.equals(templateURL.getPort(), port)) { // use
|
||||
@@ -300,15 +300,27 @@ public class DubboCloudRegistry extends FailbackRegistry {
|
||||
return templateURL;
|
||||
}
|
||||
|
||||
URLBuilder clonedURLBuilder = from(templateURL) // remove the
|
||||
// parameters from
|
||||
// the template
|
||||
// URL
|
||||
.setHost(host) // reset the host
|
||||
.setPort(port); // reset the port
|
||||
if (port == null) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(
|
||||
"The protocol[{}] port of Dubbo service instance[host : {}] "
|
||||
+ "can't be resolved",
|
||||
protocol, host);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
URLBuilder clonedURLBuilder = from(templateURL) // remove the
|
||||
// parameters from
|
||||
// the template
|
||||
// URL
|
||||
.setHost(host) // reset the host
|
||||
.setPort(port); // reset the port
|
||||
|
||||
return clonedURLBuilder.build();
|
||||
}).forEach(clonedExportedURLs::add);
|
||||
return clonedURLBuilder.build();
|
||||
}
|
||||
|
||||
}).filter(Objects::nonNull).forEach(clonedExportedURLs::add);
|
||||
});
|
||||
return clonedExportedURLs;
|
||||
}
|
||||
|
||||
+20
-7
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.alibaba.cloud.dubbo.registry;
|
||||
|
||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent;
|
||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstanceRegisteredEvent;
|
||||
import org.aspectj.lang.annotation.After;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.context.ApplicationEventPublisherAware;
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @see ServiceInstancePreRegisteredEvent
|
||||
* @see ServiceInstanceRegisteredEvent
|
||||
* @see ServiceInstancePreDeregisteredEvent
|
||||
*/
|
||||
@Aspect
|
||||
public class DubboServiceRegistrationEventPublishingAspect
|
||||
@@ -41,18 +43,29 @@ public class DubboServiceRegistrationEventPublishingAspect
|
||||
/**
|
||||
* The pointcut expression for {@link ServiceRegistry#register(Registration)}.
|
||||
*/
|
||||
public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && args(registration)";
|
||||
public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && target(registry) && args(registration)";
|
||||
|
||||
/**
|
||||
* The pointcut expression for {@link ServiceRegistry#deregister(Registration)}.
|
||||
*/
|
||||
public static final String DEREGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.deregister(*)) && target(registry) && args(registration)";
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
@Before(REGISTER_POINTCUT_EXPRESSION)
|
||||
public void beforeRegister(Registration registration) {
|
||||
applicationEventPublisher
|
||||
.publishEvent(new ServiceInstancePreRegisteredEvent(registration));
|
||||
@Before(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration")
|
||||
public void beforeRegister(ServiceRegistry registry, Registration registration) {
|
||||
applicationEventPublisher.publishEvent(
|
||||
new ServiceInstancePreRegisteredEvent(registry, registration));
|
||||
}
|
||||
|
||||
@After(REGISTER_POINTCUT_EXPRESSION)
|
||||
public void afterRegister(Registration registration) {
|
||||
@Before(value = DEREGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration")
|
||||
public void beforeDeregister(ServiceRegistry registry, Registration registration) {
|
||||
applicationEventPublisher.publishEvent(
|
||||
new ServiceInstancePreDeregisteredEvent(registry, registration));
|
||||
}
|
||||
|
||||
@After(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration")
|
||||
public void afterRegister(ServiceRegistry registry, Registration registration) {
|
||||
applicationEventPublisher
|
||||
.publishEvent(new ServiceInstanceRegisteredEvent(registration));
|
||||
}
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.dubbo.registry.event;
|
||||
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* The
|
||||
* before-{@link org.springframework.cloud.client.serviceregistry.ServiceRegistry#register(org.springframework.cloud.client.serviceregistry.Registration)
|
||||
* register} event for {@link org.springframework.cloud.client.ServiceInstance}.
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class ServiceInstancePreDeregisteredEvent extends ApplicationEvent {
|
||||
|
||||
private final ServiceRegistry<Registration> registry;
|
||||
|
||||
public ServiceInstancePreDeregisteredEvent(ServiceRegistry<Registration> registry,
|
||||
Registration source) {
|
||||
super(source);
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registration getSource() {
|
||||
return (Registration) super.getSource();
|
||||
}
|
||||
|
||||
public ServiceRegistry<Registration> getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-1
@@ -29,8 +29,12 @@ import org.springframework.context.ApplicationEvent;
|
||||
*/
|
||||
public class ServiceInstancePreRegisteredEvent extends ApplicationEvent {
|
||||
|
||||
public ServiceInstancePreRegisteredEvent(Registration source) {
|
||||
private final ServiceRegistry<Registration> registry;
|
||||
|
||||
public ServiceInstancePreRegisteredEvent(ServiceRegistry<Registration> registry,
|
||||
Registration source) {
|
||||
super(source);
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,4 +42,8 @@ public class ServiceInstancePreRegisteredEvent extends ApplicationEvent {
|
||||
return (Registration) super.getSource();
|
||||
}
|
||||
|
||||
public ServiceRegistry<Registration> getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user