From f34633ebf4f0ac22a5a3ab1db24ec1126339906b Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 10 Jan 2019 15:37:36 +0800 Subject: [PATCH 01/50] Polish spring-cloud-incubator/spring-cloud-alibaba#261 --- .../NacosDiscoveryAutoConfiguration.java | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index ac2872808..34d3dfaff 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -19,7 +19,6 @@ package org.springframework.cloud.alibaba.nacos; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration; @@ -34,38 +33,37 @@ import org.springframework.context.annotation.Configuration; /** * @author xiaojing + * @author Mercy */ - @Configuration @EnableConfigurationProperties @ConditionalOnNacosDiscoveryEnabled -@ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent") @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class, - NacosDiscoveryClientAutoConfiguration.class }) +@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class, + NacosDiscoveryClientAutoConfiguration.class}) @AutoConfigureAfter(AutoServiceRegistrationConfiguration.class) public class NacosDiscoveryAutoConfiguration { - @Bean - public NacosServiceRegistry nacosServiceRegistry() { - return new NacosServiceRegistry(); - } + @Bean + public NacosServiceRegistry nacosServiceRegistry() { + return new NacosServiceRegistry(); + } - @Bean - @ConditionalOnBean(AutoServiceRegistrationProperties.class) - public NacosRegistration nacosRegistration( - NacosDiscoveryProperties nacosDiscoveryProperties, - ApplicationContext context) { - return new NacosRegistration(nacosDiscoveryProperties, context); - } + @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + public NacosRegistration nacosRegistration( + NacosDiscoveryProperties nacosDiscoveryProperties, + ApplicationContext context) { + return new NacosRegistration(nacosDiscoveryProperties, context); + } - @Bean - @ConditionalOnBean(AutoServiceRegistrationProperties.class) - public NacosAutoServiceRegistration nacosAutoServiceRegistration( - NacosServiceRegistry registry, - AutoServiceRegistrationProperties autoServiceRegistrationProperties, - NacosRegistration registration) { - return new NacosAutoServiceRegistration(registry, - autoServiceRegistrationProperties, registration); - } + @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + public NacosAutoServiceRegistration nacosAutoServiceRegistration( + NacosServiceRegistry registry, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + NacosRegistration registration) { + return new NacosAutoServiceRegistration(registry, + autoServiceRegistrationProperties, registration); + } } \ No newline at end of file From 571d0eca156d220dc22794d3b06f37d02e3e0c66 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 10 Jan 2019 17:31:12 +0800 Subject: [PATCH 02/50] Polish spring-cloud-incubator/spring-cloud-alibaba#262 --- pom.xml | 16 +++++-- spring-cloud-alibaba-dependencies/pom.xml | 46 +++++++++++++++++++ .../sentinel-dubbo-consumer-example/pom.xml | 6 ++- .../sentinel-dubbo-provider-example/pom.xml | 7 ++- 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 742b16b8e..da119e47d 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,7 @@ spring-cloud-alibaba-nacos-discovery spring-cloud-stream-binder-rocketmq spring-cloud-alibaba-nacos-config-server + spring-cloud-alibaba-dubbo spring-cloud-alicloud-context spring-cloud-alibaba-examples spring-cloud-alibaba-test @@ -106,10 +107,11 @@ + - org.springframework.cloud - spring-cloud-alibaba-dependencies - ${project.version} + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} pom import @@ -153,6 +155,14 @@ import + + org.springframework.cloud + spring-cloud-alibaba-dependencies + ${project.version} + pom + import + + diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index cc49e9ee0..82ba57696 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -28,6 +28,9 @@ 2.16.0 4.3.1 2.1.6 + 2.6.5 + 0.2.1-SNAPSHOT + 0.0.2 @@ -166,6 +169,49 @@ ${oss.version} + + + com.alibaba + dubbo-dependencies-bom + ${dubbo.version} + pom + import + + + + + com.alibaba + dubbo + ${dubbo.version} + + + org.springframework + spring-context + + + javax.servlet + servlet-api + + + log4j + log4j + + + + + + + com.alibaba.boot + dubbo-spring-boot-starter + ${dubbo-spring-boot.version} + + + + + com.alibaba + dubbo-registry-nacos + ${dubbo-registry-nacos.version} + diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml index 5a2cdbf0a..f10efec51 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml @@ -30,7 +30,11 @@ com.alibaba.boot dubbo-spring-boot-starter - 0.2.0 + + + + com.alibaba + dubbo diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml index 8454515c2..5fde98b0e 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml @@ -29,8 +29,13 @@ com.alibaba.boot dubbo-spring-boot-starter - 0.2.0 + + + com.alibaba + dubbo + + From a6b9f6c5dc888f1987c90ef656fe3fda32761b28 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 10 Jan 2019 22:16:02 +0800 Subject: [PATCH 03/50] Polish spring-cloud-incubator/spring-cloud-alibaba#266 --- .../NacosDiscoveryAutoConfiguration.java | 4 +- .../nacos/NacosDiscoveryProperties.java | 706 +++++++++--------- .../NacosAutoServiceRegistration.java | 120 +-- .../nacos/registry/NacosServiceRegistry.java | 161 ++-- 4 files changed, 505 insertions(+), 486 deletions(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index 34d3dfaff..0a87e58ec 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -45,8 +45,8 @@ import org.springframework.context.annotation.Configuration; public class NacosDiscoveryAutoConfiguration { @Bean - public NacosServiceRegistry nacosServiceRegistry() { - return new NacosServiceRegistry(); + public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) { + return new NacosServiceRegistry(nacosDiscoveryProperties); } @Bean diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java index 86b73bf39..fa6e126cb 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java @@ -19,6 +19,7 @@ package org.springframework.cloud.alibaba.nacos; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.client.naming.utils.UtilAndComs; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -27,366 +28,375 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; + import javax.annotation.PostConstruct; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.util.*; - -import static com.alibaba.nacos.api.PropertyKeyConst.*; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME; +import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; +import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE; +import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; +import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; /** * @author dungu.zpf * @author xiaojing + * @author Mercy */ - @ConfigurationProperties("spring.cloud.nacos.discovery") public class NacosDiscoveryProperties { - private static final Logger LOGGER = LoggerFactory - .getLogger(NacosDiscoveryProperties.class); - - /** - * nacos discovery server address - */ - private String serverAddr; - - /** - * the domain name of a service, through which the server address can be dynamically - * obtained. - */ - private String endpoint; - - /** - * namespace, separation registry of different environments. - */ - private String namespace; - - /** - * nacos naming log file name - */ - private String logName; - - /** - * service name to registry - */ - @Value("${spring.cloud.nacos.discovery.service:${spring.application.name:}}") - private String service; - - /** - * weight for service instance, the larger the value, the larger the weight. - */ - private float weight = 1; - - /** - * cluster name for nacos server. - */ - private String clusterName = "DEFAULT"; - - /** - * naming load from local cache at application start. true is load - */ - private String namingLoadCacheAtStart = "false"; - - /** - * extra metadata to register. - */ - private Map metadata = new HashMap<>(); - - /** - * if you just want to subscribe, but don't want to register your service, set it to - * false. - */ - private boolean registerEnabled = true; - - /** - * The ip address your want to register for your service instance, needn't to set it - * if the auto detect ip works well. - */ - private String ip; - - /** - * which network interface's ip you want to register - */ - private String networkInterface = ""; - - /** - * The port your want to register for your service instance, needn't to set it if the - * auto detect port works well - */ - private int port = -1; - - /** - * whether your service is a https service - */ - private boolean secure = false; - - /** - * access key for namespace. - */ - private String accessKey; - - /** - * secret key for namespace. - */ - private String secretKey; - - @Autowired - private InetUtils inetUtils; - - @Autowired - private Environment environment; - - private NamingService namingService; - - @PostConstruct - public void init() throws SocketException { - - if (secure) { - metadata.put("secure", "true"); - } - - serverAddr = Objects.toString(serverAddr, ""); - endpoint = Objects.toString(endpoint, ""); - namespace = Objects.toString(namespace, ""); - logName = Objects.toString(logName, ""); - - if (StringUtils.isEmpty(ip)) { - // traversing network interfaces if didn't specify a interface - if (StringUtils.isEmpty(networkInterface)) { - ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); - } - else { - NetworkInterface netInterface = NetworkInterface - .getByName(networkInterface); - if (null == networkInterface) { - throw new IllegalArgumentException( - "no such interface " + networkInterface); - } - - Enumeration inetAddress = netInterface.getInetAddresses(); - while (inetAddress.hasMoreElements()) { - InetAddress currentAddress = inetAddress.nextElement(); - if (currentAddress instanceof Inet4Address - && !currentAddress.isLoopbackAddress()) { - ip = currentAddress.getHostAddress(); - break; - } - } - - if (StringUtils.isEmpty(ip)) { - throw new RuntimeException("cannot find available ip from" - + " network interface " + networkInterface); - } - - } - } - - this.overrideFromEnv(environment); - } - - public String getEndpoint() { - return endpoint; - } - - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } - - public String getNamespace() { - return namespace; - } - - public void setNamespace(String namespace) { - this.namespace = namespace; - } - - public String getLogName() { - return logName; - } - - public void setLogName(String logName) { - this.logName = logName; - } - - public void setInetUtils(InetUtils inetUtils) { - this.inetUtils = inetUtils; - } - - public float getWeight() { - return weight; - } - - public void setWeight(float weight) { - this.weight = weight; - } - - public String getClusterName() { - return clusterName; - } - - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - - public String getService() { - return service; - } - - public void setService(String service) { - this.service = service; - } - - public boolean isRegisterEnabled() { - return registerEnabled; - } - - public void setRegisterEnabled(boolean registerEnabled) { - this.registerEnabled = registerEnabled; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getNetworkInterface() { - return networkInterface; - } - - public void setNetworkInterface(String networkInterface) { - this.networkInterface = networkInterface; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public boolean isSecure() { - return secure; - } - - public void setSecure(boolean secure) { - this.secure = secure; - } - - public Map getMetadata() { - return metadata; - } - - public void setMetadata(Map metadata) { - this.metadata = metadata; - } - - public String getServerAddr() { - return serverAddr; - } - - public void setServerAddr(String serverAddr) { - this.serverAddr = serverAddr; - } - - public String getAccessKey() { - return accessKey; - } - - public void setAccessKey(String accessKey) { - this.accessKey = accessKey; - } - - public String getSecretKey() { - return secretKey; - } - - public void setSecretKey(String secretKey) { - this.secretKey = secretKey; - } - - public String getNamingLoadCacheAtStart() { - return namingLoadCacheAtStart; - } - - public void setNamingLoadCacheAtStart(String namingLoadCacheAtStart) { - this.namingLoadCacheAtStart = namingLoadCacheAtStart; - } - - @Override - public String toString() { - return "NacosDiscoveryProperties{" + "serverAddr='" + serverAddr + '\'' - + ", endpoint='" + endpoint + '\'' + ", namespace='" + namespace + '\'' - + ", logName='" + logName + '\'' + ", service='" + service + '\'' - + ", weight=" + weight + ", clusterName='" + clusterName + '\'' - + ", metadata=" + metadata + ", registerEnabled=" + registerEnabled - + ", ip='" + ip + '\'' + ", networkInterface='" + networkInterface + '\'' - + ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey - + ", namingLoadCacheAtStart=" + namingLoadCacheAtStart + '\'' - + ", secretKey='" + secretKey + '\'' + '}'; - } - - public void overrideFromEnv(Environment env) { - - if (StringUtils.isEmpty(this.getServerAddr())) { - this.setServerAddr(env - .resolvePlaceholders("${spring.cloud.nacos.discovery.server-addr:}")); - } - if (StringUtils.isEmpty(this.getNamespace())) { - this.setNamespace(env - .resolvePlaceholders("${spring.cloud.nacos.discovery.namespace:}")); - } - if (StringUtils.isEmpty(this.getAccessKey())) { - this.setAccessKey(env - .resolvePlaceholders("${spring.cloud.nacos.discovery.access-key:}")); - } - if (StringUtils.isEmpty(this.getSecretKey())) { - this.setSecretKey(env - .resolvePlaceholders("${spring.cloud.nacos.discovery.secret-key:}")); - } - if (StringUtils.isEmpty(this.getLogName())) { - this.setLogName( - env.resolvePlaceholders("${spring.cloud.nacos.discovery.log-name:}")); - } - if (StringUtils.isEmpty(this.getClusterName())) { - this.setClusterName(env.resolvePlaceholders( - "${spring.cloud.nacos.discovery.cluster-name:}")); - } - if (StringUtils.isEmpty(this.getEndpoint())) { - this.setEndpoint( - env.resolvePlaceholders("${spring.cloud.nacos.discovery.endpoint:}")); - } - } - - public NamingService namingServiceInstance() { - - if (null != namingService) { - return namingService; - } - - Properties properties = new Properties(); - properties.put(SERVER_ADDR, serverAddr); - properties.put(NAMESPACE, namespace); - properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, logName); - properties.put(ENDPOINT, endpoint); - properties.put(ACCESS_KEY, accessKey); - properties.put(SECRET_KEY, secretKey); - properties.put(CLUSTER_NAME, clusterName); - properties.put(NAMING_LOAD_CACHE_AT_START, namingLoadCacheAtStart); - - try { - namingService = NacosFactory.createNamingService(properties); - return namingService; - } - catch (Exception e) { - LOGGER.error("create naming service error!properties={},e=,", this, e); - return null; - } - } + private static final Logger LOGGER = LoggerFactory + .getLogger(NacosDiscoveryProperties.class); + + /** + * nacos discovery server address + */ + private String serverAddr; + + /** + * the domain name of a service, through which the server address can be dynamically + * obtained. + */ + private String endpoint; + + /** + * namespace, separation registry of different environments. + */ + private String namespace; + + /** + * nacos naming log file name + */ + private String logName; + + /** + * service name to registry + */ + @Value("${spring.cloud.nacos.discovery.service:${spring.application.name:}}") + private String service; + + /** + * weight for service instance, the larger the value, the larger the weight. + */ + private float weight = 1; + + /** + * cluster name for nacos server. + */ + private String clusterName = "DEFAULT"; + + /** + * naming load from local cache at application start. true is load + */ + private String namingLoadCacheAtStart = "false"; + + /** + * extra metadata to register. + */ + private Map metadata = new HashMap<>(); + + /** + * if you just want to subscribe, but don't want to register your service, set it to + * false. + */ + private boolean registerEnabled = true; + + /** + * The ip address your want to register for your service instance, needn't to set it + * if the auto detect ip works well. + */ + private String ip; + + /** + * which network interface's ip you want to register + */ + private String networkInterface = ""; + + /** + * The port your want to register for your service instance, needn't to set it if the + * auto detect port works well + */ + private int port = -1; + + /** + * whether your service is a https service + */ + private boolean secure = false; + + /** + * access key for namespace. + */ + private String accessKey; + + /** + * secret key for namespace. + */ + private String secretKey; + + @Autowired + private InetUtils inetUtils; + + @Autowired + private Environment environment; + + private NamingService namingService; + + @PostConstruct + public void init() throws SocketException { + + if (secure) { + metadata.put("secure", "true"); + } + + serverAddr = Objects.toString(serverAddr, ""); + endpoint = Objects.toString(endpoint, ""); + namespace = Objects.toString(namespace, ""); + logName = Objects.toString(logName, ""); + + if (StringUtils.isEmpty(ip)) { + // traversing network interfaces if didn't specify a interface + if (StringUtils.isEmpty(networkInterface)) { + ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + } else { + NetworkInterface netInterface = NetworkInterface + .getByName(networkInterface); + if (null == networkInterface) { + throw new IllegalArgumentException( + "no such interface " + networkInterface); + } + + Enumeration inetAddress = netInterface.getInetAddresses(); + while (inetAddress.hasMoreElements()) { + InetAddress currentAddress = inetAddress.nextElement(); + if (currentAddress instanceof Inet4Address + && !currentAddress.isLoopbackAddress()) { + ip = currentAddress.getHostAddress(); + break; + } + } + + if (StringUtils.isEmpty(ip)) { + throw new RuntimeException("cannot find available ip from" + + " network interface " + networkInterface); + } + + } + } + + this.overrideFromEnv(environment); + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getLogName() { + return logName; + } + + public void setLogName(String logName) { + this.logName = logName; + } + + public void setInetUtils(InetUtils inetUtils) { + this.inetUtils = inetUtils; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public boolean isRegisterEnabled() { + return registerEnabled; + } + + public void setRegisterEnabled(boolean registerEnabled) { + this.registerEnabled = registerEnabled; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getNetworkInterface() { + return networkInterface; + } + + public void setNetworkInterface(String networkInterface) { + this.networkInterface = networkInterface; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getServerAddr() { + return serverAddr; + } + + public void setServerAddr(String serverAddr) { + this.serverAddr = serverAddr; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getNamingLoadCacheAtStart() { + return namingLoadCacheAtStart; + } + + public void setNamingLoadCacheAtStart(String namingLoadCacheAtStart) { + this.namingLoadCacheAtStart = namingLoadCacheAtStart; + } + + @Override + public String toString() { + return "NacosDiscoveryProperties{" + "serverAddr='" + serverAddr + '\'' + + ", endpoint='" + endpoint + '\'' + ", namespace='" + namespace + '\'' + + ", logName='" + logName + '\'' + ", service='" + service + '\'' + + ", weight=" + weight + ", clusterName='" + clusterName + '\'' + + ", metadata=" + metadata + ", registerEnabled=" + registerEnabled + + ", ip='" + ip + '\'' + ", networkInterface='" + networkInterface + '\'' + + ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey + + ", namingLoadCacheAtStart=" + namingLoadCacheAtStart + '\'' + + ", secretKey='" + secretKey + '\'' + '}'; + } + + public void overrideFromEnv(Environment env) { + + if (StringUtils.isEmpty(this.getServerAddr())) { + this.setServerAddr(env + .resolvePlaceholders("${spring.cloud.nacos.discovery.server-addr:}")); + } + if (StringUtils.isEmpty(this.getNamespace())) { + this.setNamespace(env + .resolvePlaceholders("${spring.cloud.nacos.discovery.namespace:}")); + } + if (StringUtils.isEmpty(this.getAccessKey())) { + this.setAccessKey(env + .resolvePlaceholders("${spring.cloud.nacos.discovery.access-key:}")); + } + if (StringUtils.isEmpty(this.getSecretKey())) { + this.setSecretKey(env + .resolvePlaceholders("${spring.cloud.nacos.discovery.secret-key:}")); + } + if (StringUtils.isEmpty(this.getLogName())) { + this.setLogName( + env.resolvePlaceholders("${spring.cloud.nacos.discovery.log-name:}")); + } + if (StringUtils.isEmpty(this.getClusterName())) { + this.setClusterName(env.resolvePlaceholders( + "${spring.cloud.nacos.discovery.cluster-name:}")); + } + if (StringUtils.isEmpty(this.getEndpoint())) { + this.setEndpoint( + env.resolvePlaceholders("${spring.cloud.nacos.discovery.endpoint:}")); + } + } + + public NamingService namingServiceInstance() { + + if (null != namingService) { + return namingService; + } + + Properties properties = new Properties(); + properties.put(SERVER_ADDR, serverAddr); + properties.put(NAMESPACE, namespace); + properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, logName); + properties.put(ENDPOINT, endpoint); + properties.put(ACCESS_KEY, accessKey); + properties.put(SECRET_KEY, secretKey); + properties.put(CLUSTER_NAME, clusterName); + properties.put(NAMING_LOAD_CACHE_AT_START, namingLoadCacheAtStart); + + try { + namingService = NacosFactory.createNamingService(properties); + } catch (Exception e) { + LOGGER.error("create naming service error!properties={},e=,", this, e); + return null; + } + return namingService; + } } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java index ec60041ce..24b0a8481 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java @@ -20,83 +20,85 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * @author xiaojing + * @author Mercy */ public class NacosAutoServiceRegistration - extends AbstractAutoServiceRegistration { - private static final Logger LOGGER = LoggerFactory - .getLogger(NacosAutoServiceRegistration.class); + extends AbstractAutoServiceRegistration { + private static final Logger LOGGER = LoggerFactory + .getLogger(NacosAutoServiceRegistration.class); - private NacosRegistration registration; + private NacosRegistration registration; - public NacosAutoServiceRegistration( - ServiceRegistry serviceRegistry, - AutoServiceRegistrationProperties autoServiceRegistrationProperties, - NacosRegistration registration) { - super(serviceRegistry, autoServiceRegistrationProperties); - this.registration = registration; - } + public NacosAutoServiceRegistration( + ServiceRegistry serviceRegistry, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + NacosRegistration registration) { + super(serviceRegistry, autoServiceRegistrationProperties); + this.registration = registration; + } - @Deprecated - public void setPort(int port) { - getPort().set(port); - } + @Deprecated + public void setPort(int port) { + getPort().set(port); + } - @Override - protected NacosRegistration getRegistration() { - if (this.registration.getPort() < 0 && this.getPort().get() > 0) { - this.registration.setPort(this.getPort().get()); - } - Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set"); - return this.registration; - } + @Override + protected NacosRegistration getRegistration() { + if (this.registration.getPort() < 0 && this.getPort().get() > 0) { + this.registration.setPort(this.getPort().get()); + } + Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set"); + return this.registration; + } - @Override - protected NacosRegistration getManagementRegistration() { - return null; - } + @Override + protected NacosRegistration getManagementRegistration() { + return null; + } - @Override - protected void register() { - if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) { - LOGGER.debug("Registration disabled."); - return; - } - if (this.registration.getPort() < 0) { - this.registration.setPort(getPort().get()); - } - super.register(); - } + @Override + protected void register() { + if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) { + LOGGER.debug("Registration disabled."); + return; + } + if (this.registration.getPort() < 0) { + this.registration.setPort(getPort().get()); + } + super.register(); + } - @Override - protected void registerManagement() { - if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) { - return; - } - super.registerManagement(); + @Override + protected void registerManagement() { + if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) { + return; + } + super.registerManagement(); - } + } - @Override - protected Object getConfiguration() { - return this.registration.getNacosDiscoveryProperties(); - } + @Override + protected Object getConfiguration() { + return this.registration.getNacosDiscoveryProperties(); + } - @Override - protected boolean isEnabled() { - return this.registration.getNacosDiscoveryProperties().isRegisterEnabled(); - } + @Override + protected boolean isEnabled() { + return this.registration.getNacosDiscoveryProperties().isRegisterEnabled(); + } - @Override - @SuppressWarnings("deprecation") - protected String getAppName() { - String appName = registration.getNacosDiscoveryProperties().getService(); - return StringUtils.isEmpty(appName) ? super.getAppName() : appName; - } + @Override + @SuppressWarnings("deprecation") + protected String getAppName() { + String appName = registration.getNacosDiscoveryProperties().getService(); + return StringUtils.isEmpty(appName) ? super.getAppName() : appName; + } } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java index f3850a185..121d9f9eb 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java @@ -18,90 +18,97 @@ package org.springframework.cloud.alibaba.nacos.registry; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.util.StringUtils; /** * @author xiaojing + * @author Mercy */ -public class NacosServiceRegistry implements ServiceRegistry { - - private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); - - @Override - public void register(NacosRegistration registration) { - - if (!registration.isRegisterEnabled()) { - logger.info("Nacos Registration is disabled..."); - return; - } - if (StringUtils.isEmpty(registration.getServiceId())) { - logger.info("No service to register for nacos client..."); - return; - } - - NamingService namingService = registration.getNacosNamingService(); - String serviceId = registration.getServiceId(); - - Instance instance = new Instance(); - instance.setIp(registration.getHost()); - instance.setPort(registration.getPort()); - instance.setWeight(registration.getRegisterWeight()); - instance.setClusterName(registration.getCluster()); - instance.setMetadata(registration.getMetadata()); - - try { - namingService.registerInstance(serviceId, instance); - logger.info("nacos registry, {} {}:{} register finished", serviceId, - instance.getIp(), instance.getPort()); - } - catch (Exception e) { - logger.error("nacos registry, {} register failed...{},", serviceId, - registration.toString(), e); - } - } - - @Override - public void deregister(NacosRegistration registration) { - - logger.info("De-registering from Nacos Server now..."); - - if (StringUtils.isEmpty(registration.getServiceId())) { - logger.info("No dom to de-register for nacos client..."); - return; - } - - NamingService namingService = registration.getNacosNamingService(); - String serviceId = registration.getServiceId(); - - try { - namingService.deregisterInstance(serviceId, registration.getHost(), - registration.getPort(), registration.getCluster()); - } - catch (Exception e) { - logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},", - registration.toString(), e); - } - - logger.info("De-registration finished."); - } - - @Override - public void close() { - - } - - @Override - public void setStatus(NacosRegistration registration, String status) { - // nacos doesn't support set status of a particular registration. - } - - @Override - public T getStatus(NacosRegistration registration) { - // nacos doesn't support query status of a particular registration. - return null; - } +public class NacosServiceRegistry implements ServiceRegistry { + + private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); + + private final NacosDiscoveryProperties nacosDiscoveryProperties; + + private final NamingService namingService; + + public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) { + this.nacosDiscoveryProperties = nacosDiscoveryProperties; + this.namingService = nacosDiscoveryProperties.namingServiceInstance(); + } + + + @Override + public void register(Registration registration) { + + if (StringUtils.isEmpty(registration.getServiceId())) { + logger.info("No service to register for nacos client..."); + return; + } + + String serviceId = registration.getServiceId(); + + Instance instance = new Instance(); + instance.setIp(registration.getHost()); + instance.setPort(registration.getPort()); + instance.setWeight(nacosDiscoveryProperties.getWeight()); + instance.setClusterName(nacosDiscoveryProperties.getClusterName()); + instance.setMetadata(registration.getMetadata()); + + try { + namingService.registerInstance(serviceId, instance); + logger.info("nacos registry, {} {}:{} register finished", serviceId, + instance.getIp(), instance.getPort()); + } catch (Exception e) { + logger.error("nacos registry, {} register failed...{},", serviceId, + registration.toString(), e); + } + } + + @Override + public void deregister(Registration registration) { + + logger.info("De-registering from Nacos Server now..."); + + if (StringUtils.isEmpty(registration.getServiceId())) { + logger.info("No dom to de-register for nacos client..."); + return; + } + + NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); + String serviceId = registration.getServiceId(); + + try { + namingService.deregisterInstance(serviceId, registration.getHost(), + registration.getPort(), nacosDiscoveryProperties.getClusterName()); + } catch (Exception e) { + logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},", + registration.toString(), e); + } + + logger.info("De-registration finished."); + } + + @Override + public void close() { + + } + + @Override + public void setStatus(Registration registration, String status) { + // nacos doesn't support set status of a particular registration. + } + + @Override + public T getStatus(Registration registration) { + // nacos doesn't support query status of a particular registration. + return null; + } } From 325d00d1b65e817da9986ebbbe8c9eb6c5c62fd3 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 10 Jan 2019 22:58:12 +0800 Subject: [PATCH 04/50] Polish spring-cloud-incubator/spring-cloud-alibaba#267 --- .../NacosDiscoveryAutoConfiguration.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index 0a87e58ec..ffd67df53 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -16,9 +16,11 @@ package org.springframework.cloud.alibaba.nacos; +import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration; @@ -66,4 +68,21 @@ public class NacosDiscoveryAutoConfiguration { return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); } + + @Bean + @ConditionalOnBean(NacosAutoServiceRegistration.class) // NacosAutoServiceRegistration should be present + @ConditionalOnNotWebApplication // Not Web Application + public ApplicationRunner applicationRunner(NacosAutoServiceRegistration nacosAutoServiceRegistration) { + return args -> { + // WebServerInitializedEvent should not be multicast in Non-Web environment. + // Whatever, NacosAutoServiceRegistration must be checked it's running or not. + if (!nacosAutoServiceRegistration.isRunning()) { // If it's not running, let it start. + // FIXME: Please make sure "spring.cloud.nacos.discovery.port" must be configured on an available port, + // or the startup or Nacos health check will be failed. + nacosAutoServiceRegistration.start(); + // NacosAutoServiceRegistration will be stopped after its destroy() method is invoked. + // @PreDestroy destroy() -> stop() + } + }; + } } \ No newline at end of file From d40555eff464b8b8e28ce8393ff83c6adf856ee6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 11 Jan 2019 13:04:34 +0800 Subject: [PATCH 05/50] Polish spring-cloud-incubator/spring-cloud-alibaba#269 --- spring-cloud-alibaba-dubbo/pom.xml | 158 +++++++ .../DubboRestAutoConfiguration.java | 30 ++ ...oServiceRegistrationAutoConfiguration.java | 46 ++ .../dubbo/registry/DubboRegistration.java | 72 ++++ .../dubbo/registry/SpringCloudRegistry.java | 405 ++++++++++++++++++ .../registry/SpringCloudRegistryFactory.java | 49 +++ ...com.alibaba.dubbo.registry.RegistryFactory | 1 + .../main/resources/META-INF/spring.factories | 3 + ...viceRegistrationAutoConfigurationTest.java | 28 ++ .../bootstrap/DubboSpringCloudBootstrap.java | 52 +++ .../dubbo/service/DefaultEchoService.java | 39 ++ .../alibaba/dubbo/service/EchoService.java | 27 ++ .../src/test/resources/application.yaml | 9 + .../src/test/resources/bootstrap.yaml | 26 ++ 14 files changed, 945 insertions(+) create mode 100644 spring-cloud-alibaba-dubbo/pom.xml create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory create mode 100644 spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/resources/application.yaml create mode 100644 spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml new file mode 100644 index 000000000..1a7d27ac2 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -0,0 +1,158 @@ + + + + spring-cloud-alibaba + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../pom.xml + + 4.0.0 + + spring-cloud-alibaba-dubbo + Spring Cloud Alibaba Dubbo + + + + + + org.springframework.boot + spring-boot-actuator + true + + + + org.springframework.boot + spring-boot-actuator-autoconfigure + true + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.boot + spring-boot + true + + + + org.springframework.boot + spring-boot-autoconfigure + true + + + + + org.springframework.cloud + spring-cloud-commons + true + + + + org.springframework.cloud + spring-cloud-context + true + + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + + + + + com.alibaba.boot + dubbo-spring-boot-starter + + + + com.alibaba + dubbo + + + + + io.netty + netty-all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.github.openfeign + feign-jaxrs2 + 9.7.0 + + + + + junit + junit + test + + + + org.springframework + spring-test + test + + + + org.springframework.boot + spring-boot-starter-web + test + + + + org.springframework.boot + spring-boot-test + test + + + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-discovery + test + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + test + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java new file mode 100644 index 000000000..7108cbbf0 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import org.springframework.context.annotation.Configuration; + +/** + * Spring Boot Auto-Configuration class for Dubbo REST + * + * @author Mercy + */ +@Configuration +public class DubboRestAutoConfiguration { + + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java new file mode 100644 index 000000000..b9bae9815 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration; + +import org.springframework.beans.BeansException; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; + +/** + * {@link DubboServiceRegistrationAutoConfiguration} will register the Dubbo services as the specified Spring cloud + * applications that will not be considered normal ones, but only are used to Dubbo's service discovery even if it is + * based on Spring Cloud Commons abstraction. However, current application will be registered by other + * DiscoveryClientAutoConfiguration. + * + * @author Mercy + */ +@Configuration +@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class, DubboAutoConfiguration.class}) +public class DubboServiceRegistrationAutoConfiguration implements ApplicationContextAware { + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register + SpringCloudRegistryFactory.setApplicationContext(applicationContext); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java new file mode 100644 index 000000000..9a435ff27 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; + +import java.net.URI; +import java.util.Map; + +/** + * The {@link Registration} of Dubbo uses an external of {@link ServiceInstance} instance as the delegate. + * + * @author Mercy + */ +class DubboRegistration implements Registration { + + private final ServiceInstance delegate; + + public DubboRegistration(ServiceInstance delegate) { + this.delegate = delegate; + } + + @Override + public String getServiceId() { + return delegate.getServiceId(); + } + + @Override + public String getHost() { + return delegate.getHost(); + } + + @Override + public int getPort() { + return delegate.getPort(); + } + + @Override + public boolean isSecure() { + return delegate.isSecure(); + } + + @Override + public URI getUri() { + return delegate.getUri(); + } + + @Override + public Map getMetadata() { + return delegate.getMetadata(); + } + + @Override + public String getScheme() { + return delegate.getScheme(); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java new file mode 100644 index 000000000..aa93c7e56 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.UrlUtils; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.support.FailbackRegistry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY; + +/** + * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * + * @author Mercy + */ +public class SpringCloudRegistry extends FailbackRegistry { + + /** + * All supported categories + */ + private static final String[] ALL_SUPPORTED_CATEGORIES = of( + PROVIDERS_CATEGORY, + CONSUMERS_CATEGORY, + ROUTERS_CATEGORY, + CONFIGURATORS_CATEGORY + ); + + private static final int CATEGORY_INDEX = 0; + + private static final int SERVICE_INTERFACE_INDEX = 1; + + private static final int SERVICE_VERSION_INDEX = 2; + + private static final int SERVICE_GROUP_INDEX = 3; + + private static final String WILDCARD = "*"; + + /** + * The separator for service name + */ + private static final String SERVICE_NAME_SEPARATOR = ":"; + + private final ServiceRegistry serviceRegistry; + + private final DiscoveryClient discoveryClient; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS) + */ + private volatile ScheduledExecutorService scheduledExecutorService; + + /** + * The interval in second of lookup service names(only for Dubbo-OPS) + */ + private static final long LOOKUP_INTERVAL = Long.getLong("dubbo.service.names.lookup.interval", 30); + + public SpringCloudRegistry(URL url, ServiceRegistry serviceRegistry, + DiscoveryClient discoveryClient) { + super(url); + this.serviceRegistry = serviceRegistry; + this.discoveryClient = discoveryClient; + } + + @Override + protected void doRegister(URL url) { + final String serviceName = getServiceName(url); + final Registration registration = createRegistration(serviceName, url); + serviceRegistry.register(registration); + } + + @Override + protected void doUnregister(URL url) { + final String serviceName = getServiceName(url); + final Registration registration = createRegistration(serviceName, url); + this.serviceRegistry.deregister(registration); + } + + @Override + protected void doSubscribe(URL url, NotifyListener listener) { + List serviceNames = getServiceNames(url, listener); + doSubscribe(url, listener, serviceNames); + } + + @Override + protected void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } + } + + @Override + public boolean isAvailable() { + return false; + } + + private void shutdownServiceNamesLookup() { + if (scheduledExecutorService != null) { + scheduledExecutorService.shutdown(); + } + } + + private Registration createRegistration(String serviceName, URL url) { + return new DubboRegistration(createServiceInstance(serviceName, url)); + } + + private ServiceInstance createServiceInstance(String serviceName, URL url) { + // Append default category if absent + String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); + URL newURL = url.addParameter(Constants.CATEGORY_KEY, category); + newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol()); + String ip = NetUtils.getLocalHost(); + int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort()); + DefaultServiceInstance serviceInstance = new DefaultServiceInstance(serviceName, ip, port, false); + serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters())); + return serviceInstance; + } + + private String getServiceName(URL url) { + String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); + return getServiceName(url, category); + } + + private String getServiceName(URL url, String category) { + StringBuilder serviceNameBuilder = new StringBuilder(category); + appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); + appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); + appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY); + return serviceNameBuilder.toString(); + } + + private void appendIfPresent(StringBuilder target, URL url, String parameterName) { + String parameterValue = url.getParameter(parameterName); + if (StringUtils.hasText(parameterValue)) { + target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); + } + } + + private void filterServiceNames(List serviceNames, URL url) { + + final String[] categories = getCategories(url); + + final String targetServiceInterface = url.getServiceInterface(); + + final String targetVersion = url.getParameter(Constants.VERSION_KEY); + + final String targetGroup = url.getParameter(Constants.GROUP_KEY); + + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + // split service name to segments + // (required) segments[0] = category + // (required) segments[1] = serviceInterface + // (required) segments[2] = version + // (optional) segments[3] = group + String[] segments = StringUtils.split(serviceName, SERVICE_NAME_SEPARATOR); + int length = segments.length; + if (length < 3) { // must present 3 segments or more + return false; + } + + String category = segments[CATEGORY_INDEX]; + if (Arrays.binarySearch(categories, category) > -1) { // no match category + return false; + } + + String serviceInterface = segments[SERVICE_INTERFACE_INDEX]; + if (!WILDCARD.equals(targetServiceInterface) && + !Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface + return false; + } + + String version = segments[SERVICE_VERSION_INDEX]; + if (!WILDCARD.equals(targetVersion) && + !Objects.equals(targetVersion, version)) { // no match service version + return false; + } + + String group = length > 3 ? segments[SERVICE_GROUP_INDEX] : null; + if (group != null && !WILDCARD.equals(targetGroup) + && !Objects.equals(targetGroup, group)) { // no match service group + return false; + } + + return true; + } + }); + } + + /** + * Get the categories from {@link URL} + * + * @param url {@link URL} + * @return non-null array + */ + private String[] getCategories(URL url) { + return Constants.ANY_VALUE.equals(url.getServiceInterface()) ? + ALL_SUPPORTED_CATEGORIES : of(Constants.DEFAULT_CATEGORY); + } + + private List getAllServiceNames() { + return discoveryClient.getServices(); + } + + /** + * Get the service names from the specified {@link URL url} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @return non-null + */ + private List getServiceNames(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + scheduleServiceNamesLookup(url, listener); + return getServiceNamesForOps(url); + } else { + return doGetServiceNames(url); + } + } + + + private boolean isAdminProtocol(URL url) { + return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + private void scheduleServiceNamesLookup(final URL url, final NotifyListener listener) { + if (scheduledExecutorService == null) { + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + List serviceNames = getAllServiceNames(); + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + boolean accepted = false; + for (String category : ALL_SUPPORTED_CATEGORIES) { + String prefix = category + SERVICE_NAME_SEPARATOR; + if (StringUtils.startsWithIgnoreCase(serviceName, prefix)) { + accepted = true; + break; + } + } + return accepted; + } + }); + doSubscribe(url, listener, serviceNames); + } + }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS); + } + } + + private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) { + for (String serviceName : serviceNames) { + List serviceInstances = discoveryClient.getInstances(serviceName); + notifySubscriber(url, listener, serviceInstances); + // TODO Support Update notification event + } + } + + private List doGetServiceNames(URL url) { + String[] categories = getCategories(url); + List serviceNames = new ArrayList(categories.length); + for (String category : categories) { + final String serviceName = getServiceName(url, category); + serviceNames.add(serviceName); + } + return serviceNames; + } + + /** + * Notify the Healthy {@link ServiceInstance service instance} to subscriber. + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @param serviceInstances all {@link ServiceInstance instances} + */ + private void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) { + List healthyInstances = new LinkedList(serviceInstances); + // Healthy Instances + filterHealthyInstances(healthyInstances); + List urls = buildURLs(url, healthyInstances); + this.notify(url, listener, urls); + } + + private void filterHealthyInstances(Collection instances) { + filter(instances, new Filter() { + @Override + public boolean accept(ServiceInstance data) { + // TODO check the details of status + return serviceRegistry.getStatus(new DubboRegistration(data)) != null; + } + }); + } + + private List buildURLs(URL consumerURL, Collection serviceInstances) { + if (serviceInstances.isEmpty()) { + return Collections.emptyList(); + } + List urls = new LinkedList(); + for (ServiceInstance serviceInstance : serviceInstances) { + URL url = buildURL(serviceInstance); + if (UrlUtils.isMatch(consumerURL, url)) { + urls.add(url); + } + } + return urls; + } + + private URL buildURL(ServiceInstance serviceInstance) { + URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), + serviceInstance.getHost(), + serviceInstance.getPort(), + serviceInstance.getMetadata()); + return url; + } + + /** + * Get the service names for Dubbo OPS + * + * @param url {@link URL} + * @return non-null + */ + private List getServiceNamesForOps(URL url) { + List serviceNames = getAllServiceNames(); + filterServiceNames(serviceNames, url); + return serviceNames; + } + + private void filter(Collection collection, Filter filter) { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + T data = iterator.next(); + if (!filter.accept(data)) { // remove if not accept + iterator.remove(); + } + } + } + + private static T[] of(T... values) { + return values; + } + + /** + * A filter + */ + private interface Filter { + + /** + * Tests whether or not the specified data should be accepted. + * + * @param data The data to be tested + * @return true if and only if data + * should be accepted + */ + boolean accept(T data); + + } + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java new file mode 100644 index 000000000..7402ff974 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; + +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationContext; + +/** + * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * + * @author Mercy + * @see RegistryFactory + * @see SpringCloudRegistry + */ +public class SpringCloudRegistryFactory implements RegistryFactory { + + private static ApplicationContext applicationContext; + + @Override + public Registry getRegistry(URL url) { + ServiceRegistry serviceRegistry = applicationContext.getBean(ServiceRegistry.class); + DiscoveryClient discoveryClient = applicationContext.getBean(DiscoveryClient.class); + return new SpringCloudRegistry(url, serviceRegistry, discoveryClient); + } + + public static void setApplicationContext(ApplicationContext applicationContext) { + SpringCloudRegistryFactory.applicationContext = applicationContext; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory new file mode 100644 index 000000000..77ac945aa --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +spring-cloud=org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..3af4c939c --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java new file mode 100644 index 000000000..ce32e641e --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import org.springframework.boot.test.context.SpringBootTest; + +/** + * {@link DubboServiceRegistrationAutoConfiguration} Test + * + * @author Mercy + */ +@SpringBootTest +public class DubboServiceRegistrationAutoConfigurationTest { +} diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java new file mode 100644 index 000000000..72bd95cfe --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.bootstrap; + +import com.alibaba.dubbo.config.annotation.Reference; + +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.alibaba.dubbo.service.EchoService; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.context.annotation.Bean; + +/** + * Dubbo Spring Cloud Bootstrap + */ +@EnableDiscoveryClient +@EnableAutoConfiguration +public class DubboSpringCloudBootstrap { + + @Reference(version = "1.0.0") + private EchoService echoService; + + @Bean + public ApplicationRunner applicationRunner() { + return arguments -> { + System.out.println(echoService.echo("mercyblitz")); + }; + } + + public static void main(String[] args) { + new SpringApplicationBuilder(DubboSpringCloudBootstrap.class) + .run(args); + } +} + + + diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java new file mode 100644 index 000000000..f0fc0ac01 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service; + +import com.alibaba.dubbo.config.annotation.Service; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * Default {@link EchoService} + * + * @author Mercy + */ +@Service(version = "1.0.0") +@RestController +public class DefaultEchoService implements EchoService { + + @Override + @GetMapping("/echo") + public String echo(@RequestParam String message) { + return "[echo] : " + message; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java new file mode 100644 index 000000000..7bc249f45 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service; + +/** + * Echo Service + * + * @author Mercy + */ +public interface EchoService { + + String echo(String message); +} diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml new file mode 100644 index 000000000..65249ca91 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml @@ -0,0 +1,9 @@ + + +dubbo: + scan: + base-packages: org.springframework.cloud.alibaba.dubbo.service + protocol: + port: 12345 + registry: + address: spring-cloud://dummy \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml new file mode 100644 index 000000000..9a5062a11 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml @@ -0,0 +1,26 @@ +spring: + application: + name: spring-cloud-alibaba-dubbo + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + port: 12345 +eureka: + client: + enabled: false + +--- +spring: + profiles: eureka + cloud: + nacos: + discovery: + enabled: false + register-enabled: false + +eureka: + client: + enabled: true + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ \ No newline at end of file From 53b677f3b7e64e14f8b02238bb262d96a66776a7 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 11 Jan 2019 20:15:19 +0800 Subject: [PATCH 06/50] Polish spring-cloud-incubator/spring-cloud-alibaba#263 --- spring-cloud-alibaba-dubbo/pom.xml | 61 ++++++---- .../DubboRestAutoConfiguration.java | 40 ++++++- .../DubboRestDiscoveryAutoConfiguration.java | 72 ++++++++++++ ...MetadataRegistrationAutoConfiguration.java | 108 ++++++++++++++++++ .../dubbo/registry/SpringCloudRegistry.java | 6 +- .../rest/feign/RestMetadataResolver.java | 74 ++++++++++++ .../bootstrap/DubboSpringCloudBootstrap.java | 34 ++++++ .../dubbo/service/DefaultEchoService.java | 33 +++++- .../alibaba/dubbo/service/EchoService.java | 3 + .../src/test/resources/application.yaml | 12 +- 10 files changed, 406 insertions(+), 37 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml index 1a7d27ac2..1a869a3e4 100644 --- a/spring-cloud-alibaba-dubbo/pom.xml +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -82,31 +82,42 @@ netty-all - - - - - - - - - - - - - - - - - - - - - - - - - + + + org.jboss.resteasy + resteasy-jaxrs + + + + org.jboss.resteasy + resteasy-client + + + + org.jboss.resteasy + resteasy-netty4 + + + + javax.validation + validation-api + + + + org.jboss.resteasy + resteasy-jackson-provider + + + + org.jboss.resteasy + resteasy-jaxb-provider + + + + javax.servlet + javax.servlet-api + provided + diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java index 7108cbbf0..58528da7e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -16,7 +16,18 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Contract; +import feign.jaxrs2.JAXRS2Contract; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; +import org.springframework.cloud.openfeign.support.SpringMvcContract; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.ws.rs.Path; /** * Spring Boot Auto-Configuration class for Dubbo REST @@ -26,5 +37,32 @@ import org.springframework.context.annotation.Configuration; @Configuration public class DubboRestAutoConfiguration { + /** + * A Feign Contract bean for JAX-RS if available + */ + @ConditionalOnClass(Path.class) + @Bean + public Contract jaxrs2Contract() { + return new JAXRS2Contract(); + } + + @Bean + @ConditionalOnMissingBean + public ObjectMapper objectMapper() { + return new ObjectMapper(); + } + + /** + * A Feign Contract bean for Spring MVC if available + */ + @ConditionalOnClass(RequestMapping.class) + @Bean + public Contract springMvcContract() { + return new SpringMvcContract(); + } -} + @Bean + public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) { + return new RestMetadataResolver(objectMapper); + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java new file mode 100644 index 000000000..ddb2fd2b8 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.context.named.NamedContextFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; + +import java.util.Map; + +/** + * The Auto-Configuration class for Dubbo REST Discovery + * + * @author Mercy + */ +@Configuration +@AutoConfigureAfter(value = { + DubboRestAutoConfiguration.class, + DubboRestMetadataRegistrationAutoConfiguration.class}) +public class DubboRestDiscoveryAutoConfiguration { + + + @Autowired + private DiscoveryClient discoveryClient; + + // 1. Get all service names from Spring beans that was annotated by @FeignClient + // 2. Get all service instances by echo specified service name + // 3. Get Rest metadata from service instance + // 4. Resolve REST metadata from the @FeignClient instance + + @Bean + public SmartInitializingSingleton onBeansInitialized(ListableBeanFactory beanFactory) { + return () -> { + Map feignClientBeans = beanFactory.getBeansWithAnnotation(FeignClient.class); + feignClientBeans.forEach((beanName, bean) -> { + if (bean instanceof NamedContextFactory.Specification) { + NamedContextFactory.Specification specification = (NamedContextFactory.Specification) bean; + String serviceName = specification.getName(); + } + }); + }; + } + + @EventListener(ContextRefreshedEvent.class) + public void onContextRefreshed(ContextRefreshedEvent event) { + + } + + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java new file mode 100644 index 000000000..ea9af9a38 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.config.spring.ServiceBean; +import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Contract; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; +import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceName; + +/** + * The Auto-Configuration class for Dubbo REST metadata registration, + * REST metadata that is a part of {@link Registration#getMetadata() Spring Cloud service instances' metadata} + * will be registered Spring Cloud registry. + * + * @author Mercy + */ +@Configuration +@AutoConfigureAfter(value = { + DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class}) +public class DubboRestMetadataRegistrationAutoConfiguration { + + /** + * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, + * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods. + */ + private final Map> restMetadata = new LinkedHashMap<>(); + + /** + * Autowire Feign Contract Beans + */ + @Autowired(required = false) + private Collection contracts = Collections.emptyList(); + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private RestMetadataResolver restMetadataResolver; + + @EventListener(ServiceBeanExportedEvent.class) + public void recordRestMetadata(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + List urls = serviceBean.getExportedUrls(); + Object bean = serviceBean.getRef(); + + Set metadata = contracts.stream() + .map(contract -> contract.parseAndValidatateMetadata(bean.getClass())) + .flatMap(v -> v.stream()) + .map(restMetadataResolver::resolve) + .collect(Collectors.toSet()); + + urls.forEach(url -> { + String serviceName = getServiceName(url); + restMetadata.put(serviceName, metadata); + }); + } + + /** + * Pre-handle Spring Cloud application service registered: + *

+ * Put restMetadata with the JSON format into + * {@link Registration#getMetadata() service instances' metadata} + *

+ * + * @param event {@link InstancePreRegisteredEvent} instance + */ + @EventListener(InstancePreRegisteredEvent.class) + public void registerRestMetadata(InstancePreRegisteredEvent event) throws JsonProcessingException { + Registration registration = event.getRegistration(); + Map serviceInstanceMetadata = registration.getMetadata(); + String restMetadataJson = objectMapper.writeValueAsString(restMetadata); + serviceInstanceMetadata.put("restMetadata", restMetadataJson); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java index aa93c7e56..f9d713406 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -160,12 +160,12 @@ public class SpringCloudRegistry extends FailbackRegistry { return serviceInstance; } - private String getServiceName(URL url) { + public static String getServiceName(URL url) { String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); return getServiceName(url, category); } - private String getServiceName(URL url, String category) { + private static String getServiceName(URL url, String category) { StringBuilder serviceNameBuilder = new StringBuilder(category); appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); @@ -173,7 +173,7 @@ public class SpringCloudRegistry extends FailbackRegistry { return serviceNameBuilder.toString(); } - private void appendIfPresent(StringBuilder target, URL url, String parameterName) { + private static void appendIfPresent(StringBuilder target, URL url, String parameterName) { String parameterValue = url.getParameter(parameterName); if (StringUtils.hasText(parameterValue)) { target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java new file mode 100644 index 000000000..f9127c70e --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.rest.feign; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.MethodMetadata; +import feign.Request; +import feign.RequestTemplate; + +import java.io.IOException; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * The JSON resolver for {@link MethodMetadata} + */ +public class RestMetadataResolver { + + private static final String METHOD_PROPERTY_NAME = "method"; + private static final String URL_PROPERTY_NAME = "url"; + private static final String HEADERS_PROPERTY_NAME = "headers"; + + private final ObjectMapper objectMapper; + + public RestMetadataResolver(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + public String resolve(MethodMetadata methodMetadata) { + String jsonContent = null; + Map metadata = new LinkedHashMap<>(); + RequestTemplate requestTemplate = methodMetadata.template(); + Request request = requestTemplate.request(); + metadata.put(METHOD_PROPERTY_NAME, request.method()); + metadata.put(URL_PROPERTY_NAME, request.url()); + metadata.put(HEADERS_PROPERTY_NAME, request.headers()); + try { + jsonContent = objectMapper.writeValueAsString(metadata); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + return jsonContent; + } + + public Request resolveRequest(String json) { + Request request = null; + try { + Map data = objectMapper.readValue(json, Map.class); + String method = (String) data.get(METHOD_PROPERTY_NAME); + String url = (String) data.get(URL_PROPERTY_NAME); + Map> headers = (Map) data.get(HEADERS_PROPERTY_NAME); + request = Request.create(method, url, headers, null, null); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + return request; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java index 72bd95cfe..8b32a4b94 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -16,14 +16,23 @@ */ package org.springframework.cloud.alibaba.dubbo.bootstrap; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.ReferenceBean; +import com.alibaba.dubbo.config.spring.ServiceBean; +import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.alibaba.dubbo.service.EchoService; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.event.EventListener; + +import java.util.List; /** * Dubbo Spring Cloud Bootstrap @@ -35,6 +44,9 @@ public class DubboSpringCloudBootstrap { @Reference(version = "1.0.0") private EchoService echoService; + @Reference(version = "1.0.0") + private EchoService echoServiceForRest; + @Bean public ApplicationRunner applicationRunner() { return arguments -> { @@ -42,6 +54,28 @@ public class DubboSpringCloudBootstrap { }; } + + @Autowired + private ApplicationConfig applicationConfig; + + @Autowired + private List registries; + + @EventListener(ServiceBeanExportedEvent.class) + public void onServiceBeanExportedEvent(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + ReferenceBean referenceBean = new ReferenceBean(); + referenceBean.setApplication(applicationConfig); + referenceBean.setRegistries(registries); + referenceBean.setInterface(serviceBean.getInterfaceClass()); + referenceBean.setInterface(serviceBean.getInterface()); + referenceBean.setVersion(serviceBean.getVersion()); + referenceBean.setGroup(serviceBean.getGroup()); + Object object = referenceBean.get(); + System.out.println(object); + } + + public static void main(String[] args) { new SpringApplicationBuilder(DubboSpringCloudBootstrap.class) .run(args); diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java index f0fc0ac01..abc2d6414 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java @@ -17,23 +17,48 @@ package org.springframework.cloud.alibaba.dubbo.service; import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.rpc.RpcContext; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; + /** * Default {@link EchoService} * * @author Mercy */ -@Service(version = "1.0.0") +@Service(version = "1.0.0", protocol = {"dubbo", "rest"}) @RestController +@Path("/") public class DefaultEchoService implements EchoService { @Override - @GetMapping("/echo") - public String echo(@RequestParam String message) { - return "[echo] : " + message; + @GetMapping(value = "/echo", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @Path("/echo") + @GET + @Consumes("application/json") + @Produces("application/json;charset=UTF-8") + public String echo(@RequestParam @QueryParam("message") String message) { + return RpcContext.getContext().getUrl() + " [echo] : " + message; + } + + @Override + @PostMapping("/plus") + @Path("/plus") + @POST + public String plus(@RequestParam @QueryParam("a") int a, @RequestParam @QueryParam("b") int b) { + return null; } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java index 7bc249f45..10ace8ec1 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java @@ -24,4 +24,7 @@ package org.springframework.cloud.alibaba.dubbo.service; public interface EchoService { String echo(String message); + + String plus(int a, int b); + } diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml index 65249ca91..113a3aa56 100644 --- a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml +++ b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml @@ -1,9 +1,13 @@ - - dubbo: scan: base-packages: org.springframework.cloud.alibaba.dubbo.service - protocol: - port: 12345 + protocols: + dubbo: + name: dubbo + port: 12345 + rest: + name: rest + port: 9090 + server: netty registry: address: spring-cloud://dummy \ No newline at end of file From 7aa17d376040705bc403f156e343668362fa9990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=A9=AC=E5=93=A5?= Date: Mon, 14 Jan 2019 10:44:11 +0800 Subject: [PATCH 07/50] Temporary commit --- .../DubboRestAutoConfiguration.java | 32 ++-- .../DubboRestDiscoveryAutoConfiguration.java | 169 ++++++++++++++++-- ...MetadataRegistrationAutoConfiguration.java | 38 +++- .../main/resources/META-INF/spring.factories | 4 +- .../bootstrap/DubboSpringCloudBootstrap.java | 31 +++- .../dubbo/service/DefaultEchoService.java | 11 +- .../src/test/resources/application.yaml | 2 +- .../src/test/resources/bootstrap.yaml | 1 - .../nacos-discovery-consumer-example/pom.xml | 24 ++- .../demos/SpringCloudRestClientBootstrap.java | 42 +++++ .../src/main/resources/application.properties | 7 +- 11 files changed, 309 insertions(+), 52 deletions(-) create mode 100644 spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java index 58528da7e..7af8faeba 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -37,14 +37,14 @@ import javax.ws.rs.Path; @Configuration public class DubboRestAutoConfiguration { - /** - * A Feign Contract bean for JAX-RS if available - */ - @ConditionalOnClass(Path.class) - @Bean - public Contract jaxrs2Contract() { - return new JAXRS2Contract(); - } +// /** +// * A Feign Contract bean for JAX-RS if available +// */ +// @ConditionalOnClass(Path.class) +// @Bean +// public Contract jaxrs2Contract() { +// return new JAXRS2Contract(); +// } @Bean @ConditionalOnMissingBean @@ -52,14 +52,14 @@ public class DubboRestAutoConfiguration { return new ObjectMapper(); } - /** - * A Feign Contract bean for Spring MVC if available - */ - @ConditionalOnClass(RequestMapping.class) - @Bean - public Contract springMvcContract() { - return new SpringMvcContract(); - } +// /** +// * A Feign Contract bean for Spring MVC if available +// */ +// @ConditionalOnClass(RequestMapping.class) +// @Bean +// public Contract springMvcContract() { +// return new SpringMvcContract(); +// } @Bean public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java index ddb2fd2b8..93fdc338f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java @@ -16,10 +16,23 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.spring.ReferenceBean; +import feign.Client; +import feign.Request; +import feign.Response; +import org.codehaus.jackson.map.ObjectMapper; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; +import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.context.named.NamedContextFactory; import org.springframework.cloud.openfeign.FeignClient; @@ -27,8 +40,18 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.util.StringUtils; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * The Auto-Configuration class for Dubbo REST Discovery @@ -41,28 +64,148 @@ import java.util.Map; DubboRestMetadataRegistrationAutoConfiguration.class}) public class DubboRestDiscoveryAutoConfiguration { - @Autowired private DiscoveryClient discoveryClient; - // 1. Get all service names from Spring beans that was annotated by @FeignClient - // 2. Get all service instances by echo specified service name - // 3. Get Rest metadata from service instance - // 4. Resolve REST metadata from the @FeignClient instance + @Autowired + private RestMetadataResolver restMetadataResolver; + + @Autowired(required = false) + private ObjectMapper objectMapper = new ObjectMapper(); + + /** + * Feign Request -> Dubbo ReferenceBean + */ + private Map referenceBeanCache = new HashMap<>(); + + @Autowired + private ApplicationConfig applicationConfig; + + @Value("${spring.cloud.nacos.discovery.server-addr}") + private String nacosServerAddress; + + + private volatile boolean initialized = false; + + @Autowired + private ListableBeanFactory beanFactory; + + @Scheduled(initialDelay = 10 * 1000, fixedRate = 5000) + public void init() { + + if (initialized) { + return; + } + + Map specifications = + beanFactory.getBeansOfType(NamedContextFactory.Specification.class); + ServiceAnnotationBeanPostProcessor + // 1. Get all service names from Spring beans that was annotated by @FeignClient + List serviceNames = new LinkedList<>(); + + specifications.forEach((beanName, specification) -> { + String serviceName = beanName.substring(0, beanName.indexOf(".")); + serviceNames.add(serviceName); + + // 2. Get all service instances by echo specified service name + List serviceInstances = discoveryClient.getInstances(serviceName); + if (!serviceInstances.isEmpty()) { + ServiceInstance serviceInstance = serviceInstances.get(0); + // 3. Get Rest metadata from service instance + Map metadata = serviceInstance.getMetadata(); + // 4. Resolve REST metadata from the @FeignClient instance + String restMetadataJson = metadata.get("restMetadata"); + /** + * { + * "providers:org.springframework.cloud.alibaba.dubbo.service.EchoService:1.0.0": [ + * "{\"method\":\"POST\",\"url\":\"/plus?a={a}&b={b}\",\"headers\":{}}", + * "{\"method\":\"GET\",\"url\":\"/echo?message={message}\",\"headers\":{}}" + * ] + * } + */ + try { + Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); + + restMetadata.forEach((dubboServiceName, restJsons) -> { + restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { + referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); + }); + }); + + } catch (IOException e) { + throw new RuntimeException(e); + } + + // + } + }); + + initialized = true; + + } + + private ReferenceBean buildReferenceBean(String dubboServiceName) { + ReferenceBean referenceBean = new ReferenceBean(); + applicationConfig.setName("service-consumer"); + referenceBean.setApplication(applicationConfig); + RegistryConfig registryConfig = new RegistryConfig(); + // requires dubbo-registry-nacos + registryConfig.setAddress("nacos://" + nacosServerAddress); + referenceBean.setRegistry(registryConfig); + String[] parts = StringUtils.delimitedListToStringArray(dubboServiceName, ":"); + referenceBean.setInterface(parts[1]); + referenceBean.setVersion(parts[2]); + referenceBean.setGroup(parts.length > 3 ? parts[3] : null); + referenceBean.get(); + return referenceBean; + } @Bean - public SmartInitializingSingleton onBeansInitialized(ListableBeanFactory beanFactory) { - return () -> { - Map feignClientBeans = beanFactory.getBeansWithAnnotation(FeignClient.class); - feignClientBeans.forEach((beanName, bean) -> { - if (bean instanceof NamedContextFactory.Specification) { - NamedContextFactory.Specification specification = (NamedContextFactory.Specification) bean; - String serviceName = specification.getName(); + public BeanPostProcessor wrapClientBeanPostProcessor() { + return new BeanPostProcessor() { + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof Client) { + Client client = (Client) bean; + // wrapper + return new DubboFeignClientProxy(client); } - }); + return bean; + } }; } + class DubboFeignClientProxy implements Client { + + private final Client delegate; + + DubboFeignClientProxy(Client delegate) { + this.delegate = delegate; + } + + @Override + public Response execute(Request request, Request.Options options) throws IOException { + + ReferenceBean referenceBean = referenceBeanCache.get(request.toString()); + + if (referenceBean != null) { + Object dubboClient = referenceBean.get(); + Method method = null; + Object[] params = null; + + try { + Object result = method.invoke(dubboClient, params); + // wrapper as a Response + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + return delegate.execute(request, options); + } + } + @EventListener(ContextRefreshedEvent.class) public void onContextRefreshed(ContextRefreshedEvent event) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index ea9af9a38..6d48f3697 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -23,17 +23,23 @@ import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import feign.Contract; +import feign.jaxrs2.JAXRS2Contract; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; +import org.springframework.util.ClassUtils; +import javax.annotation.PostConstruct; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,7 +57,7 @@ import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegist @Configuration @AutoConfigureAfter(value = { DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class}) -public class DubboRestMetadataRegistrationAutoConfiguration { +public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClassLoaderAware { /** * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, @@ -60,17 +66,38 @@ public class DubboRestMetadataRegistrationAutoConfiguration { private final Map> restMetadata = new LinkedHashMap<>(); /** - * Autowire Feign Contract Beans + * Feign Contracts */ - @Autowired(required = false) private Collection contracts = Collections.emptyList(); + private ClassLoader classLoader; + @Autowired private ObjectMapper objectMapper; @Autowired private RestMetadataResolver restMetadataResolver; + @PostConstruct + public void init() { + contracts = initFeignContracts(); + } + + private Collection initFeignContracts() { + Collection contracts = new LinkedList<>(); + + if (ClassUtils.isPresent("javax.ws.rs.Path", classLoader)) { + contracts.add(new JAXRS2Contract()); + } + + if (ClassUtils.isPresent("org.springframework.web.bind.annotation.RequestMapping", classLoader)) { + contracts.add(new SpringMvcContract()); + } + + return contracts; + } + + @EventListener(ServiceBeanExportedEvent.class) public void recordRestMetadata(ServiceBeanExportedEvent event) { ServiceBean serviceBean = event.getServiceBean(); @@ -105,4 +132,9 @@ public class DubboRestMetadataRegistrationAutoConfiguration { String restMetadataJson = objectMapper.writeValueAsString(restMetadata); serviceInstanceMetadata.put("restMetadata", restMetadataJson); } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index 3af4c939c..e3cb78bf1 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -1,3 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\ - org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestDiscoveryAutoConfiguration diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java index 8b32a4b94..4445e880c 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -29,8 +29,16 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.alibaba.dubbo.service.EchoService; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -39,18 +47,37 @@ import java.util.List; */ @EnableDiscoveryClient @EnableAutoConfiguration +@EnableFeignClients +@EnableScheduling +@RestController public class DubboSpringCloudBootstrap { @Reference(version = "1.0.0") private EchoService echoService; - @Reference(version = "1.0.0") - private EchoService echoServiceForRest; + @Autowired + @Lazy + private FeignEchoService feignEchoService; + + @GetMapping(value = "/call/echo") + public String echo(@RequestParam("message") String message) { + return feignEchoService.echo(message); + } + + @FeignClient("spring-cloud-alibaba-dubbo") + public interface FeignEchoService { + + @GetMapping(value = "/echo") + String echo(@RequestParam("message") String message); + } @Bean public ApplicationRunner applicationRunner() { return arguments -> { + // Dubbo Service call System.out.println(echoService.echo("mercyblitz")); + // Spring Cloud Open Feign REST Call + System.out.println(feignEchoService.echo("mercyblitz")); }; } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java index abc2d6414..e1ad9a9d8 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java @@ -43,13 +43,14 @@ import javax.ws.rs.QueryParam; public class DefaultEchoService implements EchoService { @Override - @GetMapping(value = "/echo", - consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @GetMapping(value = "/echo" +// consumes = MediaType.APPLICATION_JSON_VALUE, +// produces = MediaType.APPLICATION_JSON_UTF8_VALUE + ) @Path("/echo") @GET - @Consumes("application/json") - @Produces("application/json;charset=UTF-8") +// @Consumes("application/json") +// @Produces("application/json;charset=UTF-8") public String echo(@RequestParam @QueryParam("message") String message) { return RpcContext.getContext().getUrl() + " [echo] : " + message; } diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml index 113a3aa56..2dc92d598 100644 --- a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml +++ b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml @@ -10,4 +10,4 @@ dubbo: port: 9090 server: netty registry: - address: spring-cloud://dummy \ No newline at end of file + address: spring-cloud://nacos \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml index 9a5062a11..c760349d2 100644 --- a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml +++ b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml @@ -5,7 +5,6 @@ spring: nacos: discovery: server-addr: 127.0.0.1:8848 - port: 12345 eureka: client: enabled: false diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml index 6a3af32b3..21713a4a8 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml @@ -16,15 +16,31 @@ + org.springframework.boot spring-boot-starter-web + org.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery + + + com.alibaba + dubbo-registry-nacos + 0.0.2 + + + + + org.springframework.cloud + spring-cloud-alibaba-dubbo + ${project.version} + + org.springframework.boot spring-boot-starter-actuator @@ -40,10 +56,10 @@ spring-cloud-starter-openfeign - - org.springframework.cloud - spring-cloud-starter-alibaba-sentinel - + + + + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java new file mode 100644 index 000000000..b5b728488 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java @@ -0,0 +1,42 @@ +package org.springframework.cloud.alibaba.cloud.examples.demos; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.context.annotation.Lazy; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@EnableAutoConfiguration // 激活自动装配 +@EnableDiscoveryClient // 激活服务注册和发现 +@EnableFeignClients // 激活 @FeignClients注册 +public class SpringCloudRestClientBootstrap { + + @FeignClient("spring-cloud-alibaba-dubbo") + public interface FeignEchoService { + + @GetMapping(value = "/echo") + String echo(@RequestParam("message") String message); + } + + + @RestController + public static class EchoServiceController { + + @Autowired + private FeignEchoService feignEchoService; + + @GetMapping("/call/echo") + public String echo(@RequestParam("message") String message) { + return feignEchoService.echo(message); + } + } + + public static void main(String[] args) { + SpringApplication.run(SpringCloudRestClientBootstrap.class, args); + } +} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties index fbc9736eb..1e6c2f5e5 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties @@ -3,10 +3,5 @@ server.port=18083 management.endpoints.web.exposure.include=* spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 -feign.sentinel.enabled=true +dubbo.registry.address= spring-cloud://nacos -spring.cloud.sentinel.transport.dashboard=localhost:8080 -spring.cloud.sentinel.eager=true - -spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json -spring.cloud.sentinel.datasource.ds1.file.data-type=json \ No newline at end of file From 26a05cbefb8a38fb94030c4ab32ea05bdc9a2993 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 18 Jan 2019 19:25:39 +0800 Subject: [PATCH 08/50] Temporary commit --- .../src/main/asciidoc-zh/nacos-discovery.adoc | 4 +- .../src/main/asciidoc/nacos-discovery.adoc | 4 +- spring-cloud-alibaba-dubbo/pom.xml | 26 ++- .../DubboRestAutoConfiguration.java | 34 +--- .../DubboRestDiscoveryAutoConfiguration.java | 95 +++++++++-- ...MetadataRegistrationAutoConfiguration.java | 79 +++------ .../rest/feign/RestMetadataResolver.java | 126 ++++++++++++-- .../rest/metadata/MethodRestMetadata.java | 100 +++++++++++ .../rest/metadata/ServiceRestMetadata.java | 63 +++++++ .../dubbo/util/MetadataConfigUtils.java | 61 +++++++ .../src/test/resources/bootstrap.yaml | 3 + .../cloud/examples/EchoController.java | 40 +++++ .../alibaba/cloud/examples/EchoService.java | 33 ++++ .../cloud/examples/ProviderApplication.java | 157 +++++++++++++++--- .../src/main/resources/application.properties | 10 +- .../nacos-discovery-example/pom.xml | 36 ++++ ...cosDiscoveryEndpointAutoConfiguration.java | 2 + 17 files changed, 736 insertions(+), 137 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java create mode 100644 spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java create mode 100644 spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc index bd88310af..324741e24 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc @@ -260,8 +260,8 @@ public class NacosConsumerApp { @GetMapping("/echo/app-name") public String echoAppName(){ //使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问 - ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider"); - String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName); + ServiceInstance delegate = loadBalancerClient.choose("nacos-provider"); + String url = String.format("http://%s:%s/echo/%s",delegate.getHost(),delegate.getPort(),appName); System.out.println("request url:"+url); return restTemplate.getForObject(url,String.class); } diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc index 44f2222f5..03f1c3f4e 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc @@ -260,8 +260,8 @@ public class NacosConsumerApp { @GetMapping("/echo/app-name") public String echoAppName(){ //Access through the combination of LoadBalanceClient and RestTemolate - ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider"); - String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName); + ServiceInstance delegate = loadBalancerClient.choose("nacos-provider"); + String url = String.format("http://%s:%s/echo/%s",delegate.getHost(),delegate.getPort(),appName); System.out.println("request url:" +url); return restTemplate.getForObject(url,String.class); } diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml index 1a869a3e4..2de8ada5c 100644 --- a/spring-cloud-alibaba-dubbo/pom.xml +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -59,6 +59,17 @@ true + + org.springframework.cloud + spring-cloud-alibaba-nacos-config + + + + + + + + org.springframework.cloud spring-cloud-starter-openfeign @@ -126,6 +137,11 @@ 9.7.0 + + org.apache.commons + commons-lang3 + + junit @@ -159,11 +175,11 @@ - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - test - + + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java index 7af8faeba..90ee30797 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -17,17 +17,13 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; -import feign.Contract; -import feign.jaxrs2.JAXRS2Contract; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; -import org.springframework.cloud.openfeign.support.SpringMvcContract; +import org.springframework.cloud.alibaba.dubbo.util.MetadataConfigUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.bind.annotation.RequestMapping; - -import javax.ws.rs.Path; +import org.springframework.core.Ordered; /** * Spring Boot Auto-Configuration class for Dubbo REST @@ -35,34 +31,22 @@ import javax.ws.rs.Path; * @author Mercy */ @Configuration +@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) public class DubboRestAutoConfiguration { -// /** -// * A Feign Contract bean for JAX-RS if available -// */ -// @ConditionalOnClass(Path.class) -// @Bean -// public Contract jaxrs2Contract() { -// return new JAXRS2Contract(); -// } - @Bean @ConditionalOnMissingBean public ObjectMapper objectMapper() { return new ObjectMapper(); } -// /** -// * A Feign Contract bean for Spring MVC if available -// */ -// @ConditionalOnClass(RequestMapping.class) -// @Bean -// public Contract springMvcContract() { -// return new SpringMvcContract(); -// } - @Bean public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) { return new RestMetadataResolver(objectMapper); } + + @Bean + public MetadataConfigUtils metadataConfigUtils() { + return new MetadataConfigUtils(); + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java index 93fdc338f..8cf682f7e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java @@ -16,31 +16,36 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; +import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.ReferenceBean; import feign.Client; import feign.Request; +import feign.RequestInterceptor; import feign.Response; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.BeansException; import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; +import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.util.MetadataConfigUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; +import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.context.named.NamedContextFactory; -import org.springframework.cloud.openfeign.FeignClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import java.io.IOException; @@ -51,17 +56,18 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; /** * The Auto-Configuration class for Dubbo REST Discovery * * @author Mercy */ -@Configuration +@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = true) @AutoConfigureAfter(value = { + DubboAutoConfiguration.class, DubboRestAutoConfiguration.class, DubboRestMetadataRegistrationAutoConfiguration.class}) +@Configuration public class DubboRestDiscoveryAutoConfiguration { @Autowired @@ -81,29 +87,66 @@ public class DubboRestDiscoveryAutoConfiguration { @Autowired private ApplicationConfig applicationConfig; + @Value("${spring.application.name}") + private String applicationName; + @Value("${spring.cloud.nacos.discovery.server-addr}") private String nacosServerAddress; - - private volatile boolean initialized = false; - @Autowired private ListableBeanFactory beanFactory; - @Scheduled(initialDelay = 10 * 1000, fixedRate = 5000) - public void init() { + @Autowired + private MetadataConfigUtils metadataConfigUtils; + + /** + * Handle on self instance registered. + * + * @param event {@link InstanceRegisteredEvent} + */ + @EventListener(InstanceRegisteredEvent.class) + public void onSelfInstanceRegistered(InstanceRegisteredEvent event) throws Exception { - if (initialized) { + Class targetClass = AbstractAutoServiceRegistration.class; + + Object source = event.getSource(); + + if (!targetClass.isInstance(source)) { return; } + // getRegistration() is a protected method + Method method = targetClass.getDeclaredMethod("getRegistration"); + + method.setAccessible(true); + + Registration registration = (Registration) ReflectionUtils.invokeMethod(method, source); + + String serviceRestMetaData = + metadataConfigUtils.getServiceRestMetadata(registration.getServiceId()); + + Set metadata = objectMapper.readValue(serviceRestMetaData, Set.class); + + System.out.println(serviceRestMetaData); + + } + + @Bean + public RequestInterceptor requestInterceptor() { + return template -> { + System.out.println(template); + }; + } + + private void noop() { Map specifications = beanFactory.getBeansOfType(NamedContextFactory.Specification.class); - ServiceAnnotationBeanPostProcessor // 1. Get all service names from Spring beans that was annotated by @FeignClient List serviceNames = new LinkedList<>(); - specifications.forEach((beanName, specification) -> { + specifications.forEach((beanName, specification) -> + + { String serviceName = beanName.substring(0, beanName.indexOf(".")); serviceNames.add(serviceName); @@ -139,11 +182,32 @@ public class DubboRestDiscoveryAutoConfiguration { // } }); + } - initialized = true; + private ReferenceBean buildReferenceBean(ServiceInstance serviceInstance) { + ReferenceBean referenceBean = new ReferenceBean(); + Map metadata = serviceInstance.getMetadata(); + // 4. Resolve REST metadata from the @FeignClient instance + String restMetadataJson = metadata.get("restMetadata"); + + try { + Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); + + restMetadata.forEach((dubboServiceName, restJsons) -> { + restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { + referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); + }); + }); + + } catch (IOException e) { + throw new RuntimeException(e); + } + + return referenceBean; } + private ReferenceBean buildReferenceBean(String dubboServiceName) { ReferenceBean referenceBean = new ReferenceBean(); applicationConfig.setName("service-consumer"); @@ -204,6 +268,7 @@ public class DubboRestDiscoveryAutoConfiguration { return delegate.execute(request, options); } + } @EventListener(ContextRefreshedEvent.class) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index 6d48f3697..8c225b0e9 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -16,36 +16,26 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; -import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import feign.Contract; -import feign.jaxrs2.JAXRS2Contract; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; +import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.util.MetadataConfigUtils; import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; -import org.springframework.util.ClassUtils; -import javax.annotation.PostConstruct; -import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; - -import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceName; /** * The Auto-Configuration class for Dubbo REST metadata registration, @@ -54,21 +44,19 @@ import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegist * * @author Mercy */ -@Configuration +@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @AutoConfigureAfter(value = { DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class}) +@Configuration public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClassLoaderAware { /** * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods. */ - private final Map> restMetadata = new LinkedHashMap<>(); + private final Map>> restMetadata = new LinkedHashMap<>(); - /** - * Feign Contracts - */ - private Collection contracts = Collections.emptyList(); + private final Set serviceRestMetadata = new LinkedHashSet<>(); private ClassLoader classLoader; @@ -78,42 +66,16 @@ public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClass @Autowired private RestMetadataResolver restMetadataResolver; - @PostConstruct - public void init() { - contracts = initFeignContracts(); - } - - private Collection initFeignContracts() { - Collection contracts = new LinkedList<>(); - - if (ClassUtils.isPresent("javax.ws.rs.Path", classLoader)) { - contracts.add(new JAXRS2Contract()); - } - - if (ClassUtils.isPresent("org.springframework.web.bind.annotation.RequestMapping", classLoader)) { - contracts.add(new SpringMvcContract()); - } - - return contracts; - } + @Autowired + private MetadataConfigUtils metadataConfigUtils; @EventListener(ServiceBeanExportedEvent.class) - public void recordRestMetadata(ServiceBeanExportedEvent event) { + public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException { ServiceBean serviceBean = event.getServiceBean(); - List urls = serviceBean.getExportedUrls(); - Object bean = serviceBean.getRef(); - - Set metadata = contracts.stream() - .map(contract -> contract.parseAndValidatateMetadata(bean.getClass())) - .flatMap(v -> v.stream()) - .map(restMetadataResolver::resolve) - .collect(Collectors.toSet()); - - urls.forEach(url -> { - String serviceName = getServiceName(url); - restMetadata.put(serviceName, metadata); - }); +// Map>> metadata = restMetadataResolver.resolve(serviceBean); +// restMetadata.putAll(metadata); + serviceRestMetadata.addAll(restMetadataResolver.resolve(serviceBean)); } /** @@ -126,15 +88,20 @@ public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClass * @param event {@link InstancePreRegisteredEvent} instance */ @EventListener(InstancePreRegisteredEvent.class) - public void registerRestMetadata(InstancePreRegisteredEvent event) throws JsonProcessingException { + public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception { Registration registration = event.getRegistration(); - Map serviceInstanceMetadata = registration.getMetadata(); - String restMetadataJson = objectMapper.writeValueAsString(restMetadata); - serviceInstanceMetadata.put("restMetadata", restMetadataJson); + + String restMetadataJson = objectMapper.writeValueAsString(serviceRestMetadata); + + metadataConfigUtils.publishServiceRestMetadata(registration.getServiceId(), restMetadataJson); + } + @Override public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } + + } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java index f9127c70e..994d0a985 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java @@ -16,21 +16,39 @@ */ package org.springframework.cloud.alibaba.dubbo.rest.feign; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.config.spring.ServiceBean; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Contract; import feign.MethodMetadata; import feign.Request; import feign.RequestTemplate; +import feign.jaxrs2.JAXRS2Contract; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry; +import org.springframework.cloud.alibaba.dubbo.rest.metadata.MethodRestMetadata; +import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; +import org.springframework.cloud.openfeign.support.SpringMvcContract; +import org.springframework.util.ClassUtils; import java.io.IOException; import java.util.Collection; -import java.util.LinkedHashMap; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Map; +import java.util.Set; /** * The JSON resolver for {@link MethodMetadata} */ -public class RestMetadataResolver { +public class RestMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton { private static final String METHOD_PROPERTY_NAME = "method"; private static final String URL_PROPERTY_NAME = "url"; @@ -38,26 +56,108 @@ public class RestMetadataResolver { private final ObjectMapper objectMapper; + /** + * Feign Contracts + */ + private Collection contracts; + + private ClassLoader classLoader; + + @Autowired + private ObjectProvider contractObjectProvider; + public RestMetadataResolver(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } - public String resolve(MethodMetadata methodMetadata) { + @Override + public void afterSingletonsInstantiated() { + + Collection contracts = new LinkedList<>(); + + // Add injected Contract , for example SpringMvcContract Bean under Spring Cloud Open Feign + Contract contract = contractObjectProvider.getIfAvailable(); + if (contract != null) { + contracts.add(contract); + } else { + if (ClassUtils.isPresent("org.springframework.cloud.openfeign.support.SpringMvcContract", classLoader)) { + contracts.add(new SpringMvcContract()); + } + } + + // Add JAXRS2Contract if it's present in Class Path + if (ClassUtils.isPresent("javax.ws.rs.Path", classLoader)) { + contracts.add(new JAXRS2Contract()); + } + + this.contracts = Collections.unmodifiableCollection(contracts); + } + + public Set resolve(ServiceBean serviceBean) { + + Object bean = serviceBean.getRef(); + + Class beanType = bean.getClass(); + + Class interfaceClass = serviceBean.getInterfaceClass(); + + Set serviceRestMetadata = new LinkedHashSet<>(); + + Set methodRestMetadata = new LinkedHashSet<>(); + + contracts.stream() + .map(contract -> contract.parseAndValidatateMetadata(bean.getClass())) + .flatMap(v -> v.stream()) + .forEach(methodMetadata -> { + methodRestMetadata.add(resolveMethodRestMetadata(methodMetadata, beanType, interfaceClass)); + }); + + List urls = serviceBean.getExportedUrls(); + + urls.stream() + .map(SpringCloudRegistry::getServiceName) + .forEach(serviceName -> { + ServiceRestMetadata metadata = new ServiceRestMetadata(); + metadata.setName(serviceName); + metadata.setMeta(methodRestMetadata); + serviceRestMetadata.add(metadata); + }); + + return serviceRestMetadata; + } + + private String toJson(Object object) { String jsonContent = null; - Map metadata = new LinkedHashMap<>(); - RequestTemplate requestTemplate = methodMetadata.template(); - Request request = requestTemplate.request(); - metadata.put(METHOD_PROPERTY_NAME, request.method()); - metadata.put(URL_PROPERTY_NAME, request.url()); - metadata.put(HEADERS_PROPERTY_NAME, request.headers()); try { - jsonContent = objectMapper.writeValueAsString(metadata); + jsonContent = objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { throw new IllegalArgumentException(e); } return jsonContent; } + private String regenerateConfigKey(String configKey, Class beanType, Class interfaceClass) { + return StringUtils.replace(configKey, beanType.getSimpleName(), interfaceClass.getSimpleName()); + } + + protected MethodRestMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class beanType, + Class interfaceClass) { + RequestTemplate requestTemplate = methodMetadata.template(); + Request request = requestTemplate.request(); + + String configKey = methodMetadata.configKey(); + String newConfigKey = regenerateConfigKey(configKey, beanType, interfaceClass); + + MethodRestMetadata methodRestMetadata = new MethodRestMetadata(); + methodRestMetadata.setConfigKey(newConfigKey); + methodRestMetadata.setMethod(request.method()); + methodRestMetadata.setUrl(request.url()); + methodRestMetadata.setHeaders(request.headers()); + methodRestMetadata.setIndexToName(methodMetadata.indexToName()); + + return methodRestMetadata; + } + public Request resolveRequest(String json) { Request request = null; try { @@ -71,4 +171,10 @@ public class RestMetadataResolver { } return request; } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java new file mode 100644 index 000000000..ad8d9db9f --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.rest.metadata; + +import java.util.Collection; +import java.util.Map; + +/** + * TODO + */ +public class MethodRestMetadata { + + private String configKey; + + private String method; + + private String url; + + private Map> headers; + + private Map> indexToName; + + public String getConfigKey() { + return configKey; + } + + public void setConfigKey(String configKey) { + this.configKey = configKey; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Map> getHeaders() { + return headers; + } + + public void setHeaders(Map> headers) { + this.headers = headers; + } + + public Map> getIndexToName() { + return indexToName; + } + + public void setIndexToName(Map> indexToName) { + this.indexToName = indexToName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MethodRestMetadata that = (MethodRestMetadata) o; + + if (configKey != null ? !configKey.equals(that.configKey) : that.configKey != null) return false; + if (method != null ? !method.equals(that.method) : that.method != null) return false; + if (url != null ? !url.equals(that.url) : that.url != null) return false; + if (headers != null ? !headers.equals(that.headers) : that.headers != null) return false; + return indexToName != null ? indexToName.equals(that.indexToName) : that.indexToName == null; + } + + @Override + public int hashCode() { + int result = configKey != null ? configKey.hashCode() : 0; + result = 31 * result + (method != null ? method.hashCode() : 0); + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (headers != null ? headers.hashCode() : 0); + result = 31 * result + (indexToName != null ? indexToName.hashCode() : 0); + return result; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java new file mode 100644 index 000000000..6b93302fa --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.rest.metadata; + +import java.util.Set; + +/** + * TODO + */ +public class ServiceRestMetadata { + + private String name; + + private Set meta; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getMeta() { + return meta; + } + + public void setMeta(Set meta) { + this.meta = meta; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ServiceRestMetadata that = (ServiceRestMetadata) o; + + if (name != null ? !name.equals(that.name) : that.name != null) return false; + return meta != null ? meta.equals(that.meta) : that.meta == null; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (meta != null ? meta.hashCode() : 0); + return result; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java new file mode 100644 index 000000000..5fe71b3a4 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.util; + +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.exception.NacosException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; + +import javax.annotation.PostConstruct; + +import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; + +/** + * TODO + */ +public class MetadataConfigUtils { + + @Autowired + private NacosConfigProperties nacosConfigProperties; + + private ConfigService configService; + + @PostConstruct + public void init() { + this.configService = nacosConfigProperties.configServiceInstance(); + } + + /** + * Get the data Id of service rest metadata + * TODO JavaDoc + */ + private static String getServiceRestMetadataDataId(String serviceName) { + return serviceName + "-rest-metadata.json"; + } + + public void publishServiceRestMetadata(String serviceName, String restMetadataJSON) + throws NacosException { + String dataId = getServiceRestMetadataDataId(serviceName); + configService.publishConfig(dataId, DEFAULT_GROUP, restMetadataJSON); + } + + public String getServiceRestMetadata(String serviceName) throws NacosException { + String dataId = getServiceRestMetadataDataId(serviceName); + return configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml index c760349d2..c3799608e 100644 --- a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml +++ b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml @@ -5,6 +5,9 @@ spring: nacos: discovery: server-addr: 127.0.0.1:8848 + config: + server-addr: 127.0.0.1:8848 + eureka: client: enabled: false diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java new file mode 100644 index 000000000..1a571b264 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.cloud.examples; + +import com.alibaba.dubbo.config.annotation.Service; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Service(version = "1.0.0") +public class EchoController implements EchoService { + @Override + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) + public String echo(@PathVariable String string) { + return "hello Nacos Discovery " + string; + } + + @Override + @RequestMapping(value = "/divide", method = RequestMethod.GET) + public String divide(@RequestParam Integer a, @RequestParam Integer b) { + return String.valueOf(a / b); + } +} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java new file mode 100644 index 000000000..b60affbc8 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * TODO + */ +public interface EchoService { + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) + String echo(@PathVariable String string); + + @RequestMapping(value = "/divide", method = RequestMethod.GET) + String divide(@RequestParam Integer a, @RequestParam Integer b); +} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java index 843f5cbe0..2519096a5 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java @@ -1,13 +1,30 @@ package org.springframework.cloud.alibaba.cloud.examples; +import com.alibaba.dubbo.config.spring.ServiceBean; +import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.context.event.EventListener; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URL; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.springframework.util.ClassUtils.isPrimitiveOrWrapper; /** * @author xiaojing @@ -16,20 +33,118 @@ import org.springframework.web.bind.annotation.RestController; @EnableDiscoveryClient public class ProviderApplication { - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - } - - @RestController - class EchoController { - @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) - public String echo(@PathVariable String string) { - return "hello Nacos Discovery " + string; - } - - @RequestMapping(value = "/divide", method = RequestMethod.GET) - public String divide(@RequestParam Integer a, @RequestParam Integer b) { - return String.valueOf(a / b); - } - } + public static void main(String[] args) { + SpringApplication.run(ProviderApplication.class, args); + } + + @Autowired + private ConfigurableListableBeanFactory beanFactory; + + @Autowired + private ObjectMapper objectMapper; + + @EventListener(ServiceBeanExportedEvent.class) + public void onServiceBeanExportedEvent(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + } + + @EventListener(InstancePreRegisteredEvent.class) + public void onInstancePreRegisteredEvent(InstancePreRegisteredEvent event) throws JsonProcessingException { + Registration registration = event.getRegistration(); + Map serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class); + Map metaData = registration.getMetadata(); + String serviceBeansJson = objectMapper.writeValueAsString(services(serviceBeansMap)); + metaData.put("serviceBeans", serviceBeansJson); + } + + public Map> services(Map serviceBeansMap) { + + Map> servicesMetadata = new LinkedHashMap<>(serviceBeansMap.size()); + + for (Map.Entry entry : serviceBeansMap.entrySet()) { + + String serviceBeanName = entry.getKey(); + + ServiceBean serviceBean = entry.getValue(); + + Map serviceBeanMetadata = resolveBeanMetadata(serviceBean); + + Object service = resolveServiceBean(serviceBeanName, serviceBean); + + if (service != null) { + // Add Service implementation class + serviceBeanMetadata.put("serviceClass", service.getClass().getName()); + } + + servicesMetadata.put(serviceBeanName, serviceBeanMetadata); + + } + + return servicesMetadata; + + } + + protected Map resolveBeanMetadata(final Object bean) { + + final Map beanMetadata = new LinkedHashMap<>(); + + try { + + BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + + Method readMethod = propertyDescriptor.getReadMethod(); + + if (readMethod != null && isSimpleType(propertyDescriptor.getPropertyType())) { + + String name = Introspector.decapitalize(propertyDescriptor.getName()); + Object value = readMethod.invoke(bean); + + if (value != null) { + beanMetadata.put(name, value); + } + } + + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return beanMetadata; + + } + + private Object resolveServiceBean(String serviceBeanName, ServiceBean serviceBean) { + + int index = serviceBeanName.indexOf("#"); + + if (index > -1) { + + Class interfaceClass = serviceBean.getInterfaceClass(); + + String serviceName = serviceBeanName.substring(index + 1); + + if (beanFactory.containsBean(serviceName)) { + return beanFactory.getBean(serviceName, interfaceClass); + } + + } + + return null; + + } + + private static boolean isSimpleType(Class type) { + return isPrimitiveOrWrapper(type) + || type == String.class + || type == BigDecimal.class + || type == BigInteger.class + || type == Date.class + || type == URL.class + || type == Class.class + ; + } } diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties index 66100d79f..81cea7178 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties @@ -1,4 +1,12 @@ server.port=18082 spring.application.name=service-provider spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 -management.endpoints.web.exposure.include=* \ No newline at end of file +management.endpoints.web.exposure.include=* + + +dubbo.scan.base-packages=org.springframework.cloud.alibaba.cloud.examples + +dubbo.registry.address=nacos://127.0.0.1:8848 + +dubbo.protocol.name=dubbo +dubbo.protocol.port=-1 \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml index ac62d9a31..5d37f8836 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml @@ -15,11 +15,47 @@ pom Example demonstrating how to use nacos discovery + + 2.6.5 + nacos-discovery-consumer-example nacos-discovery-provider-example + + + + + com.alibaba.boot + dubbo-spring-boot-starter + + + + com.alibaba + dubbo + ${dubbo.version} + + + + + io.netty + netty-all + + + + + com.alibaba + dubbo-registry-nacos + + + + + com.alibaba.nacos + nacos-client + + + diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java index 2356ad0ac..0bbee4c28 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java @@ -20,6 +20,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.condition.Conditi import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.alibaba.nacos.ConditionalOnNacosDiscoveryEnabled; import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -29,6 +30,7 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @ConditionalOnClass(Endpoint.class) +@ConditionalOnNacosDiscoveryEnabled public class NacosDiscoveryEndpointAutoConfiguration { @Bean From f34e1883e3ecc1dfbce2bdb89c9430f2e737ab99 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Sat, 19 Jan 2019 11:54:45 +0800 Subject: [PATCH 09/50] Temporary commit --- .../DubboOpenFeignAutoConfiguration.java | 96 +++++++ .../DubboRestAutoConfiguration.java | 7 +- .../DubboRestDiscoveryAutoConfiguration.java | 257 +++++++++--------- ...MetadataRegistrationAutoConfiguration.java | 24 +- .../DubboFeignClientsConfiguration.java | 56 ++++ .../feign/RestMetadataConfigService.java} | 6 +- .../main/resources/META-INF/spring.factories | 1 + .../bootstrap/DubboSpringCloudBootstrap.java | 22 +- 8 files changed, 296 insertions(+), 173 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{util/MetadataConfigUtils.java => rest/feign/RestMetadataConfigService.java} (94%) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java new file mode 100644 index 000000000..7b0c4c97f --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import feign.Feign; +import feign.RequestInterceptor; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.cloud.alibaba.dubbo.openfeign.DubboFeignClientsConfiguration; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignAutoConfiguration; +import org.springframework.cloud.openfeign.FeignContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import java.util.LinkedHashSet; +import java.util.Set; + +import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME; + + +/** + * Dubbo Feign Auto-{@link Configuration Configuration} + * + * @author Mercy + */ +@ConditionalOnClass(value = Feign.class, name = FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME) +@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class) +@AutoConfigureAfter(FeignAutoConfiguration.class) +@Configuration +public class DubboOpenFeignAutoConfiguration { + + static final String FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME = + "org.springframework.cloud.openfeign.FeignClientFactoryBean"; + + @Autowired + private ObjectProvider feignContextObjectProvider; + + @EventListener(ApplicationReadyEvent.class) + public void onContextRefreshed(ApplicationReadyEvent event) { + ConfigurableApplicationContext applicationContext = event.getApplicationContext(); + // Resolve the subscribed service names for @FeignClient + Set feignClientServiceNames = resolveFeignClientServiceNames(applicationContext); + // FeignContext + FeignContext feignContext = feignContextObjectProvider.getIfAvailable(); + + } + + /** + * Resolve the subscribed service names for @FeignClient + * + * @param applicationContext Current {@link ConfigurableApplicationContext} + * @return non-null {@link Set} + */ + private Set resolveFeignClientServiceNames(ConfigurableApplicationContext applicationContext) { + Set feignClientServiceNames = new LinkedHashSet<>(); + ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); + for (String beanName : beanFactory.getBeanDefinitionNames()) { + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + if (FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME.equals(beanDefinition.getBeanClassName())) { + String feignClientServiceName = (String) beanDefinition.getPropertyValues().get("name"); + feignClientServiceNames.add(feignClientServiceName); + } + } + return feignClientServiceNames; + } + + @Bean + public RequestInterceptor requestInterceptor() { + return template -> { + System.out.println(template); + }; + } + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java index 90ee30797..775f706b8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -19,8 +19,8 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; -import org.springframework.cloud.alibaba.dubbo.util.MetadataConfigUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -46,7 +46,8 @@ public class DubboRestAutoConfiguration { } @Bean - public MetadataConfigUtils metadataConfigUtils() { - return new MetadataConfigUtils(); + public RestMetadataConfigService restMetadataConfigService() { + return new RestMetadataConfigService(); } + } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java index 8cf682f7e..25ceaf0da 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java @@ -20,42 +20,28 @@ import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration; import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.ReferenceBean; +import com.fasterxml.jackson.databind.ObjectMapper; import feign.Client; import feign.Request; -import feign.RequestInterceptor; import feign.Response; -import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; -import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; -import org.springframework.cloud.alibaba.dubbo.util.MetadataConfigUtils; -import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; -import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.context.named.NamedContextFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; -import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; import java.util.Map; -import java.util.Set; /** * The Auto-Configuration class for Dubbo REST Discovery @@ -70,6 +56,9 @@ import java.util.Set; @Configuration public class DubboRestDiscoveryAutoConfiguration { + private static final String FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME = + "org.springframework.cloud.openfeign.FeignClientFactoryBean"; + @Autowired private DiscoveryClient discoveryClient; @@ -94,119 +83,7 @@ public class DubboRestDiscoveryAutoConfiguration { private String nacosServerAddress; @Autowired - private ListableBeanFactory beanFactory; - - @Autowired - private MetadataConfigUtils metadataConfigUtils; - - /** - * Handle on self instance registered. - * - * @param event {@link InstanceRegisteredEvent} - */ - @EventListener(InstanceRegisteredEvent.class) - public void onSelfInstanceRegistered(InstanceRegisteredEvent event) throws Exception { - - Class targetClass = AbstractAutoServiceRegistration.class; - - Object source = event.getSource(); - - if (!targetClass.isInstance(source)) { - return; - } - - // getRegistration() is a protected method - Method method = targetClass.getDeclaredMethod("getRegistration"); - - method.setAccessible(true); - - Registration registration = (Registration) ReflectionUtils.invokeMethod(method, source); - - String serviceRestMetaData = - metadataConfigUtils.getServiceRestMetadata(registration.getServiceId()); - - Set metadata = objectMapper.readValue(serviceRestMetaData, Set.class); - - System.out.println(serviceRestMetaData); - - } - - @Bean - public RequestInterceptor requestInterceptor() { - return template -> { - System.out.println(template); - }; - } - - private void noop() { - Map specifications = - beanFactory.getBeansOfType(NamedContextFactory.Specification.class); - // 1. Get all service names from Spring beans that was annotated by @FeignClient - List serviceNames = new LinkedList<>(); - - specifications.forEach((beanName, specification) -> - - { - String serviceName = beanName.substring(0, beanName.indexOf(".")); - serviceNames.add(serviceName); - - // 2. Get all service instances by echo specified service name - List serviceInstances = discoveryClient.getInstances(serviceName); - if (!serviceInstances.isEmpty()) { - ServiceInstance serviceInstance = serviceInstances.get(0); - // 3. Get Rest metadata from service instance - Map metadata = serviceInstance.getMetadata(); - // 4. Resolve REST metadata from the @FeignClient instance - String restMetadataJson = metadata.get("restMetadata"); - /** - * { - * "providers:org.springframework.cloud.alibaba.dubbo.service.EchoService:1.0.0": [ - * "{\"method\":\"POST\",\"url\":\"/plus?a={a}&b={b}\",\"headers\":{}}", - * "{\"method\":\"GET\",\"url\":\"/echo?message={message}\",\"headers\":{}}" - * ] - * } - */ - try { - Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); - - restMetadata.forEach((dubboServiceName, restJsons) -> { - restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { - referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); - }); - }); - - } catch (IOException e) { - throw new RuntimeException(e); - } - - // - } - }); - } - - private ReferenceBean buildReferenceBean(ServiceInstance serviceInstance) { - - ReferenceBean referenceBean = new ReferenceBean(); - Map metadata = serviceInstance.getMetadata(); - // 4. Resolve REST metadata from the @FeignClient instance - String restMetadataJson = metadata.get("restMetadata"); - - try { - Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); - - restMetadata.forEach((dubboServiceName, restJsons) -> { - restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { - referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); - }); - }); - - } catch (IOException e) { - throw new RuntimeException(e); - } - - return referenceBean; - } - + private RestMetadataConfigService restMetadataConfigService; private ReferenceBean buildReferenceBean(String dubboServiceName) { ReferenceBean referenceBean = new ReferenceBean(); @@ -271,10 +148,122 @@ public class DubboRestDiscoveryAutoConfiguration { } - @EventListener(ContextRefreshedEvent.class) - public void onContextRefreshed(ContextRefreshedEvent event) { - - } +} -} +// private Method getRegistrationMethod; +// +// @PostConstruct +// public void init() throws NoSuchMethodException { +// getRegistrationMethod = initGetRegistrationMethod(); +// } +// +// /** +// * Initializes {@link AbstractAutoServiceRegistration#getRegistration() getRegistration method} that is is protected. +// * +// * @return {@link Method} +// * @throws NoSuchMethodException +// */ +// private Method initGetRegistrationMethod() throws NoSuchMethodException { +// Method method = AbstractAutoServiceRegistration.class.getDeclaredMethod("getRegistration"); +// method.setAccessible(true); +// return method; +// } +// +// private Registration getRegistration(AbstractAutoServiceRegistration source) { +// return (Registration) ReflectionUtils.invokeMethod(getRegistrationMethod, source); +// } +// +// private void noop() { +// Map specifications = +// beanFactory.getBeansOfType(NamedContextFactory.Specification.class); +// // 1. Get all service names from Spring beans that was annotated by @FeignClient +// List serviceNames = new LinkedList<>(); +// +// specifications.forEach((beanName, specification) -> +// +// { +// String serviceName = beanName.substring(0, beanName.indexOf(".")); +// serviceNames.add(serviceName); +// +// // 2. Get all service instances by echo specified service name +// List serviceInstances = discoveryClient.getInstances(serviceName); +// if (!serviceInstances.isEmpty()) { +// ServiceInstance serviceInstance = serviceInstances.get(0); +// // 3. Get Rest metadata from service instance +// Map metadata = serviceInstance.getMetadata(); +// // 4. Resolve REST metadata from the @FeignClient instance +// String restMetadataJson = metadata.get("restMetadata"); +// /** +// * { +// * "providers:org.springframework.cloud.alibaba.dubbo.service.EchoService:1.0.0": [ +// * "{\"method\":\"POST\",\"url\":\"/plus?a={a}&b={b}\",\"headers\":{}}", +// * "{\"method\":\"GET\",\"url\":\"/echo?message={message}\",\"headers\":{}}" +// * ] +// * } +// */ +// try { +// Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); +// +// restMetadata.forEach((dubboServiceName, restJsons) -> { +// restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { +// referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); +// }); +// }); +// +// } catch (IOException e) { +// throw new RuntimeException(e); +// } +// +// // +// } +// }); +// } +// +// private ReferenceBean buildReferenceBean(ServiceInstance serviceInstance) { +// +// ReferenceBean referenceBean = new ReferenceBean(); +// Map metadata = serviceInstance.getMetadata(); +// // 4. Resolve REST metadata from the @FeignClient instance +// String restMetadataJson = metadata.get("restMetadata"); +// +// try { +// Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); +// +// restMetadata.forEach((dubboServiceName, restJsons) -> { +// restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { +// referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); +// }); +// }); +// +// } catch (IOException e) { +// throw new RuntimeException(e); +// } +// +// return referenceBean; +// } + +// /** +// * Handle on self instance registered. +// * +// * @param event {@link InstanceRegisteredEvent} +// */ +// @EventListener(InstanceRegisteredEvent.class) +// public void onSelfInstanceRegistered(InstanceRegisteredEvent event) throws Exception { +// +// Class targetClass = AbstractAutoServiceRegistration.class; +// +// Object source = event.getSource(); +// +// Assert.isInstanceOf(targetClass, source, +// format("The source of %s must implement %s", source, targetClass.getName())); +// +// Registration registration = getRegistration((AbstractAutoServiceRegistration) source); +// +// String serviceRestMetaDataConfig = +// restMetadataConfigService.getServiceRestMetadata(registration.getServiceId()); +// +// Set serviceRestMetadata = objectMapper.readValue(serviceRestMetaDataConfig, +// TypeFactory.defaultInstance().constructCollectionType(Set.class, ServiceRestMetadata.class)); +// +// } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index 8c225b0e9..2b901e6f2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -20,21 +20,18 @@ import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; -import org.springframework.cloud.alibaba.dubbo.util.MetadataConfigUtils; import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; import java.util.Set; /** @@ -48,18 +45,14 @@ import java.util.Set; @AutoConfigureAfter(value = { DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class}) @Configuration -public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClassLoaderAware { +public class DubboRestMetadataRegistrationAutoConfiguration { /** * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods. */ - private final Map>> restMetadata = new LinkedHashMap<>(); - private final Set serviceRestMetadata = new LinkedHashSet<>(); - private ClassLoader classLoader; - @Autowired private ObjectMapper objectMapper; @@ -67,14 +60,12 @@ public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClass private RestMetadataResolver restMetadataResolver; @Autowired - private MetadataConfigUtils metadataConfigUtils; + private RestMetadataConfigService metadataConfigService; @EventListener(ServiceBeanExportedEvent.class) public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException { ServiceBean serviceBean = event.getServiceBean(); -// Map>> metadata = restMetadataResolver.resolve(serviceBean); -// restMetadata.putAll(metadata); serviceRestMetadata.addAll(restMetadataResolver.resolve(serviceBean)); } @@ -93,15 +84,8 @@ public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClass String restMetadataJson = objectMapper.writeValueAsString(serviceRestMetadata); - metadataConfigUtils.publishServiceRestMetadata(registration.getServiceId(), restMetadataJson); - - } - + metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), restMetadataJson); - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; } - } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java new file mode 100644 index 000000000..6fa4a9788 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.openfeign; + +import feign.Feign; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.FeignClientsConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +/** + * Dubbo {@link Configuration} for {@link FeignClient FeignClients} + * + * @author Mercy + * @see DubboOpenFeignAutoConfiguration + * @see org.springframework.cloud.openfeign.FeignContext#setConfigurations(List) + * @see FeignClientsConfiguration + */ +@Configuration +public class DubboFeignClientsConfiguration { + + @Bean + public BeanPostProcessor beanPostProcessor() { + return new BeanPostProcessor() { + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof Feign.Builder) { + Feign.Builder builder = (Feign.Builder) bean; + Feign feign = builder.build(); + } + return bean; + } + }; + } + + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java similarity index 94% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java index 5fe71b3a4..d66a6947c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/MetadataConfigUtils.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.util; +package org.springframework.cloud.alibaba.dubbo.rest.feign; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; @@ -26,9 +26,9 @@ import javax.annotation.PostConstruct; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; /** - * TODO + * Rest Metadata Config Service */ -public class MetadataConfigUtils { +public class RestMetadataConfigService { @Autowired private NacosConfigProperties nacosConfigProperties; diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index e3cb78bf1..1df5be4d8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -1,5 +1,6 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestDiscoveryAutoConfiguration diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java index 4445e880c..08de6e2b0 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -22,21 +22,17 @@ import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; - import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.alibaba.dubbo.service.EchoService; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -71,15 +67,15 @@ public class DubboSpringCloudBootstrap { String echo(@RequestParam("message") String message); } - @Bean - public ApplicationRunner applicationRunner() { - return arguments -> { - // Dubbo Service call - System.out.println(echoService.echo("mercyblitz")); - // Spring Cloud Open Feign REST Call - System.out.println(feignEchoService.echo("mercyblitz")); - }; - } +// @Bean +// public ApplicationRunner applicationRunner() { +// return arguments -> { +// // Dubbo Service call +// System.out.println(echoService.echo("mercyblitz")); +// // Spring Cloud Open Feign REST Call +// System.out.println(feignEchoService.echo("mercyblitz")); +// }; +// } @Autowired From 5c2b118523facc638825ddafa4ee7cc42af4b005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=A9=AC=E5=93=A5?= Date: Sat, 19 Jan 2019 23:21:24 +0800 Subject: [PATCH 10/50] Temporary commit --- .../DubboOpenFeignAutoConfiguration.java | 2 +- .../DubboRestAutoConfiguration.java | 16 +-- .../DubboRestDiscoveryAutoConfiguration.java | 8 +- ...MetadataRegistrationAutoConfiguration.java | 6 +- .../DubboFeignClientsConfiguration.java | 127 +++++++++++++++++- ...er.java => FeignRestMetadataResolver.java} | 86 ++++++++---- .../rest/feign/RestMetadataConfigService.java | 4 +- .../src/test/resources/application.yaml | 5 +- 8 files changed, 203 insertions(+), 51 deletions(-) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/{RestMetadataResolver.java => FeignRestMetadataResolver.java} (67%) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java index 7b0c4c97f..877d2ccd2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java @@ -58,7 +58,7 @@ public class DubboOpenFeignAutoConfiguration { private ObjectProvider feignContextObjectProvider; @EventListener(ApplicationReadyEvent.class) - public void onContextRefreshed(ApplicationReadyEvent event) { + public void onApplicationReady(ApplicationReadyEvent event) { ConfigurableApplicationContext applicationContext = event.getApplicationContext(); // Resolve the subscribed service names for @FeignClient Set feignClientServiceNames = resolveFeignClientServiceNames(applicationContext); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java index 775f706b8..c325e96ea 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -17,10 +17,11 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Contract; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureOrder; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -35,14 +36,9 @@ import org.springframework.core.Ordered; public class DubboRestAutoConfiguration { @Bean - @ConditionalOnMissingBean - public ObjectMapper objectMapper() { - return new ObjectMapper(); - } - - @Bean - public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) { - return new RestMetadataResolver(objectMapper); + public FeignRestMetadataResolver metadataJsonResolver( + ObjectProvider objectMapper, ObjectProvider contract) { + return new FeignRestMetadataResolver(objectMapper, contract); } @Bean diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java index 25ceaf0da..0dcfdec1d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; +import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -63,7 +63,7 @@ public class DubboRestDiscoveryAutoConfiguration { private DiscoveryClient discoveryClient; @Autowired - private RestMetadataResolver restMetadataResolver; + private FeignRestMetadataResolver feignRestMetadataResolver; @Autowired(required = false) private ObjectMapper objectMapper = new ObjectMapper(); @@ -206,7 +206,7 @@ public class DubboRestDiscoveryAutoConfiguration { // Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); // // restMetadata.forEach((dubboServiceName, restJsons) -> { -// restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { +// restJsons.stream().map(feignRestMetadataResolver::resolveRequest).forEach(request -> { // referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); // }); // }); @@ -231,7 +231,7 @@ public class DubboRestDiscoveryAutoConfiguration { // Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); // // restMetadata.forEach((dubboServiceName, restJsons) -> { -// restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> { +// restJsons.stream().map(feignRestMetadataResolver::resolveRequest).forEach(request -> { // referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); // }); // }); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index 2b901e6f2..1179cb0fe 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -23,8 +23,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver; import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver; import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; import org.springframework.cloud.client.serviceregistry.Registration; @@ -57,7 +57,7 @@ public class DubboRestMetadataRegistrationAutoConfiguration { private ObjectMapper objectMapper; @Autowired - private RestMetadataResolver restMetadataResolver; + private FeignRestMetadataResolver feignRestMetadataResolver; @Autowired private RestMetadataConfigService metadataConfigService; @@ -66,7 +66,7 @@ public class DubboRestMetadataRegistrationAutoConfiguration { @EventListener(ServiceBeanExportedEvent.class) public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException { ServiceBean serviceBean = event.getServiceBean(); - serviceRestMetadata.addAll(restMetadataResolver.resolve(serviceBean)); + serviceRestMetadata.addAll(feignRestMetadataResolver.resolveServiceRestMetadata(serviceBean)); } /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java index 6fa4a9788..cbd61416c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java @@ -16,7 +16,10 @@ */ package org.springframework.cloud.alibaba.dubbo.openfeign; -import feign.Feign; +import feign.*; +import feign.codec.Decoder; +import feign.codec.Encoder; +import feign.codec.ErrorDecoder; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration; @@ -45,12 +48,132 @@ public class DubboFeignClientsConfiguration { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Feign.Builder) { Feign.Builder builder = (Feign.Builder) bean; - Feign feign = builder.build(); + BuilderWrapper wrapper = new BuilderWrapper(builder); + return wrapper; } return bean; } }; } + private static class BuilderWrapper extends Feign.Builder { + + private final Feign.Builder delegate; + + private BuilderWrapper(Feign.Builder delegate) { + this.delegate = delegate; + } + + @Override + public Feign.Builder logLevel(Logger.Level logLevel) { + return delegate.logLevel(logLevel); + } + + @Override + public Feign.Builder contract(Contract contract) { + delegate.contract(contract); + return this; + } + + @Override + public Feign.Builder client(Client client) { + delegate.client(client); + return this; + } + + @Override + public Feign.Builder retryer(Retryer retryer) { + delegate.retryer(retryer); + return this; + } + + @Override + public Feign.Builder logger(Logger logger) { + delegate.logger(logger); + return this; + } + + @Override + public Feign.Builder encoder(Encoder encoder) { + delegate.encoder(encoder); + return this; + } + + @Override + public Feign.Builder decoder(Decoder decoder) { + delegate.decoder(decoder); + return this; + } + + @Override + public Feign.Builder queryMapEncoder(QueryMapEncoder queryMapEncoder) { + delegate.queryMapEncoder(queryMapEncoder); + return this; + } + + @Override + public Feign.Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) { + delegate.mapAndDecode(mapper, decoder); + return this; + } + + @Override + public Feign.Builder decode404() { + delegate.decode404(); + return this; + } + + @Override + public Feign.Builder errorDecoder(ErrorDecoder errorDecoder) { + delegate.errorDecoder(errorDecoder); + return this; + } + + @Override + public Feign.Builder options(Request.Options options) { + delegate.options(options); + return this; + } + + @Override + public Feign.Builder requestInterceptor(RequestInterceptor requestInterceptor) { + delegate.requestInterceptor(requestInterceptor); + return this; + } + + @Override + public Feign.Builder requestInterceptors(Iterable requestInterceptors) { + delegate.requestInterceptors(requestInterceptors); + return this; + } + + @Override + public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) { + delegate.invocationHandlerFactory(invocationHandlerFactory); + return this; + } + + @Override + public Feign.Builder doNotCloseAfterDecode() { + delegate.doNotCloseAfterDecode(); + return this; + } + + @Override + public T target(Class apiType, String url) { + return delegate.target(apiType, url); + } + + @Override + public T target(Target target) { + return delegate.target(target); + } + + @Override + public Feign build() { + return delegate.build(); + } + } + } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/FeignRestMetadataResolver.java similarity index 67% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/FeignRestMetadataResolver.java index 994d0a985..e2588c50e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/FeignRestMetadataResolver.java @@ -26,10 +26,12 @@ import feign.Request; import feign.RequestTemplate; import feign.jaxrs2.JAXRS2Contract; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry; import org.springframework.cloud.alibaba.dubbo.rest.metadata.MethodRestMetadata; import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; @@ -44,18 +46,29 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** - * The JSON resolver for {@link MethodMetadata} + * The REST metadata resolver for Feign + * + * @author Mercy */ -public class RestMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton { +public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton { private static final String METHOD_PROPERTY_NAME = "method"; private static final String URL_PROPERTY_NAME = "url"; private static final String HEADERS_PROPERTY_NAME = "headers"; + private static final String[] CONTRACT_CLASS_NAMES = { + "feign.jaxrs2.JAXRS2Contract", + "org.springframework.cloud.openfeign.support.SpringMvcContract", + }; + private final ObjectMapper objectMapper; + private final ObjectProvider contract; + /** * Feign Contracts */ @@ -63,37 +76,44 @@ public class RestMetadataResolver implements BeanClassLoaderAware, SmartInitiali private ClassLoader classLoader; - @Autowired - private ObjectProvider contractObjectProvider; + @Value("${spring.application.name}") + private String currentApplicationName; - public RestMetadataResolver(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; + public FeignRestMetadataResolver(ObjectProvider objectMapper, ObjectProvider contract) { + this.objectMapper = objectMapper.getIfAvailable(); + this.contract = contract; } @Override public void afterSingletonsInstantiated() { - Collection contracts = new LinkedList<>(); + LinkedList contracts = new LinkedList<>(); - // Add injected Contract , for example SpringMvcContract Bean under Spring Cloud Open Feign - Contract contract = contractObjectProvider.getIfAvailable(); - if (contract != null) { - contracts.add(contract); - } else { - if (ClassUtils.isPresent("org.springframework.cloud.openfeign.support.SpringMvcContract", classLoader)) { - contracts.add(new SpringMvcContract()); - } - } + // Add injected Contract if available, for example SpringMvcContract Bean under Spring Cloud Open Feign + contract.ifAvailable(contracts::add); - // Add JAXRS2Contract if it's present in Class Path - if (ClassUtils.isPresent("javax.ws.rs.Path", classLoader)) { - contracts.add(new JAXRS2Contract()); - } + Stream.of(CONTRACT_CLASS_NAMES) + .filter(this::isClassPresent) // filter the existed classes + .map(this::loadContractClass) // load Contract Class + .map(this::createContract) // create instance by the specified class + .forEach(contracts::add); // add the Contract instance into contracts this.contracts = Collections.unmodifiableCollection(contracts); } - public Set resolve(ServiceBean serviceBean) { + private Contract createContract(Class contractClassName) { + return (Contract) BeanUtils.instantiateClass(contractClassName); + } + + private Class loadContractClass(String contractClassName) { + return ClassUtils.resolveClassName(contractClassName, classLoader); + } + + private boolean isClassPresent(String className) { + return ClassUtils.isPresent(className, classLoader); + } + + public Set resolveServiceRestMetadata(ServiceBean serviceBean) { Object bean = serviceBean.getRef(); @@ -103,14 +123,7 @@ public class RestMetadataResolver implements BeanClassLoaderAware, SmartInitiali Set serviceRestMetadata = new LinkedHashSet<>(); - Set methodRestMetadata = new LinkedHashSet<>(); - - contracts.stream() - .map(contract -> contract.parseAndValidatateMetadata(bean.getClass())) - .flatMap(v -> v.stream()) - .forEach(methodMetadata -> { - methodRestMetadata.add(resolveMethodRestMetadata(methodMetadata, beanType, interfaceClass)); - }); + Set methodRestMetadata = resolveMethodRestMetadata(beanType, interfaceClass); List urls = serviceBean.getExportedUrls(); @@ -126,6 +139,18 @@ public class RestMetadataResolver implements BeanClassLoaderAware, SmartInitiali return serviceRestMetadata; } + public Set resolveMethodRestMetadata(Class targetClass) { + return resolveMethodRestMetadata(targetClass, targetClass); + } + + protected Set resolveMethodRestMetadata(Class targetClass, Class revisedClass) { + return contracts.stream() + .map(contract -> contract.parseAndValidatateMetadata(targetClass)) + .flatMap(v -> v.stream()) + .map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetClass, revisedClass)) + .collect(Collectors.toSet()); + } + private String toJson(Object object) { String jsonContent = null; try { @@ -137,6 +162,9 @@ public class RestMetadataResolver implements BeanClassLoaderAware, SmartInitiali } private String regenerateConfigKey(String configKey, Class beanType, Class interfaceClass) { + if (beanType.equals(interfaceClass)) { + return configKey; + } return StringUtils.replace(configKey, beanType.getSimpleName(), interfaceClass.getSimpleName()); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java index d66a6947c..cc14191fc 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java @@ -27,6 +27,8 @@ import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; /** * Rest Metadata Config Service + * + * @author Mercy */ public class RestMetadataConfigService { @@ -45,7 +47,7 @@ public class RestMetadataConfigService { * TODO JavaDoc */ private static String getServiceRestMetadataDataId(String serviceName) { - return serviceName + "-rest-metadata.json"; + return "metadata:rest:" + serviceName + ".json"; } public void publishServiceRestMetadata(String serviceName, String restMetadataJSON) diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml index 2dc92d598..afdfbfa78 100644 --- a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml +++ b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml @@ -10,4 +10,7 @@ dubbo: port: 9090 server: netty registry: - address: spring-cloud://nacos \ No newline at end of file + address: spring-cloud://nacos + +server: + port: 8080 \ No newline at end of file From fc72c76a9d5e549703a6fc4ad333072e8b953441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= Date: Mon, 21 Jan 2019 12:36:56 +0800 Subject: [PATCH 11/50] fix #276 --- .../nacos-example/nacos-config-example/readme-zh.md | 4 ++-- .../nacos-example/nacos-config-example/readme.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md index e7339058c..390b567e3 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md @@ -113,11 +113,11 @@ Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 `Config 在 Nacos Config Starter 中,dataId 的拼接格式如下 - ${prefix} - ${spring.active.profile} . ${file-extension} + ${prefix} - ${spring.profiles.active} . ${file-extension} * `prefix` 默认为 `spring.application.name` 的值,也可以通过配置项 `spring.cloud.nacos.config.prefix`来配置。 -* `spring.active.profile` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles) +* `spring.profiles.active` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles) **注意,当 activeprofile 为空时,对应的连接符 `-` 也将不存在,dataId 的拼接格式变成 `${prefix}`.`${file-extension}`** diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md index 58b499aef..702a51077 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md @@ -114,11 +114,11 @@ Nacos Client gets data from Nacos Server through this method. `ConfigService.get In Nacos Config Starter, the splicing format of dataId is as follows - ${prefix} - ${spring.active.profile} . ${file-extension} + ${prefix} - ${spring.profiles.active} . ${file-extension} * `prefix` default value is `spring.application.name` value, which can also be configured via the configuration item `spring.cloud.nacos.config.prefix`. -* `spring.active.profile` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles) +* `spring.profiles.active` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles) **Note: when the activeprofile is empty, the corresponding connector `-` will also not exist, and the splicing format of the dataId becomes `${prefix}`.`${file-extension}`** From 3c51f9f8d8da2fbcf7763b964bd4892e50c0beb8 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 00:25:55 +0800 Subject: [PATCH 12/50] Polish the first GA for spring-cloud-alibaba-dubbo --- ...va => DubboMetadataAutoConfiguration.java} | 27 +- .../DubboOpenFeignAutoConfiguration.java | 68 +---- .../DubboRestDiscoveryAutoConfiguration.java | 269 ------------------ ...MetadataRegistrationAutoConfiguration.java | 32 +-- .../dubbo/metadata/MethodMetadata.java | 122 ++++++++ .../metadata/MethodParameterMetadata.java | 73 +++++ .../RequestMetadata.java} | 55 ++-- .../dubbo/metadata/RestMethodMetadata.java | 72 +++++ .../metadata/ServiceRestMetadata.java | 13 +- .../DubboServiceMetadataRepository.java | 118 ++++++++ .../resolver/FeignMetadataResolver.java} | 134 ++++----- .../metadata/resolver/MetadataResolver.java | 47 +++ .../service/MetadataConfigService.java | 33 +++ .../service/NacosMetadataConfigService.java} | 52 +++- .../DubboFeignClientsConfiguration.java | 136 +-------- .../openfeign/DubboInvocationHandler.java | 69 +++++ .../DubboInvocationHandlerFactory.java | 101 +++++++ .../dubbo/registry/SpringCloudRegistry.java | 64 ++++- .../main/resources/META-INF/spring.factories | 5 +- .../bootstrap/DubboSpringCloudBootstrap.java | 50 +--- 20 files changed, 884 insertions(+), 656 deletions(-) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/{DubboRestAutoConfiguration.java => DubboMetadataAutoConfiguration.java} (61%) delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{rest/metadata/MethodRestMetadata.java => metadata/RequestMetadata.java} (53%) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{rest => }/metadata/ServiceRestMetadata.java (84%) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{rest/feign/FeignRestMetadataResolver.java => metadata/resolver/FeignMetadataResolver.java} (53%) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{rest/feign/RestMetadataConfigService.java => metadata/service/NacosMetadataConfigService.java} (50%) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java similarity index 61% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index c325e96ea..d5db05ea3 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -16,34 +16,31 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; -import com.fasterxml.jackson.databind.ObjectMapper; -import feign.Contract; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureOrder; -import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver; -import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; +import org.springframework.cloud.alibaba.dubbo.metadata.service.NacosMetadataConfigService; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; /** - * Spring Boot Auto-Configuration class for Dubbo REST + * Spring Boot Auto-Configuration class for Dubbo Metadata * * @author Mercy */ @Configuration +@Import(DubboServiceMetadataRepository.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) -public class DubboRestAutoConfiguration { +public class DubboMetadataAutoConfiguration { @Bean - public FeignRestMetadataResolver metadataJsonResolver( - ObjectProvider objectMapper, ObjectProvider contract) { - return new FeignRestMetadataResolver(objectMapper, contract); - } - - @Bean - public RestMetadataConfigService restMetadataConfigService() { - return new RestMetadataConfigService(); + @ConditionalOnBean(NacosConfigProperties.class) + public MetadataConfigService metadataConfigService() { + return new NacosMetadataConfigService(); } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java index 877d2ccd2..d37d8dc01 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java @@ -16,28 +16,20 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; +import feign.Contract; import feign.Feign; -import feign.RequestInterceptor; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.alibaba.dubbo.metadata.resolver.FeignMetadataResolver; +import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; import org.springframework.cloud.alibaba.dubbo.openfeign.DubboFeignClientsConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignAutoConfiguration; -import org.springframework.cloud.openfeign.FeignContext; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.EventListener; - -import java.util.LinkedHashSet; -import java.util.Set; - -import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME; /** @@ -45,52 +37,18 @@ import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFei * * @author Mercy */ -@ConditionalOnClass(value = Feign.class, name = FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME) -@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class) +@ConditionalOnClass(value = Feign.class) @AutoConfigureAfter(FeignAutoConfiguration.class) +@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class) @Configuration public class DubboOpenFeignAutoConfiguration { - static final String FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME = - "org.springframework.cloud.openfeign.FeignClientFactoryBean"; - - @Autowired - private ObjectProvider feignContextObjectProvider; - - @EventListener(ApplicationReadyEvent.class) - public void onApplicationReady(ApplicationReadyEvent event) { - ConfigurableApplicationContext applicationContext = event.getApplicationContext(); - // Resolve the subscribed service names for @FeignClient - Set feignClientServiceNames = resolveFeignClientServiceNames(applicationContext); - // FeignContext - FeignContext feignContext = feignContextObjectProvider.getIfAvailable(); - - } - - /** - * Resolve the subscribed service names for @FeignClient - * - * @param applicationContext Current {@link ConfigurableApplicationContext} - * @return non-null {@link Set} - */ - private Set resolveFeignClientServiceNames(ConfigurableApplicationContext applicationContext) { - Set feignClientServiceNames = new LinkedHashSet<>(); - ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); - for (String beanName : beanFactory.getBeanDefinitionNames()) { - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); - if (FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME.equals(beanDefinition.getBeanClassName())) { - String feignClientServiceName = (String) beanDefinition.getPropertyValues().get("name"); - feignClientServiceNames.add(feignClientServiceName); - } - } - return feignClientServiceNames; - } + @Value("${spring.application.name}") + private String currentApplicationName; @Bean - public RequestInterceptor requestInterceptor() { - return template -> { - System.out.println(template); - }; + @ConditionalOnMissingBean + public MetadataResolver metadataJsonResolver(ObjectProvider contract) { + return new FeignMetadataResolver(currentApplicationName, contract); } - -} +} \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java deleted file mode 100644 index 0dcfdec1d..000000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestDiscoveryAutoConfiguration.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.autoconfigure; - -import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration; -import com.alibaba.dubbo.config.ApplicationConfig; -import com.alibaba.dubbo.config.RegistryConfig; -import com.alibaba.dubbo.config.spring.ReferenceBean; -import com.fasterxml.jackson.databind.ObjectMapper; -import feign.Client; -import feign.Request; -import feign.Response; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.StringUtils; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** - * The Auto-Configuration class for Dubbo REST Discovery - * - * @author Mercy - */ -@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = true) -@AutoConfigureAfter(value = { - DubboAutoConfiguration.class, - DubboRestAutoConfiguration.class, - DubboRestMetadataRegistrationAutoConfiguration.class}) -@Configuration -public class DubboRestDiscoveryAutoConfiguration { - - private static final String FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME = - "org.springframework.cloud.openfeign.FeignClientFactoryBean"; - - @Autowired - private DiscoveryClient discoveryClient; - - @Autowired - private FeignRestMetadataResolver feignRestMetadataResolver; - - @Autowired(required = false) - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Feign Request -> Dubbo ReferenceBean - */ - private Map referenceBeanCache = new HashMap<>(); - - @Autowired - private ApplicationConfig applicationConfig; - - @Value("${spring.application.name}") - private String applicationName; - - @Value("${spring.cloud.nacos.discovery.server-addr}") - private String nacosServerAddress; - - @Autowired - private RestMetadataConfigService restMetadataConfigService; - - private ReferenceBean buildReferenceBean(String dubboServiceName) { - ReferenceBean referenceBean = new ReferenceBean(); - applicationConfig.setName("service-consumer"); - referenceBean.setApplication(applicationConfig); - RegistryConfig registryConfig = new RegistryConfig(); - // requires dubbo-registry-nacos - registryConfig.setAddress("nacos://" + nacosServerAddress); - referenceBean.setRegistry(registryConfig); - String[] parts = StringUtils.delimitedListToStringArray(dubboServiceName, ":"); - referenceBean.setInterface(parts[1]); - referenceBean.setVersion(parts[2]); - referenceBean.setGroup(parts.length > 3 ? parts[3] : null); - referenceBean.get(); - return referenceBean; - } - - @Bean - public BeanPostProcessor wrapClientBeanPostProcessor() { - return new BeanPostProcessor() { - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (bean instanceof Client) { - Client client = (Client) bean; - // wrapper - return new DubboFeignClientProxy(client); - } - return bean; - } - }; - } - - class DubboFeignClientProxy implements Client { - - private final Client delegate; - - DubboFeignClientProxy(Client delegate) { - this.delegate = delegate; - } - - @Override - public Response execute(Request request, Request.Options options) throws IOException { - - ReferenceBean referenceBean = referenceBeanCache.get(request.toString()); - - if (referenceBean != null) { - Object dubboClient = referenceBean.get(); - Method method = null; - Object[] params = null; - - try { - Object result = method.invoke(dubboClient, params); - // wrapper as a Response - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - - return delegate.execute(request, options); - } - - } - -} - - -// private Method getRegistrationMethod; -// -// @PostConstruct -// public void init() throws NoSuchMethodException { -// getRegistrationMethod = initGetRegistrationMethod(); -// } -// -// /** -// * Initializes {@link AbstractAutoServiceRegistration#getRegistration() getRegistration method} that is is protected. -// * -// * @return {@link Method} -// * @throws NoSuchMethodException -// */ -// private Method initGetRegistrationMethod() throws NoSuchMethodException { -// Method method = AbstractAutoServiceRegistration.class.getDeclaredMethod("getRegistration"); -// method.setAccessible(true); -// return method; -// } -// -// private Registration getRegistration(AbstractAutoServiceRegistration source) { -// return (Registration) ReflectionUtils.invokeMethod(getRegistrationMethod, source); -// } -// -// private void noop() { -// Map specifications = -// beanFactory.getBeansOfType(NamedContextFactory.Specification.class); -// // 1. Get all service names from Spring beans that was annotated by @FeignClient -// List serviceNames = new LinkedList<>(); -// -// specifications.forEach((beanName, specification) -> -// -// { -// String serviceName = beanName.substring(0, beanName.indexOf(".")); -// serviceNames.add(serviceName); -// -// // 2. Get all service instances by echo specified service name -// List serviceInstances = discoveryClient.getInstances(serviceName); -// if (!serviceInstances.isEmpty()) { -// ServiceInstance serviceInstance = serviceInstances.get(0); -// // 3. Get Rest metadata from service instance -// Map metadata = serviceInstance.getMetadata(); -// // 4. Resolve REST metadata from the @FeignClient instance -// String restMetadataJson = metadata.get("restMetadata"); -// /** -// * { -// * "providers:org.springframework.cloud.alibaba.dubbo.service.EchoService:1.0.0": [ -// * "{\"method\":\"POST\",\"url\":\"/plus?a={a}&b={b}\",\"headers\":{}}", -// * "{\"method\":\"GET\",\"url\":\"/echo?message={message}\",\"headers\":{}}" -// * ] -// * } -// */ -// try { -// Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); -// -// restMetadata.forEach((dubboServiceName, restJsons) -> { -// restJsons.stream().map(feignRestMetadataResolver::resolveRequest).forEach(request -> { -// referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); -// }); -// }); -// -// } catch (IOException e) { -// throw new RuntimeException(e); -// } -// -// // -// } -// }); -// } -// -// private ReferenceBean buildReferenceBean(ServiceInstance serviceInstance) { -// -// ReferenceBean referenceBean = new ReferenceBean(); -// Map metadata = serviceInstance.getMetadata(); -// // 4. Resolve REST metadata from the @FeignClient instance -// String restMetadataJson = metadata.get("restMetadata"); -// -// try { -// Map> restMetadata = objectMapper.readValue(restMetadataJson, Map.class); -// -// restMetadata.forEach((dubboServiceName, restJsons) -> { -// restJsons.stream().map(feignRestMetadataResolver::resolveRequest).forEach(request -> { -// referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName)); -// }); -// }); -// -// } catch (IOException e) { -// throw new RuntimeException(e); -// } -// -// return referenceBean; -// } - -// /** -// * Handle on self instance registered. -// * -// * @param event {@link InstanceRegisteredEvent} -// */ -// @EventListener(InstanceRegisteredEvent.class) -// public void onSelfInstanceRegistered(InstanceRegisteredEvent event) throws Exception { -// -// Class targetClass = AbstractAutoServiceRegistration.class; -// -// Object source = event.getSource(); -// -// Assert.isInstanceOf(targetClass, source, -// format("The source of %s must implement %s", source, targetClass.getName())); -// -// Registration registration = getRegistration((AbstractAutoServiceRegistration) source); -// -// String serviceRestMetaDataConfig = -// restMetadataConfigService.getServiceRestMetadata(registration.getServiceId()); -// -// Set serviceRestMetadata = objectMapper.readValue(serviceRestMetaDataConfig, -// TypeFactory.defaultInstance().constructCollectionType(Set.class, ServiceRestMetadata.class)); -// -// } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index 1179cb0fe..458b1ca1f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -19,13 +19,13 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver; -import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; +import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Configuration; @@ -42,8 +42,14 @@ import java.util.Set; * @author Mercy */ @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) +@ConditionalOnMissingBean(value = { + MetadataResolver.class, + MetadataConfigService.class +}) @AutoConfigureAfter(value = { - DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class}) + DubboMetadataAutoConfiguration.class, + DubboServiceRegistrationAutoConfiguration.class +}) @Configuration public class DubboRestMetadataRegistrationAutoConfiguration { @@ -54,19 +60,15 @@ public class DubboRestMetadataRegistrationAutoConfiguration { private final Set serviceRestMetadata = new LinkedHashSet<>(); @Autowired - private ObjectMapper objectMapper; + private MetadataResolver metadataResolver; @Autowired - private FeignRestMetadataResolver feignRestMetadataResolver; - - @Autowired - private RestMetadataConfigService metadataConfigService; - + private MetadataConfigService metadataConfigService; @EventListener(ServiceBeanExportedEvent.class) public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException { ServiceBean serviceBean = event.getServiceBean(); - serviceRestMetadata.addAll(feignRestMetadataResolver.resolveServiceRestMetadata(serviceBean)); + serviceRestMetadata.addAll(metadataResolver.resolveServiceRestMetadata(serviceBean)); } /** @@ -81,11 +83,7 @@ public class DubboRestMetadataRegistrationAutoConfiguration { @EventListener(InstancePreRegisteredEvent.class) public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception { Registration registration = event.getRegistration(); - - String restMetadataJson = objectMapper.writeValueAsString(serviceRestMetadata); - - metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), restMetadataJson); - + metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), serviceRestMetadata); } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java new file mode 100644 index 000000000..18abf0e96 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.metadata; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.commons.lang3.ClassUtils; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +/** + * {@link Method} Metadata + * + * @author Mercy + */ +public class MethodMetadata { + + private String name; + + private String returnType; + + private List params; + + @JsonIgnore + private Method method; + + public MethodMetadata() { + this.params = new LinkedList<>(); + } + + public MethodMetadata(Method method) { + this.name = method.getName(); + this.returnType = ClassUtils.getName(method.getReturnType()); + this.params = initParameters(method); + this.method = method; + } + + private List initParameters(Method method) { + int parameterCount = method.getParameterCount(); + if (parameterCount < 1) { + return Collections.emptyList(); + } + List params = new ArrayList<>(parameterCount); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameterCount; i++) { + Parameter parameter = parameters[i]; + MethodParameterMetadata param = toMethodParameterMetadata(i, parameter); + params.add(param); + } + return params; + } + + private MethodParameterMetadata toMethodParameterMetadata(int index, Parameter parameter) { + MethodParameterMetadata metadata = new MethodParameterMetadata(); + metadata.setIndex(index); + metadata.setName(parameter.getName()); + metadata.setType(parameter.getType().getTypeName()); + return metadata; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + + public Method getMethod() { + return method; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodMetadata that = (MethodMetadata) o; + return Objects.equals(name, that.name) && + Objects.equals(returnType, that.returnType) && + Objects.equals(params, that.params); + } + + @Override + public int hashCode() { + return Objects.hash(name, returnType, params); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.java new file mode 100644 index 000000000..fbcaad00a --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.metadata; + +import java.lang.reflect.Method; +import java.util.Objects; + +/** + * {@link Method} Parameter Metadata + * + * @author Mercy + */ +public class MethodParameterMetadata { + + private int index; + + private String name; + + private String type; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodParameterMetadata that = (MethodParameterMetadata) o; + return index == that.index && + Objects.equals(name, that.name) && + Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hash(index, name, type); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RequestMetadata.java similarity index 53% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RequestMetadata.java index ad8d9db9f..ae3d10dce 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/MethodRestMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RequestMetadata.java @@ -14,32 +14,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.rest.metadata; +package org.springframework.cloud.alibaba.dubbo.metadata; + +import feign.RequestTemplate; import java.util.Collection; import java.util.Map; +import java.util.Objects; /** - * TODO + * Request Metadata + * + * @author Mercy */ -public class MethodRestMetadata { - - private String configKey; +public class RequestMetadata { private String method; private String url; - private Map> headers; + private Map> queries; - private Map> indexToName; + private Map> headers; - public String getConfigKey() { - return configKey; + public RequestMetadata() { } - public void setConfigKey(String configKey) { - this.configKey = configKey; + public RequestMetadata(RequestTemplate requestTemplate) { + this.method = requestTemplate.method(); + this.url = requestTemplate.url(); + this.queries = requestTemplate.queries(); + this.headers = requestTemplate.headers(); } public String getMethod() { @@ -66,35 +71,27 @@ public class MethodRestMetadata { this.headers = headers; } - public Map> getIndexToName() { - return indexToName; + public Map> getQueries() { + return queries; } - public void setIndexToName(Map> indexToName) { - this.indexToName = indexToName; + public void setQueries(Map> queries) { + this.queries = queries; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - - MethodRestMetadata that = (MethodRestMetadata) o; - - if (configKey != null ? !configKey.equals(that.configKey) : that.configKey != null) return false; - if (method != null ? !method.equals(that.method) : that.method != null) return false; - if (url != null ? !url.equals(that.url) : that.url != null) return false; - if (headers != null ? !headers.equals(that.headers) : that.headers != null) return false; - return indexToName != null ? indexToName.equals(that.indexToName) : that.indexToName == null; + RequestMetadata that = (RequestMetadata) o; + return Objects.equals(method, that.method) && + Objects.equals(url, that.url) && + Objects.equals(queries, that.queries) && + Objects.equals(headers, that.headers); } @Override public int hashCode() { - int result = configKey != null ? configKey.hashCode() : 0; - result = 31 * result + (method != null ? method.hashCode() : 0); - result = 31 * result + (url != null ? url.hashCode() : 0); - result = 31 * result + (headers != null ? headers.hashCode() : 0); - result = 31 * result + (indexToName != null ? indexToName.hashCode() : 0); - return result; + return Objects.hash(method, url, queries, headers); } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java new file mode 100644 index 000000000..5024fefa5 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.metadata; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +/** + * Method Request Metadata + */ +public class RestMethodMetadata { + + private MethodMetadata method; + + private RequestMetadata request; + + private Map> indexToName; + + public MethodMetadata getMethod() { + return method; + } + + public void setMethod(MethodMetadata method) { + this.method = method; + } + + public RequestMetadata getRequest() { + return request; + } + + public void setRequest(RequestMetadata request) { + this.request = request; + } + + public Map> getIndexToName() { + return indexToName; + } + + public void setIndexToName(Map> indexToName) { + this.indexToName = indexToName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RestMethodMetadata that = (RestMethodMetadata) o; + return Objects.equals(method, that.method) && + Objects.equals(request, that.request) && + Objects.equals(indexToName, that.indexToName); + } + + @Override + public int hashCode() { + return Objects.hash(method, request, indexToName); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/ServiceRestMetadata.java similarity index 84% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/ServiceRestMetadata.java index 6b93302fa..d5ba11f44 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/metadata/ServiceRestMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/ServiceRestMetadata.java @@ -14,18 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.rest.metadata; +package org.springframework.cloud.alibaba.dubbo.metadata; import java.util.Set; /** - * TODO + * Service Rest Metadata + * + * @author Mercy + * @see RestMethodMetadata */ public class ServiceRestMetadata { private String name; - private Set meta; + private Set meta; public String getName() { return name; @@ -35,11 +38,11 @@ public class ServiceRestMetadata { this.name = name; } - public Set getMeta() { + public Set getMeta() { return meta; } - public void setMeta(Set meta) { + public void setMeta(Set meta) { this.meta = meta; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java new file mode 100644 index 000000000..57a0a1337 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.metadata.repository; + +import com.alibaba.dubbo.config.spring.ReferenceBean; +import com.alibaba.dubbo.rpc.service.GenericService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceGroup; +import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceInterface; +import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceSegments; +import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceVersion; + +/** + * Dubbo Service Metadata {@link Repository} + * + * @author Mercy + */ +@Repository +public class DubboServiceMetadataRepository { + + /** + * Key is application name + * Value is Map + */ + private Map> genericServicesRepository = new HashMap<>(); + + private Map> methodMetadataRepository = new HashMap<>(); + + @Autowired + private MetadataConfigService metadataConfigService; + + @Value("${dubbo.target.protocol:dubbo}") + private String targetProtocol; + + @Value("${dubbo.target.cluster:failover}") + private String targetCluster; + + public void updateMetadata(String serviceName) { + + Map genericServicesMap = genericServicesRepository.computeIfAbsent(serviceName, k -> new HashMap<>()); + + Map methodMetadataMap = methodMetadataRepository.computeIfAbsent(serviceName, k -> new HashMap<>()); + + Set serviceRestMetadataSet = metadataConfigService.getServiceRestMetadata(serviceName); + + for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { + + ReferenceBean referenceBean = adaptReferenceBean(serviceRestMetadata); + + serviceRestMetadata.getMeta().forEach(restMethodMetadata -> { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + genericServicesMap.put(requestMetadata, referenceBean.get()); + methodMetadataMap.put(requestMetadata, restMethodMetadata.getMethod()); + }); + } + } + + public GenericService getGenericService(String serviceName, RequestMetadata requestMetadata) { + return getGenericServicesMap(serviceName).get(requestMetadata); + } + + public MethodMetadata getMethodMetadata(String serviceName, RequestMetadata requestMetadata) { + return getMethodMetadataMap(serviceName).get(requestMetadata); + } + + private ReferenceBean adaptReferenceBean(ServiceRestMetadata serviceRestMetadata) { + String dubboServiceName = serviceRestMetadata.getName(); + String[] segments = getServiceSegments(dubboServiceName); + String interfaceName = getServiceInterface(segments); + String version = getServiceVersion(segments); + String group = getServiceGroup(segments); + + ReferenceBean referenceBean = new ReferenceBean(); + referenceBean.setGeneric(true); + referenceBean.setInterface(interfaceName); + referenceBean.setVersion(version); + referenceBean.setGroup(group); + referenceBean.setProtocol(targetProtocol); + referenceBean.setCluster(targetCluster); + + return referenceBean; + } + + private Map getGenericServicesMap(String serviceName) { + return genericServicesRepository.getOrDefault(serviceName, Collections.emptyMap()); + } + + private Map getMethodMetadataMap(String serviceName) { + return methodMetadataRepository.getOrDefault(serviceName, Collections.emptyMap()); + } + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/FeignRestMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/FeignMetadataResolver.java similarity index 53% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/FeignRestMetadataResolver.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/FeignMetadataResolver.java index e2588c50e..e7f80dd4f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/FeignRestMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/FeignMetadataResolver.java @@ -14,73 +14,60 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.rest.feign; +package org.springframework.cloud.alibaba.dubbo.metadata.resolver; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.config.spring.ServiceBean; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import feign.Contract; +import feign.Feign; import feign.MethodMetadata; -import feign.Request; -import feign.RequestTemplate; -import feign.jaxrs2.JAXRS2Contract; -import org.apache.commons.lang3.StringUtils; +import feign.Util; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry; -import org.springframework.cloud.alibaba.dubbo.rest.metadata.MethodRestMetadata; -import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata; -import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.util.ClassUtils; -import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; /** - * The REST metadata resolver for Feign + * The metadata resolver for {@link Feign} * * @author Mercy */ -public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton { - - private static final String METHOD_PROPERTY_NAME = "method"; - private static final String URL_PROPERTY_NAME = "url"; - private static final String HEADERS_PROPERTY_NAME = "headers"; +public class FeignMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton, MetadataResolver { private static final String[] CONTRACT_CLASS_NAMES = { "feign.jaxrs2.JAXRS2Contract", "org.springframework.cloud.openfeign.support.SpringMvcContract", }; - private final ObjectMapper objectMapper; + private final String currentApplicationName; private final ObjectProvider contract; + private ClassLoader classLoader; + /** * Feign Contracts */ private Collection contracts; - private ClassLoader classLoader; - - @Value("${spring.application.name}") - private String currentApplicationName; - - public FeignRestMetadataResolver(ObjectProvider objectMapper, ObjectProvider contract) { - this.objectMapper = objectMapper.getIfAvailable(); + public FeignMetadataResolver(String currentApplicationName, ObjectProvider contract) { + this.currentApplicationName = currentApplicationName; this.contract = contract; } @@ -113,17 +100,16 @@ public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartIni return ClassUtils.isPresent(className, classLoader); } + @Override public Set resolveServiceRestMetadata(ServiceBean serviceBean) { Object bean = serviceBean.getRef(); Class beanType = bean.getClass(); - Class interfaceClass = serviceBean.getInterfaceClass(); - Set serviceRestMetadata = new LinkedHashSet<>(); - Set methodRestMetadata = resolveMethodRestMetadata(beanType, interfaceClass); + Set methodRestMetadata = resolveMethodRestMetadata(beanType); List urls = serviceBean.getExportedUrls(); @@ -139,65 +125,61 @@ public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartIni return serviceRestMetadata; } - public Set resolveMethodRestMetadata(Class targetClass) { - return resolveMethodRestMetadata(targetClass, targetClass); - } - - protected Set resolveMethodRestMetadata(Class targetClass, Class revisedClass) { + @Override + public Set resolveMethodRestMetadata(Class targetType) { + List feignContractMethods = selectFeignContractMethods(targetType); return contracts.stream() - .map(contract -> contract.parseAndValidatateMetadata(targetClass)) + .map(contract -> contract.parseAndValidatateMetadata(targetType)) .flatMap(v -> v.stream()) - .map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetClass, revisedClass)) + .map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetType, feignContractMethods)) .collect(Collectors.toSet()); } - private String toJson(Object object) { - String jsonContent = null; - try { - jsonContent = objectMapper.writeValueAsString(object); - } catch (JsonProcessingException e) { - throw new IllegalArgumentException(e); - } - return jsonContent; - } - - private String regenerateConfigKey(String configKey, Class beanType, Class interfaceClass) { - if (beanType.equals(interfaceClass)) { - return configKey; + /** + * Select feign contract methods + *

+ * extract some code from {@link Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class)} + * + * @param targetType + * @return non-null + */ + private List selectFeignContractMethods(Class targetType) { + List methods = new LinkedList<>(); + for (Method method : targetType.getMethods()) { + if (method.getDeclaringClass() == Object.class || + (method.getModifiers() & Modifier.STATIC) != 0 || + Util.isDefault(method)) { + continue; + } + methods.add(method); } - return StringUtils.replace(configKey, beanType.getSimpleName(), interfaceClass.getSimpleName()); + return methods; } - protected MethodRestMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class beanType, - Class interfaceClass) { - RequestTemplate requestTemplate = methodMetadata.template(); - Request request = requestTemplate.request(); - + protected RestMethodMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class targetType, + List feignContractMethods) { String configKey = methodMetadata.configKey(); - String newConfigKey = regenerateConfigKey(configKey, beanType, interfaceClass); + Method feignContractMethod = getMatchedFeignContractMethod(targetType, feignContractMethods, configKey); + + RestMethodMetadata metadata = new RestMethodMetadata(); - MethodRestMetadata methodRestMetadata = new MethodRestMetadata(); - methodRestMetadata.setConfigKey(newConfigKey); - methodRestMetadata.setMethod(request.method()); - methodRestMetadata.setUrl(request.url()); - methodRestMetadata.setHeaders(request.headers()); - methodRestMetadata.setIndexToName(methodMetadata.indexToName()); + metadata.setRequest(new RequestMetadata(methodMetadata.template())); + metadata.setMethod(new org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata(feignContractMethod)); + metadata.setIndexToName(methodMetadata.indexToName()); - return methodRestMetadata; + return metadata; } - public Request resolveRequest(String json) { - Request request = null; - try { - Map data = objectMapper.readValue(json, Map.class); - String method = (String) data.get(METHOD_PROPERTY_NAME); - String url = (String) data.get(URL_PROPERTY_NAME); - Map> headers = (Map) data.get(HEADERS_PROPERTY_NAME); - request = Request.create(method, url, headers, null, null); - } catch (IOException e) { - throw new IllegalArgumentException(e); + private Method getMatchedFeignContractMethod(Class targetType, List methods, String expectedConfigKey) { + Method matchedMethod = null; + for (Method method : methods) { + String configKey = Feign.configKey(targetType, method); + if (expectedConfigKey.equals(configKey)) { + matchedMethod = method; + break; + } } - return request; + return matchedMethod; } @Override diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java new file mode 100644 index 000000000..4956e3870 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.metadata.resolver; + +import com.alibaba.dubbo.config.spring.ServiceBean; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; + +import java.util.Set; + +/** + * The REST metadata resolver + * + * @author Mercy + */ +public interface MetadataResolver { + + /** + * Resolve the {@link ServiceRestMetadata} {@link Set set} from {@link ServiceBean} + * + * @param serviceBean {@link ServiceBean} + * @return non-null {@link Set} + */ + Set resolveServiceRestMetadata(ServiceBean serviceBean); + + /** + * Resolve {@link RestMethodMetadata} {@link Set set} from {@link Class target type} + * + * @param targetType {@link Class target type} + * @return non-null {@link Set} + */ + Set resolveMethodRestMetadata(Class targetType); +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java new file mode 100644 index 000000000..28b7a373f --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.metadata.service; + +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; + +import java.util.Set; + +/** + * Config Service for Metadata + * + * @author Mercy + */ +public interface MetadataConfigService { + + void publishServiceRestMetadata(String serviceName, Set serviceRestMetadata); + + Set getServiceRestMetadata(String serviceName); +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java similarity index 50% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java index cc14191fc..93ce9281c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/rest/feign/RestMetadataConfigService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java @@ -14,23 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.rest.feign; +package org.springframework.cloud.alibaba.dubbo.metadata.service; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; /** - * Rest Metadata Config Service + * Nacos {@link MetadataConfigService} * * @author Mercy */ -public class RestMetadataConfigService { +public class NacosMetadataConfigService implements MetadataConfigService { + + private final ObjectMapper objectMapper = new ObjectMapper(); @Autowired private NacosConfigProperties nacosConfigProperties; @@ -40,24 +50,48 @@ public class RestMetadataConfigService { @PostConstruct public void init() { this.configService = nacosConfigProperties.configServiceInstance(); + this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); } /** * Get the data Id of service rest metadata - * TODO JavaDoc */ private static String getServiceRestMetadataDataId(String serviceName) { return "metadata:rest:" + serviceName + ".json"; } - public void publishServiceRestMetadata(String serviceName, String restMetadataJSON) - throws NacosException { + @Override + public void publishServiceRestMetadata(String serviceName, Set serviceRestMetadata) { String dataId = getServiceRestMetadataDataId(serviceName); - configService.publishConfig(dataId, DEFAULT_GROUP, restMetadataJSON); + String json = writeValueAsString(serviceRestMetadata); + try { + configService.publishConfig(dataId, DEFAULT_GROUP, json); + } catch (NacosException e) { + throw new RuntimeException(e); + } } - public String getServiceRestMetadata(String serviceName) throws NacosException { + @Override + public Set getServiceRestMetadata(String serviceName) { + Set metadata = Collections.emptySet(); String dataId = getServiceRestMetadataDataId(serviceName); - return configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3); + try { + String json = configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3); + metadata = objectMapper.readValue(json, + TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class)); + } catch (Exception e) { + throw new RuntimeException(e); + } + return metadata; + } + + private String writeValueAsString(Object object) { + String content = null; + try { + content = objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + return content; } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java index cbd61416c..0c4d74004 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java @@ -16,13 +16,13 @@ */ package org.springframework.cloud.alibaba.dubbo.openfeign; -import feign.*; -import feign.codec.Decoder; -import feign.codec.Encoder; -import feign.codec.ErrorDecoder; +import feign.Contract; +import feign.Feign; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClientsConfiguration; import org.springframework.context.annotation.Bean; @@ -41,6 +41,12 @@ import java.util.List; @Configuration public class DubboFeignClientsConfiguration { + @Autowired + private Contract contract; + + @Autowired + private DubboServiceMetadataRepository dubboServiceRepository; + @Bean public BeanPostProcessor beanPostProcessor() { return new BeanPostProcessor() { @@ -48,132 +54,12 @@ public class DubboFeignClientsConfiguration { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Feign.Builder) { Feign.Builder builder = (Feign.Builder) bean; - BuilderWrapper wrapper = new BuilderWrapper(builder); - return wrapper; + builder.invocationHandlerFactory(new DubboInvocationHandlerFactory(contract, dubboServiceRepository)); } return bean; } }; } - private static class BuilderWrapper extends Feign.Builder { - - private final Feign.Builder delegate; - - private BuilderWrapper(Feign.Builder delegate) { - this.delegate = delegate; - } - - @Override - public Feign.Builder logLevel(Logger.Level logLevel) { - return delegate.logLevel(logLevel); - } - - @Override - public Feign.Builder contract(Contract contract) { - delegate.contract(contract); - return this; - } - - @Override - public Feign.Builder client(Client client) { - delegate.client(client); - return this; - } - - @Override - public Feign.Builder retryer(Retryer retryer) { - delegate.retryer(retryer); - return this; - } - - @Override - public Feign.Builder logger(Logger logger) { - delegate.logger(logger); - return this; - } - - @Override - public Feign.Builder encoder(Encoder encoder) { - delegate.encoder(encoder); - return this; - } - - @Override - public Feign.Builder decoder(Decoder decoder) { - delegate.decoder(decoder); - return this; - } - - @Override - public Feign.Builder queryMapEncoder(QueryMapEncoder queryMapEncoder) { - delegate.queryMapEncoder(queryMapEncoder); - return this; - } - - @Override - public Feign.Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) { - delegate.mapAndDecode(mapper, decoder); - return this; - } - - @Override - public Feign.Builder decode404() { - delegate.decode404(); - return this; - } - - @Override - public Feign.Builder errorDecoder(ErrorDecoder errorDecoder) { - delegate.errorDecoder(errorDecoder); - return this; - } - - @Override - public Feign.Builder options(Request.Options options) { - delegate.options(options); - return this; - } - - @Override - public Feign.Builder requestInterceptor(RequestInterceptor requestInterceptor) { - delegate.requestInterceptor(requestInterceptor); - return this; - } - - @Override - public Feign.Builder requestInterceptors(Iterable requestInterceptors) { - delegate.requestInterceptors(requestInterceptors); - return this; - } - - @Override - public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) { - delegate.invocationHandlerFactory(invocationHandlerFactory); - return this; - } - - @Override - public Feign.Builder doNotCloseAfterDecode() { - delegate.doNotCloseAfterDecode(); - return this; - } - - @Override - public T target(Class apiType, String url) { - return delegate.target(apiType, url); - } - - @Override - public T target(Target target) { - return delegate.target(target); - } - - @Override - public Feign build() { - return delegate.build(); - } - } - } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java new file mode 100644 index 000000000..622ae340c --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.openfeign; + +import com.alibaba.dubbo.rpc.service.GenericService; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * Dubbo {@link GenericService} for {@link InvocationHandler} + * + * @author Mercy + */ +public class DubboInvocationHandler implements InvocationHandler { + + private final Map genericServicesMap; + + private final Map methodMetadata; + + private final InvocationHandler defaultInvocationHandler; + + public DubboInvocationHandler(Map genericServicesMap, + Map methodMetadata, + InvocationHandler defaultInvocationHandler) { + this.genericServicesMap = genericServicesMap; + this.methodMetadata = methodMetadata; + this.defaultInvocationHandler = defaultInvocationHandler; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + GenericService genericService = genericServicesMap.get(method); + + MethodMetadata methodMetadata = this.methodMetadata.get(method); + + if (genericService == null || methodMetadata == null) { + return defaultInvocationHandler.invoke(proxy, method, args); + } + + String methodName = methodMetadata.getName(); + + String[] parameterTypes = methodMetadata + .getParams() + .stream() + .map(MethodParameterMetadata::getType) + .toArray(String[]::new); + + return genericService.$invoke(methodName, parameterTypes, args); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java new file mode 100644 index 000000000..4fd67f409 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.openfeign; + +import com.alibaba.dubbo.rpc.service.GenericService; +import feign.Contract; +import feign.InvocationHandlerFactory; +import feign.MethodMetadata; +import feign.Target; +import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static feign.Feign.configKey; + +/** + * Dubbo {@link InvocationHandlerFactory} + * + * @author Mercy + */ +public class DubboInvocationHandlerFactory implements InvocationHandlerFactory { + + private final static InvocationHandlerFactory DEFAULT_INVOCATION_HANDLER_FACTORY = + new InvocationHandlerFactory.Default(); + + private final Contract contract; + + private final DubboServiceMetadataRepository dubboServiceRepository; + + public DubboInvocationHandlerFactory(Contract contract, DubboServiceMetadataRepository dubboServiceRepository) { + this.contract = contract; + this.dubboServiceRepository = dubboServiceRepository; + } + + @Override + public InvocationHandler create(Target target, Map dispatch) { + // The target class annotated @FeignClient + Class targetType = target.type(); + // Resolve metadata from current @FeignClient type + Map methodRequestMetadataMap = resolveMethodRequestMetadataMap(targetType, dispatch.keySet()); + // @FeignClient specifies the service name + String serviceName = target.name(); + // Update specified metadata + dubboServiceRepository.updateMetadata(serviceName); + + Map genericServicesMap = new HashMap<>(); + + Map methodMetadataMap = new HashMap<>(); + + methodRequestMetadataMap.forEach((method, requestMetadata) -> { + GenericService genericService = dubboServiceRepository.getGenericService(serviceName, requestMetadata); + org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata = + dubboServiceRepository.getMethodMetadata(serviceName, requestMetadata); + genericServicesMap.put(method, genericService); + methodMetadataMap.put(method, methodMetadata); + }); + + InvocationHandler defaultInvocationHandler = DEFAULT_INVOCATION_HANDLER_FACTORY.create(target, dispatch); + + DubboInvocationHandler invocationHandler = new DubboInvocationHandler(genericServicesMap, methodMetadataMap, + defaultInvocationHandler); + + return invocationHandler; + } + + private Map resolveMethodRequestMetadataMap(Class targetType, Set methods) { + Map requestMetadataMap = resolveRequestMetadataMap(targetType); + return methods.stream().collect(Collectors.toMap(method -> method, method -> + requestMetadataMap.get(configKey(targetType, method)) + )); + } + + private Map resolveRequestMetadataMap(Class targetType) { + return contract.parseAndValidatateMetadata(targetType) + .stream().collect(Collectors.toMap(MethodMetadata::configKey, this::requestMetadata)); + } + + private RequestMetadata requestMetadata(MethodMetadata methodMetadata) { + return new RequestMetadata(methodMetadata.template()); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java index f9d713406..1904cbd5b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -23,7 +23,6 @@ import com.alibaba.dubbo.common.utils.UrlUtils; import com.alibaba.dubbo.registry.NotifyListener; import com.alibaba.dubbo.registry.RegistryFactory; import com.alibaba.dubbo.registry.support.FailbackRegistry; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.DefaultServiceInstance; @@ -48,6 +47,7 @@ import java.util.concurrent.TimeUnit; import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY; import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.PROTOCOL_KEY; import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY; @@ -70,11 +70,13 @@ public class SpringCloudRegistry extends FailbackRegistry { private static final int CATEGORY_INDEX = 0; - private static final int SERVICE_INTERFACE_INDEX = 1; + private static final int PROTOCOL_INDEX = CATEGORY_INDEX + 1; + + private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1; - private static final int SERVICE_VERSION_INDEX = 2; + private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1; - private static final int SERVICE_GROUP_INDEX = 3; + private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1; private static final String WILDCARD = "*"; @@ -167,6 +169,7 @@ public class SpringCloudRegistry extends FailbackRegistry { private static String getServiceName(URL url, String category) { StringBuilder serviceNameBuilder = new StringBuilder(category); + appendIfPresent(serviceNameBuilder, url.getParameter(PROTOCOL_KEY, url.getProtocol())); appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY); @@ -175,6 +178,10 @@ public class SpringCloudRegistry extends FailbackRegistry { private static void appendIfPresent(StringBuilder target, URL url, String parameterName) { String parameterValue = url.getParameter(parameterName); + appendIfPresent(target, parameterValue); + } + + private static void appendIfPresent(StringBuilder target, String parameterValue) { if (StringUtils.hasText(parameterValue)) { target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); } @@ -196,32 +203,38 @@ public class SpringCloudRegistry extends FailbackRegistry { // split service name to segments // (required) segments[0] = category // (required) segments[1] = serviceInterface - // (required) segments[2] = version - // (optional) segments[3] = group - String[] segments = StringUtils.split(serviceName, SERVICE_NAME_SEPARATOR); + // (required) segments[2] = protocol + // (required) segments[3] = version + // (optional) segments[4] = group + String[] segments = getServiceSegments(serviceName); int length = segments.length; - if (length < 3) { // must present 3 segments or more + if (length < 4) { // must present 4 segments or more return false; } - String category = segments[CATEGORY_INDEX]; + String category = getCategory(segments); if (Arrays.binarySearch(categories, category) > -1) { // no match category return false; } - String serviceInterface = segments[SERVICE_INTERFACE_INDEX]; + String protocol = getProtocol(segments); + if (StringUtils.hasText(protocol)) { + return false; + } + + String serviceInterface = getServiceInterface(segments); if (!WILDCARD.equals(targetServiceInterface) && !Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface return false; } - String version = segments[SERVICE_VERSION_INDEX]; + String version = getServiceVersion(segments); if (!WILDCARD.equals(targetVersion) && !Objects.equals(targetVersion, version)) { // no match service version return false; } - String group = length > 3 ? segments[SERVICE_GROUP_INDEX] : null; + String group = getServiceGroup(segments); if (group != null && !WILDCARD.equals(targetGroup) && !Objects.equals(targetGroup, group)) { // no match service group return false; @@ -232,6 +245,30 @@ public class SpringCloudRegistry extends FailbackRegistry { }); } + public static String[] getServiceSegments(String serviceName) { + return StringUtils.delimitedListToStringArray(serviceName, SERVICE_NAME_SEPARATOR); + } + + public static String getCategory(String[] segments) { + return segments[CATEGORY_INDEX]; + } + + public static String getProtocol(String[] segments) { + return segments[PROTOCOL_INDEX]; + } + + public static String getServiceInterface(String[] segments) { + return segments[SERVICE_INTERFACE_INDEX]; + } + + public static String getServiceVersion(String[] segments) { + return segments[SERVICE_VERSION_INDEX]; + } + + public static String getServiceGroup(String[] segments) { + return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null; + } + /** * Get the categories from {@link URL} * @@ -333,7 +370,8 @@ public class SpringCloudRegistry extends FailbackRegistry { @Override public boolean accept(ServiceInstance data) { // TODO check the details of status - return serviceRegistry.getStatus(new DubboRegistration(data)) != null; +// return serviceRegistry.getStatus(new DubboRegistration(data)) != null; + return true; } }); } diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index 1df5be4d8..6a2a1cd84 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -1,6 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ - org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\ - org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestDiscoveryAutoConfiguration + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java index 08de6e2b0..d7b3d13d2 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -16,35 +16,27 @@ */ package org.springframework.cloud.alibaba.dubbo.bootstrap; -import com.alibaba.dubbo.config.ApplicationConfig; -import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.annotation.Reference; -import com.alibaba.dubbo.config.spring.ReferenceBean; -import com.alibaba.dubbo.config.spring.ServiceBean; -import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.alibaba.dubbo.service.EchoService; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - /** * Dubbo Spring Cloud Bootstrap */ @EnableDiscoveryClient @EnableAutoConfiguration @EnableFeignClients -@EnableScheduling @RestController public class DubboSpringCloudBootstrap { @@ -67,38 +59,16 @@ public class DubboSpringCloudBootstrap { String echo(@RequestParam("message") String message); } -// @Bean -// public ApplicationRunner applicationRunner() { -// return arguments -> { -// // Dubbo Service call -// System.out.println(echoService.echo("mercyblitz")); -// // Spring Cloud Open Feign REST Call -// System.out.println(feignEchoService.echo("mercyblitz")); -// }; -// } - - - @Autowired - private ApplicationConfig applicationConfig; - - @Autowired - private List registries; - - @EventListener(ServiceBeanExportedEvent.class) - public void onServiceBeanExportedEvent(ServiceBeanExportedEvent event) { - ServiceBean serviceBean = event.getServiceBean(); - ReferenceBean referenceBean = new ReferenceBean(); - referenceBean.setApplication(applicationConfig); - referenceBean.setRegistries(registries); - referenceBean.setInterface(serviceBean.getInterfaceClass()); - referenceBean.setInterface(serviceBean.getInterface()); - referenceBean.setVersion(serviceBean.getVersion()); - referenceBean.setGroup(serviceBean.getGroup()); - Object object = referenceBean.get(); - System.out.println(object); + @Bean + public ApplicationRunner applicationRunner() { + return arguments -> { + // Dubbo Service call + System.out.println(echoService.echo("mercyblitz")); + // Spring Cloud Open Feign REST Call + System.out.println(feignEchoService.echo("mercyblitz")); + }; } - public static void main(String[] args) { new SpringApplicationBuilder(DubboSpringCloudBootstrap.class) .run(args); From 490e210a81044ad1f9cd97d88f2a630d0bc742ef Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 00:43:08 +0800 Subject: [PATCH 13/50] Bug fix : DubboServiceRegistrationAutoConfiguration does not work in some cases --- spring-cloud-alibaba-dubbo/pom.xml | 6 --- .../DubboMetadataAutoConfiguration.java | 3 -- ...oServiceRegistrationAutoConfiguration.java | 46 ------------------- ...strationApplicationContextInitializer.java | 38 +++++++++++++++ .../main/resources/META-INF/spring.factories | 4 +- 5 files changed, 41 insertions(+), 56 deletions(-) delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml index 2de8ada5c..94467a24a 100644 --- a/spring-cloud-alibaba-dubbo/pom.xml +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -64,12 +64,6 @@ spring-cloud-alibaba-nacos-config - - - - - - org.springframework.cloud spring-cloud-starter-openfeign diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index d5db05ea3..cd4422c71 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -16,7 +16,6 @@ */ package org.springframework.cloud.alibaba.dubbo.autoconfigure; -import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; @@ -25,7 +24,6 @@ import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.Ordered; /** * Spring Boot Auto-Configuration class for Dubbo Metadata @@ -34,7 +32,6 @@ import org.springframework.core.Ordered; */ @Configuration @Import(DubboServiceMetadataRepository.class) -@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) public class DubboMetadataAutoConfiguration { @Bean diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java deleted file mode 100644 index b9bae9815..000000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.autoconfigure; - -import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration; - -import org.springframework.beans.BeansException; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory; -import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.Configuration; - -/** - * {@link DubboServiceRegistrationAutoConfiguration} will register the Dubbo services as the specified Spring cloud - * applications that will not be considered normal ones, but only are used to Dubbo's service discovery even if it is - * based on Spring Cloud Commons abstraction. However, current application will be registered by other - * DiscoveryClientAutoConfiguration. - * - * @author Mercy - */ -@Configuration -@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class, DubboAutoConfiguration.class}) -public class DubboServiceRegistrationAutoConfiguration implements ApplicationContextAware { - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register - SpringCloudRegistryFactory.setApplicationContext(applicationContext); - } -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java new file mode 100644 index 000000000..f1283e914 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.context; + +import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * The Dubbo services will be registered as the specified Spring cloud applications that will not be considered + * normal ones, but only are used to Dubbo's service discovery even if it is based on Spring Cloud Commons abstraction. + * However, current application will be registered by other DiscoveryClientAutoConfiguration. + * + * @author Mercy + */ +public class DubboServiceRegistrationApplicationContextInitializer implements + ApplicationContextInitializer { + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register + SpringCloudRegistryFactory.setApplicationContext(applicationContext); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index 6a2a1cd84..c2627f860 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -1,5 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ - org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration + +org.springframework.context.ApplicationContextInitializer=\ + org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer From 7fae608df4b57e88e0e8bc987d9854abb99d74d6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 10:02:13 +0800 Subject: [PATCH 14/50] Polish spring-cloud-incubator/spring-cloud-alibaba#263 --- .../DubboRestMetadataRegistrationAutoConfiguration.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index 458b1ca1f..7c7aa9fde 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -46,10 +46,7 @@ import java.util.Set; MetadataResolver.class, MetadataConfigService.class }) -@AutoConfigureAfter(value = { - DubboMetadataAutoConfiguration.class, - DubboServiceRegistrationAutoConfiguration.class -}) +@AutoConfigureAfter(value = {DubboMetadataAutoConfiguration.class}) @Configuration public class DubboRestMetadataRegistrationAutoConfiguration { From 523f039c95edf96da0dc0acd0a21de5f95759c8c Mon Sep 17 00:00:00 2001 From: flystar32 Date: Tue, 22 Jan 2019 11:50:38 +0800 Subject: [PATCH 15/50] add test case for ans module --- spring-cloud-alicloud-ans/pom.xml | 12 ++ .../alicloud/ans/AnsAutoConfiguration.java | 3 + .../ans/registry/AnsRegistration.java | 6 +- .../alicloud/ans/AnsDiscoveryClientTests.java | 116 +++++++++++++ ...ceRegistrationIpNetworkInterfaceTests.java | 147 ++++++++++++++++ .../AnsAutoServiceRegistrationIpTests.java | 81 +++++++++ ...erviceRegistrationManagementPortTests.java | 87 ++++++++++ .../AnsAutoServiceRegistrationPortTests.java | 81 +++++++++ .../AnsAutoServiceRegistrationTests.java | 158 ++++++++++++++++++ .../AnsRibbonClientConfigurationTests.java | 86 ++++++++++ .../ans/ribbon/AnsServerListTests.java | 148 ++++++++++++++++ .../ans/ribbon/AnsServiceListTests.java | 76 +++++++++ .../cloud/alicloud/ans/test/AnsMockTest.java | 45 +++++ 13 files changed, 1043 insertions(+), 3 deletions(-) create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationManagementPortTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationPortTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfigurationTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerListTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServiceListTests.java create mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/test/AnsMockTest.java diff --git a/spring-cloud-alicloud-ans/pom.xml b/spring-cloud-alicloud-ans/pom.xml index d1fdf2c93..3aa33c0b8 100644 --- a/spring-cloud-alicloud-ans/pom.xml +++ b/spring-cloud-alicloud-ans/pom.xml @@ -103,6 +103,18 @@ spring-cloud-test-support test + + org.powermock + powermock-module-junit4 + 2.0.0 + test + + + org.powermock + powermock-api-mockito2 + 2.0.0 + test + diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java index d563632ea..8d0f0fe64 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.cloud.alicloud.ans; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -27,6 +28,7 @@ import org.springframework.cloud.alicloud.ans.registry.AnsRegistration; import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry; import org.springframework.cloud.alicloud.context.ans.AnsProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -44,6 +46,7 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnAnsEnabled @AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class, AnsDiscoveryClientAutoConfiguration.class }) +@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class) public class AnsAutoConfiguration { @Bean diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java index 39a98b736..79be8e853 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/registry/AnsRegistration.java @@ -35,9 +35,9 @@ import org.springframework.util.StringUtils; */ public class AnsRegistration implements Registration, ServiceInstance { - private static final String MANAGEMENT_PORT = "management.port"; - private static final String MANAGEMENT_CONTEXT_PATH = "management.context-path"; - private static final String MANAGEMENT_ADDRESS = "management.address"; + static final String MANAGEMENT_PORT = "management.port"; + static final String MANAGEMENT_CONTEXT_PATH = "management.context-path"; + static final String MANAGEMENT_ADDRESS = "management.address"; private AnsProperties ansProperties; private ApplicationContext context; diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientTests.java new file mode 100644 index 000000000..3e02bc3dc --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/AnsDiscoveryClientTests.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.springframework.cloud.alicloud.ans.test.AnsMockTest.hostInstance; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.cloud.client.ServiceInstance; + +import com.alibaba.ans.core.NamingService; +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; + +/** + * @author xiaojing + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(NamingService.class) +public class AnsDiscoveryClientTests { + + private String host = "123.123.123.123"; + private int port = 8888; + private String serviceName = "test-service"; + + @Test + public void testGetServers() throws Exception { + + ArrayList hosts = new ArrayList<>(); + + HashMap map = new HashMap<>(); + map.put("test-key", "test-value"); + map.put("secure", "true"); + + hosts.add(hostInstance(serviceName, false, host, port, map)); + + PowerMockito.mockStatic(NamingService.class); + when(NamingService.getHosts(eq(serviceName))).thenReturn(hosts); + + AnsDiscoveryClient discoveryClient = new AnsDiscoveryClient(); + + List serviceInstances = discoveryClient + .getInstances(serviceName); + + assertThat(serviceInstances.size()).isEqualTo(1); + + ServiceInstance serviceInstance = serviceInstances.get(0); + + assertThat(serviceInstance.getServiceId()).isEqualTo(serviceName); + assertThat(serviceInstance.getHost()).isEqualTo(host); + assertThat(serviceInstance.getPort()).isEqualTo(port); + // assertThat(serviceInstance.isSecure()).isEqualTo(true); + // ans doesn't support metadata + assertThat(serviceInstance.getUri().toString()) + .isEqualTo(getUri(serviceInstance)); + // assertThat(serviceInstance.getMetadata().get("test-key")).isEqualTo("test-value"); + // ans doesn't support metadata + + } + + @Test + public void testGetAllService() throws Exception { + + Set subscribedServices = new HashSet<>(); + + subscribedServices.add(serviceName + "1"); + subscribedServices.add(serviceName + "2"); + subscribedServices.add(serviceName + "3"); + + PowerMockito.mockStatic(NamingService.class); + when(NamingService.getDomsSubscribed()).thenReturn(subscribedServices); + + AnsDiscoveryClient discoveryClient = new AnsDiscoveryClient(); + List services = discoveryClient.getServices(); + + assertThat(services.size()).isEqualTo(3); + assertThat(services.contains(serviceName + "1")); + assertThat(services.contains(serviceName + "2")); + assertThat(services.contains(serviceName + "3")); + + } + + private String getUri(ServiceInstance instance) { + + if (instance.isSecure()) { + return "https://" + host + ":" + port; + } + + return "http://" + host + ":" + port; + } +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java new file mode 100644 index 000000000..0259c27b9 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.registry; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alicloud.ans.AnsAutoConfiguration; +import org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author xiaojing + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AnsAutoServiceRegistrationIpNetworkInterfaceTests.TestConfig.class, properties = { + "spring.application.name=myTestService1", + "spring.cloud.alicloud.ans.server-list=127.0.0.1", + "spring.cloud.alicloud.ans.server-port=8080" }, webEnvironment = RANDOM_PORT) +public class AnsAutoServiceRegistrationIpNetworkInterfaceTests { + + @Autowired + private AnsRegistration registration; + + @Autowired + private AnsAutoServiceRegistration ansAutoServiceRegistration; + + @Autowired + private AnsProperties properties; + + @Autowired + private InetUtils inetUtils; + + @Test + public void contextLoads() throws Exception { + + assertNotNull("AnsRegistration was not created", registration); + assertNotNull("AnsProperties was not created", properties); + assertNotNull("AnsAutoServiceRegistration was not created", + ansAutoServiceRegistration); + + checkoutAnsDiscoveryServiceIP(); + + } + + private void checkoutAnsDiscoveryServiceIP() { + assertEquals("AnsProperties service IP was wrong", + getIPFromNetworkInterface(TestConfig.netWorkInterfaceName), + registration.getHost()); + + } + + private String getIPFromNetworkInterface(String networkInterface) { + + if (!TestConfig.hasValidNetworkInterface) { + return inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + } + + try { + NetworkInterface netInterface = NetworkInterface.getByName(networkInterface); + + Enumeration inetAddress = netInterface.getInetAddresses(); + while (inetAddress.hasMoreElements()) { + InetAddress currentAddress = inetAddress.nextElement(); + if (currentAddress instanceof Inet4Address + && !currentAddress.isLoopbackAddress()) { + return currentAddress.getHostAddress(); + } + } + return networkInterface; + } + catch (Exception e) { + return networkInterface; + } + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + AnsDiscoveryClientAutoConfiguration.class, AnsAutoConfiguration.class }) + public static class TestConfig { + + static boolean hasValidNetworkInterface = false; + static String netWorkInterfaceName; + + static { + + try { + Enumeration enumeration = NetworkInterface + .getNetworkInterfaces(); + while (enumeration.hasMoreElements() && !hasValidNetworkInterface) { + NetworkInterface networkInterface = enumeration.nextElement(); + Enumeration inetAddress = networkInterface + .getInetAddresses(); + while (inetAddress.hasMoreElements()) { + InetAddress currentAddress = inetAddress.nextElement(); + if (currentAddress instanceof Inet4Address + && !currentAddress.isLoopbackAddress()) { + hasValidNetworkInterface = true; + netWorkInterfaceName = networkInterface.getName(); + System.setProperty( + "spring.cloud.alicloud.ans.client-interface-ame", + networkInterface.getName()); + break; + } + } + } + + } + catch (Exception e) { + + } + } + } + +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpTests.java new file mode 100644 index 000000000..53d7b5c2e --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpTests.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.registry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alicloud.ans.AnsAutoConfiguration; +import org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author xiaojing + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AnsAutoServiceRegistrationIpTests.TestConfig.class, properties = { + "spring.application.name=myTestService1", + "spring.cloud.alicloud.ans.server-list=127.0.0.1", + "spring.cloud.alicloud.ans.server-port=8080", + "spring.cloud.alicloud.ans.client-ip=123.123.123.123" }, webEnvironment = RANDOM_PORT) +public class AnsAutoServiceRegistrationIpTests { + + @Autowired + private AnsRegistration registration; + + @Autowired + private AnsAutoServiceRegistration ansAutoServiceRegistration; + + @Autowired + private AnsProperties properties; + + @Test + public void contextLoads() throws Exception { + + assertNotNull("AnsRegistration was not created", registration); + assertNotNull("AnsProperties was not created", properties); + assertNotNull("AnsAutoServiceRegistration was not created", + ansAutoServiceRegistration); + + checkoutAnsDiscoveryServiceIP(); + + } + + private void checkoutAnsDiscoveryServiceIP() { + assertEquals("AnsProperties service IP was wrong", "123.123.123.123", + registration.getHost()); + + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + AnsDiscoveryClientAutoConfiguration.class, AnsAutoConfiguration.class }) + public static class TestConfig { + } +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationManagementPortTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationManagementPortTests.java new file mode 100644 index 000000000..a73f25c28 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationManagementPortTests.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.registry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.cloud.alicloud.ans.registry.AnsRegistration.MANAGEMENT_CONTEXT_PATH; +import static org.springframework.cloud.alicloud.ans.registry.AnsRegistration.MANAGEMENT_PORT; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alicloud.ans.AnsAutoConfiguration; +import org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author xiaojing + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AnsAutoServiceRegistrationManagementPortTests.TestConfig.class, properties = { + "spring.application.name=myTestService1", "management.server.port=8888", + "management.server.servlet.context-path=/test-context-path", + "spring.cloud.alicloud.ans.server-list=127.0.0.1", + "spring.cloud.alicloud.ans.server-port=8080" }, webEnvironment = RANDOM_PORT) +public class AnsAutoServiceRegistrationManagementPortTests { + + @Autowired + private AnsRegistration registration; + + @Autowired + private AnsAutoServiceRegistration ansAutoServiceRegistration; + + @Autowired + private AnsProperties properties; + + @Test + public void contextLoads() throws Exception { + + assertNotNull("AnsRegistration was not created", registration); + assertNotNull("AnsProperties was not created", properties); + assertNotNull("AnsAutoServiceRegistration was not created", + ansAutoServiceRegistration); + + checkoutNacosDiscoveryManagementData(); + + } + + private void checkoutNacosDiscoveryManagementData() { + assertEquals("AnsProperties management port was wrong", "8888", + properties.getClientMetadata().get(MANAGEMENT_PORT)); + + assertEquals("AnsProperties management context path was wrong", + "/test-context-path", + properties.getClientMetadata().get(MANAGEMENT_CONTEXT_PATH)); + + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + AnsDiscoveryClientAutoConfiguration.class, AnsAutoConfiguration.class }) + public static class TestConfig { + } +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationPortTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationPortTests.java new file mode 100644 index 000000000..20e03eb46 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationPortTests.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.registry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alicloud.ans.AnsAutoConfiguration; +import org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author xiaojing + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AnsAutoServiceRegistrationPortTests.TestConfig.class, properties = { + "spring.application.name=myTestService1", + "spring.cloud.alicloud.ans.server-list=127.0.0.1", + "spring.cloud.alicloud.ans.server-port=8080", + "spring.cloud.alicloud.ans.client-port=8888" }, webEnvironment = RANDOM_PORT) +public class AnsAutoServiceRegistrationPortTests { + + @Autowired + private AnsRegistration registration; + + @Autowired + private AnsAutoServiceRegistration ansAutoServiceRegistration; + + @Autowired + private AnsProperties properties; + + @Test + public void contextLoads() throws Exception { + + assertNotNull("AnsRegistration was not created", registration); + assertNotNull("AnsDiscoveryProperties was not created", properties); + assertNotNull("AnsAutoServiceRegistration was not created", + ansAutoServiceRegistration); + + checkoutAnsDiscoveryServicePort(); + + } + + private void checkoutAnsDiscoveryServicePort() { + assertEquals("AnsDiscoveryProperties service Port was wrong", 8888, + registration.getPort()); + + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + AnsDiscoveryClientAutoConfiguration.class, AnsAutoConfiguration.class }) + public static class TestConfig { + } +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationTests.java new file mode 100644 index 000000000..933814086 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationTests.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.registry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.alibaba.ans.core.NamingService; +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.alicloud.ans.AnsAutoConfiguration; +import org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration; +import org.springframework.cloud.alicloud.ans.endpoint.AnsEndpoint; +import org.springframework.cloud.alicloud.context.ans.AnsProperties; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author xiaojing + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AnsAutoServiceRegistrationTests.TestConfig.class, properties = { + "spring.application.name=myTestService1", + "spring.cloud.alicloud.ans.server-list=127.0.0.1", + "spring.cloud.alicloud.ans.server-port=8080", + "spring.cloud.alicloud.ans.endpoint=test-endpoint" }, webEnvironment = RANDOM_PORT) +public class AnsAutoServiceRegistrationTests { + + @Autowired + private AnsRegistration registration; + + @Autowired + private AnsAutoServiceRegistration ansAutoServiceRegistration; + + @LocalServerPort + private int port; + + @Autowired + private AnsProperties properties; + + @Autowired + private InetUtils inetUtils; + + @Test + public void contextLoads() throws Exception { + + assertNotNull("AnsRegistration was not created", registration); + assertNotNull("AnsProperties was not created", properties); + assertNotNull("AnsAutoServiceRegistration was not created", + ansAutoServiceRegistration); + + checkoutAnsDiscoveryServerList(); + checkoutAnsDiscoveryServerPort(); + + checkoutAnsDiscoveryServiceName(); + checkoutAnsDiscoveryServiceIP(); + checkoutAnsDiscoveryServicePort(); + + checkAutoRegister(); + + checkoutEndpoint(); + + } + + private void checkAutoRegister() { + assertTrue("Ans Auto Registration was not start", + ansAutoServiceRegistration.isRunning()); + } + + private void checkoutAnsDiscoveryServerList() { + assertEquals("AnsDiscoveryProperties server list was wrong", "127.0.0.1", + properties.getServerList()); + + } + + private void checkoutAnsDiscoveryServerPort() { + assertEquals("AnsDiscoveryProperties server port was wrong", "8080", + properties.getServerPort()); + + } + + private void checkoutAnsDiscoveryServiceName() { + assertEquals("AnsDiscoveryProperties service name was wrong", "myTestService1", + properties.getClientDomains()); + + } + + private void checkoutAnsDiscoveryServiceIP() { + assertEquals("AnsDiscoveryProperties service IP was wrong", + inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(), + registration.getHost()); + + } + + private void checkoutAnsDiscoveryServicePort() { + assertEquals("AnsDiscoveryProperties service Port was wrong", port, + registration.getPort()); + + } + + private void checkoutEndpoint() throws Exception { + AnsEndpoint ansEndpoint = new AnsEndpoint(properties); + Map map = ansEndpoint.invoke(); + assertEquals(map.get("ansProperties"), properties); + + Map subscribes = new HashMap<>(); + Set subscribeServices = NamingService.getDomsSubscribed(); + for (String service : subscribeServices) { + try { + List hosts = NamingService.getHosts(service); + subscribes.put(service, hosts); + } + catch (Exception ignoreException) { + + } + } + + assertEquals(map.get("subscribes"), subscribes); + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + AnsDiscoveryClientAutoConfiguration.class, AnsAutoConfiguration.class }) + public static class TestConfig { + } +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfigurationTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfigurationTests.java new file mode 100644 index 000000000..beb825c71 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsRibbonClientConfigurationTests.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.ribbon; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.alicloud.ans.AnsAutoConfiguration; +import org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import com.netflix.client.config.DefaultClientConfigImpl; +import com.netflix.client.config.IClientConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author xiaojing + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = AnsRibbonClientConfigurationTests.TestConfig.class, properties = { + "spring.application.name=myTestService1", + "spring.cloud.alicloud.ans.server-list=127.0.0.1", + "spring.cloud.alicloud.ans.server-port=8080", + "spring.cloud.alicloud.ans.endpoint=test-endpoint" }, webEnvironment = RANDOM_PORT) +public class AnsRibbonClientConfigurationTests { + + @Autowired + private AnsServerList serverList; + + @Test + public void contextLoads() throws Exception { + assertThat(serverList.getDom()).isEqualTo("myapp"); + } + + @Configuration + public static class AnsRibbonTestConfiguration { + + @Bean + IClientConfig iClientConfig() { + DefaultClientConfigImpl config = new DefaultClientConfigImpl(); + config.setClientName("myapp"); + return config; + } + + @Bean + @LoadBalanced + RestTemplate restTemplate() { + return new RestTemplate(); + } + + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + AnsDiscoveryClientAutoConfiguration.class, AnsAutoConfiguration.class, + AnsRibbonTestConfiguration.class, RibbonAnsAutoConfiguration.class, + AnsRibbonClientConfiguration.class }) + public static class TestConfig { + } + +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerListTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerListTests.java new file mode 100644 index 000000000..815fa89da --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServerListTests.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.ribbon; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.cloud.alicloud.ans.test.AnsMockTest.hostInstance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.alibaba.ans.core.NamingService; +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; + +import com.netflix.client.config.IClientConfig; + +/** + * @author xiaojing + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ NamingService.class, AnsServer.class }) +public class AnsServerListTests { + + @Test + @SuppressWarnings("unchecked") + public void testEmptyInstancesReturnsEmptyList() throws Exception { + + PowerMockito.mockStatic(NamingService.class); + when(NamingService.getHosts(anyString())).thenReturn(Collections.EMPTY_LIST); + + IClientConfig clientConfig = mock(IClientConfig.class); + when(clientConfig.getClientName()).thenReturn("test-service"); + AnsServerList serverList = new AnsServerList("test-service"); + serverList.initWithNiwsConfig(clientConfig); + List servers = serverList.getInitialListOfServers(); + assertThat(servers).isEmpty(); + } + + @Test + @SuppressWarnings("unchecked") + public void testGetServers() throws Exception { + + ArrayList hosts = new ArrayList<>(); + hosts.add(hostInstance("test-service", true, Collections.emptyMap())); + + PowerMockito.mockStatic(NamingService.class); + when(NamingService.getHosts(anyString())).thenReturn(hosts); + PowerMockito.stub(PowerMockito.method(AnsServer.class, "isAlive", long.class)) + .toReturn(true); + + IClientConfig clientConfig = mock(IClientConfig.class); + when(clientConfig.getClientName()).thenReturn("test-service"); + AnsServerList serverList = new AnsServerList("test-service"); + serverList.initWithNiwsConfig(clientConfig); + List servers = serverList.getInitialListOfServers(); + assertThat(servers).hasSize(1); + + servers = serverList.getUpdatedListOfServers(); + assertThat(servers).hasSize(1); + } + + @Test + @SuppressWarnings("unchecked") + public void testGetServersWithInstanceStatus() throws Exception { + ArrayList hosts = new ArrayList<>(); + + HashMap map1 = new HashMap<>(); + map1.put("instanceNum", "1"); + HashMap map2 = new HashMap<>(); + map2.put("instanceNum", "2"); + hosts.add(hostInstance("test-service", false, map1)); + hosts.add(hostInstance("test-service", true, map2)); + + PowerMockito.mockStatic(NamingService.class); + when(NamingService.getHosts(eq("test-service"))).thenReturn( + hosts.stream().filter(Host::isValid).collect(Collectors.toList())); + + PowerMockito.stub(PowerMockito.method(AnsServer.class, "isAlive", long.class)) + .toReturn(true); + + IClientConfig clientConfig = mock(IClientConfig.class); + when(clientConfig.getClientName()).thenReturn("test-service"); + AnsServerList serverList = new AnsServerList("test-service"); + serverList.initWithNiwsConfig(clientConfig); + List servers = serverList.getInitialListOfServers(); + assertThat(servers).hasSize(1); + + AnsServer ansServer = servers.get(0); + Host host = ansServer.getHealthService(); + + assertThat(ansServer.getMetaInfo().getInstanceId()).isEqualTo( + host.getIp() + ":" + host.getHostname() + ":" + host.getPort()); + assertThat(ansServer.getHealthService().isValid()).isEqualTo(true); + assertThat(ansServer.getHealthService().getHostname()).isEqualTo("test-service"); + + } + + @Test + public void testUpdateServers() throws Exception { + ArrayList hosts = new ArrayList<>(); + + HashMap map = new HashMap<>(); + map.put("instanceNum", "1"); + hosts.add(hostInstance("test-service", true, map)); + + PowerMockito.mockStatic(NamingService.class); + when(NamingService.getHosts(eq("test-service"))).thenReturn( + hosts.stream().filter(Host::isValid).collect(Collectors.toList())); + PowerMockito.stub(PowerMockito.method(AnsServer.class, "isAlive", long.class)) + .toReturn(true); + + IClientConfig clientConfig = mock(IClientConfig.class); + when(clientConfig.getClientName()).thenReturn("test-service"); + AnsServerList serverList = new AnsServerList("test-service"); + serverList.initWithNiwsConfig(clientConfig); + + List servers = serverList.getUpdatedListOfServers(); + assertThat(servers).hasSize(1); + + assertThat(servers.get(0).getHealthService().isValid()).isEqualTo(true); + } +} \ No newline at end of file diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServiceListTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServiceListTests.java new file mode 100644 index 000000000..3e3d59e42 --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/ribbon/AnsServiceListTests.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.ribbon; + +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; +import com.netflix.loadbalancer.Server; + +/** + * @author xiaolongzuo + */ +public class AnsServiceListTests { + + static final String IP_ADDR = "10.0.0.2"; + + static final int PORT = 8080; + + @Test + public void testAnsServer() { + AnsServerList serverList = getAnsServerList(); + List servers = serverList.getInitialListOfServers(); + assertNotNull("servers was null", servers); + assertEquals("servers was not size 1", 1, servers.size()); + Server des = assertAnsServer(servers); + assertEquals("hostPort was wrong", IP_ADDR + ":" + PORT, des.getHostPort()); + } + + protected Server assertAnsServer(List servers) { + Server actualServer = servers.get(0); + assertTrue("server was not a DomainExtractingServer", + actualServer instanceof AnsServer); + AnsServer des = AnsServer.class.cast(actualServer); + assertNotNull("host is null", des.getHealthService()); + assertEquals("unit was wrong", "DEFAULT", des.getHealthService().getUnit()); + return des; + } + + protected AnsServerList getAnsServerList() { + Host host = mock(Host.class); + given(host.getIp()).willReturn(IP_ADDR); + given(host.getDoubleWeight()).willReturn(1.0); + given(host.getPort()).willReturn(PORT); + given(host.getWeight()).willReturn(1); + given(host.getUnit()).willReturn("DEFAULT"); + + AnsServer server = new AnsServer(host, "testDom"); + @SuppressWarnings("unchecked") + AnsServerList originalServerList = mock(AnsServerList.class); + given(originalServerList.getInitialListOfServers()) + .willReturn(Arrays.asList(server)); + return originalServerList; + } + +} diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/test/AnsMockTest.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/test/AnsMockTest.java new file mode 100644 index 000000000..795f2b49a --- /dev/null +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/test/AnsMockTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.ans.test; + +import java.util.Map; + +import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; + +/** + * @author xiaojing + */ +public class AnsMockTest { + + public static Host hostInstance(String serviceName, boolean valid, + Map metadata) { + Host host = new Host(); + host.setHostname(serviceName); + host.setValid(valid); + return host; + } + + public static Host hostInstance(String serviceName, boolean valid, String ip, + int port, Map metadata) { + Host host = new Host(); + host.setIp(ip); + host.setPort(port); + host.setValid(valid); + host.setHostname(serviceName); + return host; + } +} From 962abbb71210e7b81e1f1aa3b2361ed92a7e5e4d Mon Sep 17 00:00:00 2001 From: flystar32 Date: Tue, 22 Jan 2019 14:02:43 +0800 Subject: [PATCH 16/50] delete unused file --- .../ans/ribbon/AnsServiceListTests.java | 78 ------------------- 1 file changed, 78 deletions(-) delete mode 100644 spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alibaba/ans/ribbon/AnsServiceListTests.java diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alibaba/ans/ribbon/AnsServiceListTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alibaba/ans/ribbon/AnsServiceListTests.java deleted file mode 100644 index 5cb38532a..000000000 --- a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alibaba/ans/ribbon/AnsServiceListTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.alibaba.ans.ribbon; - -import static org.junit.Assert.*; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import java.util.Arrays; -import java.util.List; - -import org.junit.Test; -import org.springframework.cloud.alicloud.ans.ribbon.AnsServer; -import org.springframework.cloud.alicloud.ans.ribbon.AnsServerList; - -import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host; -import com.netflix.loadbalancer.Server; - -/** - * @author xiaolongzuo - */ -public class AnsServiceListTests { - - static final String IP_ADDR = "10.0.0.2"; - - static final int PORT = 8080; - - @Test - public void testAnsServer() { - AnsServerList serverList = getAnsServerList(); - List servers = serverList.getInitialListOfServers(); - assertNotNull("servers was null", servers); - assertEquals("servers was not size 1", 1, servers.size()); - Server des = assertAnsServer(servers); - assertEquals("hostPort was wrong", IP_ADDR + ":" + PORT, des.getHostPort()); - } - - protected Server assertAnsServer(List servers) { - Server actualServer = servers.get(0); - assertTrue("server was not a DomainExtractingServer", - actualServer instanceof AnsServer); - AnsServer des = AnsServer.class.cast(actualServer); - assertNotNull("host is null", des.getHealthService()); - assertEquals("unit was wrong", "DEFAULT", des.getHealthService().getUnit()); - return des; - } - - protected AnsServerList getAnsServerList() { - Host host = mock(Host.class); - given(host.getIp()).willReturn(IP_ADDR); - given(host.getDoubleWeight()).willReturn(1.0); - given(host.getPort()).willReturn(PORT); - given(host.getWeight()).willReturn(1); - given(host.getUnit()).willReturn("DEFAULT"); - - AnsServer server = new AnsServer(host, "testDom"); - @SuppressWarnings("unchecked") - AnsServerList originalServerList = mock(AnsServerList.class); - given(originalServerList.getInitialListOfServers()) - .willReturn(Arrays.asList(server)); - return originalServerList; - } - -} From 054e95dd450256baec8bffb1389dd8f208ab3ee2 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 14:45:39 +0800 Subject: [PATCH 17/50] Revert nacos-discovery-consumer-example --- .../nacos-discovery-consumer-example/pom.xml | 24 ++--------- .../demos/SpringCloudRestClientBootstrap.java | 42 ------------------- .../src/main/resources/application.properties | 7 +++- 3 files changed, 10 insertions(+), 63 deletions(-) delete mode 100644 spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml index 21713a4a8..6a3af32b3 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml @@ -16,31 +16,15 @@ - org.springframework.boot spring-boot-starter-web - org.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba - dubbo-registry-nacos - 0.0.2 - - - - - org.springframework.cloud - spring-cloud-alibaba-dubbo - ${project.version} - - org.springframework.boot spring-boot-starter-actuator @@ -56,10 +40,10 @@ spring-cloud-starter-openfeign - - - - + + org.springframework.cloud + spring-cloud-starter-alibaba-sentinel + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java deleted file mode 100644 index b5b728488..000000000 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/demos/SpringCloudRestClientBootstrap.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.springframework.cloud.alibaba.cloud.examples.demos; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.context.annotation.Lazy; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@EnableAutoConfiguration // 激活自动装配 -@EnableDiscoveryClient // 激活服务注册和发现 -@EnableFeignClients // 激活 @FeignClients注册 -public class SpringCloudRestClientBootstrap { - - @FeignClient("spring-cloud-alibaba-dubbo") - public interface FeignEchoService { - - @GetMapping(value = "/echo") - String echo(@RequestParam("message") String message); - } - - - @RestController - public static class EchoServiceController { - - @Autowired - private FeignEchoService feignEchoService; - - @GetMapping("/call/echo") - public String echo(@RequestParam("message") String message) { - return feignEchoService.echo(message); - } - } - - public static void main(String[] args) { - SpringApplication.run(SpringCloudRestClientBootstrap.class, args); - } -} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties index 1e6c2f5e5..fbc9736eb 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties @@ -3,5 +3,10 @@ server.port=18083 management.endpoints.web.exposure.include=* spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 -dubbo.registry.address= spring-cloud://nacos +feign.sentinel.enabled=true +spring.cloud.sentinel.transport.dashboard=localhost:8080 +spring.cloud.sentinel.eager=true + +spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json +spring.cloud.sentinel.datasource.ds1.file.data-type=json \ No newline at end of file From 744e33229a226ee86731b9c29b63c89282df0d68 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 15:16:21 +0800 Subject: [PATCH 18/50] Merge remote-tracking branch 'upstream/master' # Conflicts: # pom.xml # spring-cloud-alibaba-dependencies/pom.xml # spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml --- pom.xml | 47 ++---- spring-cloud-alibaba-dependencies/pom.xml | 4 +- .../src/main/asciidoc-zh/nacos-discovery.adoc | 4 +- .../src/main/asciidoc/nacos-discovery.adoc | 4 +- .../cloud/examples/EchoController.java | 40 ----- .../alibaba/cloud/examples/EchoService.java | 33 ---- .../cloud/examples/ProviderApplication.java | 157 +++--------------- .../src/main/resources/application.properties | 10 +- 8 files changed, 44 insertions(+), 255 deletions(-) delete mode 100644 spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java delete mode 100644 spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java diff --git a/pom.xml b/pom.xml index 6e4ff453c..37b31ae45 100644 --- a/pom.xml +++ b/pom.xml @@ -119,6 +119,14 @@ import + + org.springframework.cloud + spring-cloud-alibaba-dependencies + ${project.version} + pom + import + + org.springframework.cloud spring-cloud-commons-dependencies @@ -157,7 +165,6 @@ pom import - net.sourceforge.cobertura cobertura-runtime @@ -165,15 +172,6 @@ provided pom - - - org.springframework.cloud - spring-cloud-alibaba-dependencies - ${project.version} - pom - import - - @@ -211,7 +209,14 @@ org.codehaus.mojo cobertura-maven-plugin - 2.7 + ${cobertura-maven-plugin.version} + + + org.ow2.asm + asm + 5.0.3 + + true @@ -220,26 +225,6 @@ - - - org/springframework/cloud/alibaba/cloud/dependencies/**.*.class - org/springframework/cloud/alibaba/cloud/docs/**.*.class - org/springframework/cloud/alibaba/cloud/examples/**.*.class - org/springframework/cloud/alibaba/cloud/test/**.*.class - org/springframework/cloud/start/alibaba/**.*.class - org/springframework/cloud/start/alicloud/**.*.class - org/springframework/cloud/alibaba/nacos/src/test/**.*.class - org/springframework/cloud/alibaba/nacos/config/server/src/test/**.*.class - org/springframework/cloud/alibaba/sentinel/src/test/**.*.class - org/springframework/cloud/alibaba/sentinel/datasource/src/test/**.*.class - org/springframework/cloud/alicloud/acm/src/test/**.*.class - org/springframework/cloud/alicloud/ans/src/test/**.*.class - org/springframework/cloud/alicloud/context/src/test/**.*.class - org/springframework/cloud/alicloud/oss/src/test/**.*.class - org/springframework/cloud/alicloud/scx/src/test/**.*.class - org/springframework/cloud/stream/binder/rocketmq/src/test/**.*.class - - diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index 8e0d43052..51b95c492 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -17,14 +17,14 @@ Spring Cloud Alibaba Dependencies - 1.4.0 + 1.4.1 3.1.0 0.6.2 0.6.1 1.0.8 1.0.1 4.0.1 - 1.0.4 + 1.0.5 2.16.0 4.3.1 2.1.6 diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc index 324741e24..bd88310af 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc @@ -260,8 +260,8 @@ public class NacosConsumerApp { @GetMapping("/echo/app-name") public String echoAppName(){ //使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问 - ServiceInstance delegate = loadBalancerClient.choose("nacos-provider"); - String url = String.format("http://%s:%s/echo/%s",delegate.getHost(),delegate.getPort(),appName); + ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider"); + String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName); System.out.println("request url:"+url); return restTemplate.getForObject(url,String.class); } diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc index 03f1c3f4e..44f2222f5 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc @@ -260,8 +260,8 @@ public class NacosConsumerApp { @GetMapping("/echo/app-name") public String echoAppName(){ //Access through the combination of LoadBalanceClient and RestTemolate - ServiceInstance delegate = loadBalancerClient.choose("nacos-provider"); - String url = String.format("http://%s:%s/echo/%s",delegate.getHost(),delegate.getPort(),appName); + ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider"); + String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName); System.out.println("request url:" +url); return restTemplate.getForObject(url,String.class); } diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java deleted file mode 100644 index 1a571b264..000000000 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoController.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.cloud.examples; - -import com.alibaba.dubbo.config.annotation.Service; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@Service(version = "1.0.0") -public class EchoController implements EchoService { - @Override - @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) - public String echo(@PathVariable String string) { - return "hello Nacos Discovery " + string; - } - - @Override - @RequestMapping(value = "/divide", method = RequestMethod.GET) - public String divide(@RequestParam Integer a, @RequestParam Integer b) { - return String.valueOf(a / b); - } -} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java deleted file mode 100644 index b60affbc8..000000000 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/EchoService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.cloud.examples; - -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -/** - * TODO - */ -public interface EchoService { - @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) - String echo(@PathVariable String string); - - @RequestMapping(value = "/divide", method = RequestMethod.GET) - String divide(@RequestParam Integer a, @RequestParam Integer b); -} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java index 2519096a5..843f5cbe0 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java @@ -1,30 +1,13 @@ package org.springframework.cloud.alibaba.cloud.examples; -import com.alibaba.dubbo.config.spring.ServiceBean; -import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.context.event.EventListener; - -import java.beans.BeanInfo; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.URL; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; - -import static org.springframework.util.ClassUtils.isPrimitiveOrWrapper; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; /** * @author xiaojing @@ -33,118 +16,20 @@ import static org.springframework.util.ClassUtils.isPrimitiveOrWrapper; @EnableDiscoveryClient public class ProviderApplication { - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - } - - @Autowired - private ConfigurableListableBeanFactory beanFactory; - - @Autowired - private ObjectMapper objectMapper; - - @EventListener(ServiceBeanExportedEvent.class) - public void onServiceBeanExportedEvent(ServiceBeanExportedEvent event) { - ServiceBean serviceBean = event.getServiceBean(); - } - - @EventListener(InstancePreRegisteredEvent.class) - public void onInstancePreRegisteredEvent(InstancePreRegisteredEvent event) throws JsonProcessingException { - Registration registration = event.getRegistration(); - Map serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class); - Map metaData = registration.getMetadata(); - String serviceBeansJson = objectMapper.writeValueAsString(services(serviceBeansMap)); - metaData.put("serviceBeans", serviceBeansJson); - } - - public Map> services(Map serviceBeansMap) { - - Map> servicesMetadata = new LinkedHashMap<>(serviceBeansMap.size()); - - for (Map.Entry entry : serviceBeansMap.entrySet()) { - - String serviceBeanName = entry.getKey(); - - ServiceBean serviceBean = entry.getValue(); - - Map serviceBeanMetadata = resolveBeanMetadata(serviceBean); - - Object service = resolveServiceBean(serviceBeanName, serviceBean); - - if (service != null) { - // Add Service implementation class - serviceBeanMetadata.put("serviceClass", service.getClass().getName()); - } - - servicesMetadata.put(serviceBeanName, serviceBeanMetadata); - - } - - return servicesMetadata; - - } - - protected Map resolveBeanMetadata(final Object bean) { - - final Map beanMetadata = new LinkedHashMap<>(); - - try { - - BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); - PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); - - for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { - - Method readMethod = propertyDescriptor.getReadMethod(); - - if (readMethod != null && isSimpleType(propertyDescriptor.getPropertyType())) { - - String name = Introspector.decapitalize(propertyDescriptor.getName()); - Object value = readMethod.invoke(bean); - - if (value != null) { - beanMetadata.put(name, value); - } - } - - } - - } catch (Exception e) { - throw new RuntimeException(e); - } - - return beanMetadata; - - } - - private Object resolveServiceBean(String serviceBeanName, ServiceBean serviceBean) { - - int index = serviceBeanName.indexOf("#"); - - if (index > -1) { - - Class interfaceClass = serviceBean.getInterfaceClass(); - - String serviceName = serviceBeanName.substring(index + 1); - - if (beanFactory.containsBean(serviceName)) { - return beanFactory.getBean(serviceName, interfaceClass); - } - - } - - return null; - - } - - private static boolean isSimpleType(Class type) { - return isPrimitiveOrWrapper(type) - || type == String.class - || type == BigDecimal.class - || type == BigInteger.class - || type == Date.class - || type == URL.class - || type == Class.class - ; - } + public static void main(String[] args) { + SpringApplication.run(ProviderApplication.class, args); + } + + @RestController + class EchoController { + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) + public String echo(@PathVariable String string) { + return "hello Nacos Discovery " + string; + } + + @RequestMapping(value = "/divide", method = RequestMethod.GET) + public String divide(@RequestParam Integer a, @RequestParam Integer b) { + return String.valueOf(a / b); + } + } } diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties index 81cea7178..66100d79f 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties @@ -1,12 +1,4 @@ server.port=18082 spring.application.name=service-provider spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 -management.endpoints.web.exposure.include=* - - -dubbo.scan.base-packages=org.springframework.cloud.alibaba.cloud.examples - -dubbo.registry.address=nacos://127.0.0.1:8848 - -dubbo.protocol.name=dubbo -dubbo.protocol.port=-1 \ No newline at end of file +management.endpoints.web.exposure.include=* \ No newline at end of file From 65397e861cd5bdbb892fa141c72363496bc03d9e Mon Sep 17 00:00:00 2001 From: xiaolongzuo <150349407@qq.com> Date: Tue, 22 Jan 2019 16:49:12 +0800 Subject: [PATCH 19/50] Fix code format error. --- .../acm/endpoint/AcmEndpointAutoConfiguration.java | 1 + .../context/nacos/NacosParameterInitListener.java | 7 ++++--- .../cloud/alicloud/oss/OssApplicationListener.java | 9 +++++---- .../oss/endpoint/OssEndpointAutoConfiguration.java | 2 +- .../oss/resource/OssStorageProtocolResolver.java | 9 +++++---- spring-cloud-alicloud-schedulerx/pom.xml | 6 ++++++ .../scx/endpoint/ScxEndpointAutoConfiguration.java | 14 ++++++++++---- 7 files changed, 32 insertions(+), 16 deletions(-) diff --git a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpointAutoConfiguration.java b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpointAutoConfiguration.java index 86c7fa184..a2f7d312d 100644 --- a/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpointAutoConfiguration.java +++ b/spring-cloud-alicloud-acm/src/main/java/org/springframework/cloud/alicloud/acm/endpoint/AcmEndpointAutoConfiguration.java @@ -51,6 +51,7 @@ public class AcmEndpointAutoConfiguration { } @Bean + @ConditionalOnMissingBean public AcmHealthIndicator acmHealthIndicator(AcmProperties acmProperties, AcmPropertySourceRepository acmPropertySourceRepository) { return new AcmHealthIndicator(acmProperties, acmPropertySourceRepository); diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListener.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListener.java index 73dcc75dd..496dd5a5e 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListener.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListener.java @@ -27,12 +27,13 @@ public class NacosParameterInitListener EdasChangeOrderConfiguration edasChangeOrderConfiguration = EdasChangeOrderConfigurationFactory .getEdasChangeOrderConfiguration(); - log.info("Initialize Nacos Parameter from edas change order,is edas managed {}.", - edasChangeOrderConfiguration.isEdasManaged()); - if (!edasChangeOrderConfiguration.isEdasManaged()) { return; } + + log.info("Initialize Nacos Parameter from edas change order,is edas managed {}.", + edasChangeOrderConfiguration.isEdasManaged()); + // initialize nacos configuration System.getProperties().setProperty("spring.cloud.nacos.config.server-addr", ""); System.getProperties().setProperty("spring.cloud.nacos.config.endpoint", diff --git a/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/OssApplicationListener.java b/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/OssApplicationListener.java index 23120e388..fa0473d69 100644 --- a/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/OssApplicationListener.java +++ b/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/OssApplicationListener.java @@ -26,22 +26,23 @@ import org.springframework.context.event.ContextClosedEvent; import com.aliyun.oss.OSS; /** - * Shutdown All OSS Clients when {@code ApplicationContext} gets closed {@link ApplicationListener} + * Shutdown All OSS Clients when {@code ApplicationContext} gets closed + * {@link ApplicationListener} * * @author Jim */ public class OssApplicationListener implements ApplicationListener { - private static final Logger logger = LoggerFactory + private static final Logger log = LoggerFactory .getLogger(OssApplicationListener.class); @Override public void onApplicationEvent(ContextClosedEvent event) { Map ossClientMap = event.getApplicationContext() .getBeansOfType(OSS.class); - logger.info("{} OSSClients will be shutdown soon", ossClientMap.size()); + log.info("{} OSSClients will be shutdown soon", ossClientMap.size()); ossClientMap.keySet().forEach(beanName -> { - logger.info("shutdown ossClient: {}", beanName); + log.info("shutdown ossClient: {}", beanName); ossClientMap.get(beanName).shutdown(); }); } diff --git a/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/endpoint/OssEndpointAutoConfiguration.java b/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/endpoint/OssEndpointAutoConfiguration.java index 0378dd4f7..aec1cae9b 100644 --- a/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/endpoint/OssEndpointAutoConfiguration.java +++ b/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/endpoint/OssEndpointAutoConfiguration.java @@ -34,7 +34,7 @@ public class OssEndpointAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint - public OssEndpoint sentinelEndPoint() { + public OssEndpoint ossEndpoint() { return new OssEndpoint(); } diff --git a/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/resource/OssStorageProtocolResolver.java b/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/resource/OssStorageProtocolResolver.java index 681f3e882..b062e6448 100644 --- a/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/resource/OssStorageProtocolResolver.java +++ b/spring-cloud-alicloud-oss/src/main/java/org/springframework/cloud/alicloud/oss/resource/OssStorageProtocolResolver.java @@ -39,7 +39,7 @@ public class OssStorageProtocolResolver public static final String PROTOCOL = "oss://"; - private static final Logger logger = LoggerFactory + private static final Logger log = LoggerFactory .getLogger(OssStorageProtocolResolver.class); private ConfigurableListableBeanFactory beanFactory; @@ -49,8 +49,9 @@ public class OssStorageProtocolResolver private OSS getOSS() { if (this.oss == null) { if (this.beanFactory.getBeansOfType(OSS.class).size() > 1) { - logger.warn( - "There are multiple OSS instances, consider marking one of them as @Primary to resolve oss protocol."); + log.warn( + "There are multiple OSS instances, consider marking one of them as @Primary to resolve oss " + + "protocol."); } this.oss = this.beanFactory.getBean(OSS.class); } @@ -71,7 +72,7 @@ public class OssStorageProtocolResolver ((DefaultResourceLoader) resourceLoader).addProtocolResolver(this); } else { - logger.warn("The provided delegate resource loader is not an implementation " + log.warn("The provided delegate resource loader is not an implementation " + "of DefaultResourceLoader. Custom Protocol using oss:// prefix will not be enabled."); } } diff --git a/spring-cloud-alicloud-schedulerx/pom.xml b/spring-cloud-alicloud-schedulerx/pom.xml index e3c1b8e89..04b948a54 100644 --- a/spring-cloud-alicloud-schedulerx/pom.xml +++ b/spring-cloud-alicloud-schedulerx/pom.xml @@ -38,6 +38,12 @@ provided true + + org.springframework.boot + spring-boot-actuator-autoconfigure + provided + true + org.springframework.boot spring-boot-actuator diff --git a/spring-cloud-alicloud-schedulerx/src/main/java/org/springframework/cloud/alicloud/scx/endpoint/ScxEndpointAutoConfiguration.java b/spring-cloud-alicloud-schedulerx/src/main/java/org/springframework/cloud/alicloud/scx/endpoint/ScxEndpointAutoConfiguration.java index 9ca280b55..46d749d21 100644 --- a/spring-cloud-alicloud-schedulerx/src/main/java/org/springframework/cloud/alicloud/scx/endpoint/ScxEndpointAutoConfiguration.java +++ b/spring-cloud-alicloud-schedulerx/src/main/java/org/springframework/cloud/alicloud/scx/endpoint/ScxEndpointAutoConfiguration.java @@ -16,8 +16,10 @@ package org.springframework.cloud.alicloud.scx.endpoint; +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.cloud.alicloud.context.edas.EdasProperties; import org.springframework.cloud.alicloud.context.scx.ScxProperties; @@ -30,8 +32,12 @@ import org.springframework.context.annotation.Bean; @ConditionalOnClass(Endpoint.class) public class ScxEndpointAutoConfiguration { - @Bean - public ScxEndpoint scxEndpoint(EdasProperties edasProperties, ScxProperties scxProperties) { - return new ScxEndpoint(edasProperties, scxProperties); - } + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + public ScxEndpoint scxEndpoint(EdasProperties edasProperties, + ScxProperties scxProperties) { + return new ScxEndpoint(edasProperties, scxProperties); + } + } From d3f98b66a4d59058ffb588278d841cfdade54bc0 Mon Sep 17 00:00:00 2001 From: justlive1 Date: Fri, 25 Jan 2019 15:33:03 +0800 Subject: [PATCH 20/50] fixed netInterface NullPointerException --- .../cloud/alibaba/nacos/NacosDiscoveryProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java index 86b73bf39..ed568e24b 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java @@ -160,7 +160,7 @@ public class NacosDiscoveryProperties { else { NetworkInterface netInterface = NetworkInterface .getByName(networkInterface); - if (null == networkInterface) { + if (null == netInterface) { throw new IllegalArgumentException( "no such interface " + networkInterface); } From 65ce68ebaa2b8754d053c0388a2194c2156303ec Mon Sep 17 00:00:00 2001 From: xiaojing Date: Tue, 29 Jan 2019 10:08:44 +0800 Subject: [PATCH 21/50] Update README.md --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 8b073b616..3d5172e1c 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,28 @@ During the incubation period, the version management of the project will follow * Functional updates will be reflected in the 3rd number of the version, for example, the next version of 0.1.0 will be 0.1.1. +## Code of Conduct +This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. + +## Code Conventions and Housekeeping +None of these is essential for a pull request, but they will all help. They can also be added after the original pull request but before a merge. + +Use the Spring Framework code format conventions. If you use Eclipse you can import formatter settings using the eclipse-code-formatter.xml file from the Spring Cloud Build project. If using IntelliJ, you can use the Eclipse Code Formatter Plugin to import the same file. + +Make sure all new .java files to have a simple Javadoc class comment with at least an @author tag identifying you, and preferably at least a paragraph on what the class is for. + +Add the ASF license header comment to all new .java files (copy from existing files in the project) + +Add yourself as an @author to the .java files that you modify substantially (more than cosmetic changes). + +Add some Javadocs and, if you change the namespace, some XSD doc elements. + +A few unit tests would help a lot as well — someone has to do it. + +If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project). + +When writing a commit message please follow these conventions, if you are fixing an existing issue please add Fixes gh-XXXX at the end of the commit message (where XXXX is the issue number). + ## Contact Us Mailing list is recommended for discussing almost anything related to spring-cloud-alibaba. From 200b25d538cd86467db300958ba8a6001cee385a Mon Sep 17 00:00:00 2001 From: xiaojing Date: Tue, 29 Jan 2019 10:13:39 +0800 Subject: [PATCH 22/50] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d5172e1c..40e6fd242 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ During the incubation period, the version management of the project will follow ## Code of Conduct -This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. +This project is a sub-project of Spring Cloud, it adheres to the Contributor Covenant [code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. ## Code Conventions and Housekeeping None of these is essential for a pull request, but they will all help. They can also be added after the original pull request but before a merge. From e976844dc3d0aa4920795271b6d1bcc2f9856dc2 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Tue, 29 Jan 2019 10:19:57 +0800 Subject: [PATCH 23/50] Create CODE_OF_CONDUCT.adoc --- CODE_OF_CONDUCT.adoc | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 CODE_OF_CONDUCT.adoc diff --git a/CODE_OF_CONDUCT.adoc b/CODE_OF_CONDUCT.adoc new file mode 100644 index 000000000..77a7e0acf --- /dev/null +++ b/CODE_OF_CONDUCT.adoc @@ -0,0 +1,45 @@ + += Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open +and welcoming community, we pledge to respect all people who contribute through reporting +issues, posting feature requests, updating documentation, submitting pull requests or +patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for +everyone, regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, body size, race, ethnicity, age, +religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic addresses, + without explicit permission +* Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, +commits, code, wiki edits, issues, and other contributions that are not aligned to this +Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors +that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to fairly and +consistently applying these principles to every aspect of managing this project. Project +maintainers who do not follow or enforce the Code of Conduct may be permanently removed +from the project team. + +This Code of Conduct applies both within project spaces and in public spaces when an +individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will +be reviewed and investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. Maintainers are obligated to maintain confidentiality +with regard to the reporter of an incident. + +This Code of Conduct is adapted from the +http://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at +http://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/] From ac0cd78c101fe5a53699ca76fb0de68f5afe4a58 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Tue, 29 Jan 2019 10:24:07 +0800 Subject: [PATCH 24/50] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..7146573a5 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,29 @@ +## Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery + +- Personal attacks + +- Trolling or insulting/derogatory comments + +- Public or private harassment + +- Publishing other’s private information, such as physical or electronic addresses, without explicit permission + +- Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org/), version 1.3.0, available at [contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/) From 2521246a5d313f65f536308887678d4d122632ca Mon Sep 17 00:00:00 2001 From: xiaojing Date: Tue, 29 Jan 2019 10:25:59 +0800 Subject: [PATCH 25/50] Create PULL_REQUEST_TEMPLATE.md --- PULL_REQUEST_TEMPLATE.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..7261357c5 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ + +### Describe what this PR does / why we need it + + +### Does this pull request fix one issue? + + + +### Describe how you did it + + +### Describe how to verify it + + +### Special notes for reviews From 990bf1bff7a30c6852f895aa915d7f61cf087b68 Mon Sep 17 00:00:00 2001 From: flystar32 Date: Tue, 29 Jan 2019 10:47:32 +0800 Subject: [PATCH 26/50] update nacos version to 0.8.0 ,Polish #295, #317 --- spring-cloud-alibaba-dependencies/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index b2b9f8069..74e532715 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -19,8 +19,8 @@ 1.4.1 3.1.0 - 0.6.2 - 0.6.1 + 0.8.0 + 0.8.0 1.0.8 1.0.1 4.0.1 From d5d90d9c0a1aa3150ddba4fc4d26e82d5078df8e Mon Sep 17 00:00:00 2001 From: xiaolongzuo <150349407@qq.com> Date: Tue, 29 Jan 2019 16:10:06 +0800 Subject: [PATCH 27/50] Polish java doc. --- .../alicloud/context/ans/AnsProperties.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java index 2852ff573..587ed0c63 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java @@ -42,84 +42,94 @@ import com.alibaba.cloud.context.ans.AnsConfiguration; public class AnsProperties implements AnsConfiguration { /** - * 服务端模式,默认为LOCAL + * Server side mode,the default is LOCAL. */ private AliCloudServerMode serverMode = AliCloudServerMode.LOCAL; /** - * 服务端列表 + * Server list. */ private String serverList = "127.0.0.1"; /** - * 服务端列表 + * Server port. */ private String serverPort = "8080"; /** - * 注册的服务名,默认从 spring.cloud.alicloud.ans.doms 中获取,当没有配置时,使用 spring.application.name + * Service names,default value is ${spring.cloud.alicloud.ans.doms}. When not + * configured, use ${spring.application.name}. */ @Value("${spring.cloud.alicloud.ans.client-domains:${spring.application.name:}}") private String clientDomains; /** - * 注册服务的权重,从配置 spring.cloud.alicloud.ans.weight 中获取,默认为 1 + * The weight of the registration service, obtained from the configuration + * ${spring.cloud.alicloud.ans.weight}, the default is 1. */ private float clientWeight = 1; /** - * 当存在多个doms,需要对应不同的 weight 时,通过 spring.cloud.alicloud.ans.weight.dom1=weight1 的方式配置 + * When there are multiple doms and need to correspond to different weights, configure + * them by spring.cloud.alicloud.ans.weight.dom1=weight1. */ private Map clientWeights = new HashMap(); /** - * 注册服务的 token ,从 spring.cloud.alicloud.ans.token 中获取 + * The token of the registration service, obtained from + * ${spring.cloud.alicloud.ans.token}. */ private String clientToken; /** - * 当存在多个doms,需要对应不同的token时,通过 spring.cloud.alicloud.ans.tokens.dom1=token1 的方式配置 + * When there are multiple doms and need to correspond to different tokens, configure + * them by spring.cloud.alicloud.ans.tokens.dom1=token1. */ private Map clientTokens = new HashMap(); /** - * 配置注册到哪个集群,从 spring.cloud.alicloud.ans.cluster 中获取,默认为 DEFAULT + * Configure which cluster to register with, obtained from + * ${spring.cloud.alicloud.ans.cluster}, defaults to DEFAULT. */ private String clientCluster = "DEFAULT"; /** - * metadata 实现 serviceInstance 接口所需的字段,但 ans 目前尚不支持此字段,配置了也没用 + * Unsupported. */ private Map clientMetadata = new HashMap<>(); /** - * 默认打开注册,可以通过 spring.cloud.alicloud.ans.register-enabled=false 的配置来关闭注册 + * Registration is turned on by default, and registration can be turned off by the + * configuration of spring.cloud.alicloud.ans.register-enabled=false. */ private boolean registerEnabled = true; /** - * 想要发布的服务的ip,从 spring.cloud.alicloud.ans.client-ip 中获取 + * The ip of the service you want to publish, obtained from + * ${spring.cloud.alicloud.ans.client-ip}. */ private String clientIp; /** - * 想要发布的服务的ip从哪一块网卡中获取 + * Configure which NIC the ip of the service you want to publish is obtained from. */ private String clientInterfaceName; /** - * 想要发布的服务的端口,从 spring.cloud.alicloud.ans.port 中获取 + * The port of the service you want to publish. */ private int clientPort = -1; /** - * 租户下的环境隔离配置,相同租户的相同环境下的服务才能互相发现 + * The environment isolation configuration under the tenant, the services in the same + * environment of the same tenant can discover each other. */ @Value("${spring.cloud.alicloud.ans.env:${env.id:DEFAULT}}") private String env; /** - * 是否注册成 https 的形式,通过 spring.cloud.alicloud.ans.secure 来配置,默认为false + * Whether to register as https, configured by ${spring.cloud.alicloud.ans.secure}, + * default is false. */ private boolean secure = false; @@ -131,11 +141,10 @@ public class AnsProperties implements AnsConfiguration { @PostConstruct public void init() throws SocketException { - // 增加注册类型,标记为 spring cloud 应用 + // Marked as spring cloud application tags.put("ANS_SERVICE_TYPE", "SPRING_CLOUD"); if (StringUtils.isEmpty(clientIp)) { - // 如果没有指定注册的ip对应的网卡名,则通过遍历网卡去获取 if (StringUtils.isEmpty(clientInterfaceName)) { clientIp = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); } From 0acd1b0a537374fa502becb22254f07e6136b433 Mon Sep 17 00:00:00 2001 From: xiaolongzuo <150349407@qq.com> Date: Tue, 29 Jan 2019 16:24:59 +0800 Subject: [PATCH 28/50] Polish java doc. --- .../cloud/alicloud/context/ans/AnsProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java index 587ed0c63..1952a5246 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/ans/AnsProperties.java @@ -94,7 +94,7 @@ public class AnsProperties implements AnsConfiguration { private String clientCluster = "DEFAULT"; /** - * Unsupported. + * Temporarily not supported, reserved fields. */ private Map clientMetadata = new HashMap<>(); From a6a894a110f699ce1d429bce6ebc096cd1f7bea2 Mon Sep 17 00:00:00 2001 From: flystar32 Date: Wed, 30 Jan 2019 13:40:26 +0800 Subject: [PATCH 29/50] add module Fescar, Polish #303 --- pom.xml | 1 + spring-cloud-alibaba-dependencies/pom.xml | 35 ++++ .../fescar-example/account-service/pom.xml | 63 +++++++ .../cloud/examples/AccountApplication.java | 32 ++++ .../cloud/examples/AccountController.java | 66 ++++++++ .../cloud/examples/DatabaseConfiguration.java | 92 +++++++++++ .../src/main/resources/application.conf | 30 ++++ .../src/main/resources/application.properties | 9 + .../fescar-example/business-service/pom.xml | 62 +++++++ .../cloud/examples/BusinessApplication.java | 63 +++++++ .../cloud/examples/HomeController.java | 117 +++++++++++++ .../cloud/alibaba/cloud/examples/Order.java | 33 ++++ .../src/main/resources/application.conf | 30 ++++ .../src/main/resources/application.properties | 8 + .../fescar-example/order-service/pom.xml | 63 +++++++ .../cloud/examples/DatabaseConfiguration.java | 89 ++++++++++ .../cloud/examples/OderApplication.java | 39 +++++ .../cloud/alibaba/cloud/examples/Order.java | 33 ++++ .../cloud/examples/OrderController.java | 131 +++++++++++++++ .../src/main/resources/application.conf | 30 ++++ .../src/main/resources/application.properties | 9 + .../fescar-example/readme-zh.md | 156 ++++++++++++++++++ .../fescar-example/storage-service/pom.xml | 68 ++++++++ .../cloud/examples/DatabaseConfiguration.java | 94 +++++++++++ .../cloud/examples/StorageApplication.java | 32 ++++ .../cloud/examples/StorageController.java | 58 +++++++ .../src/main/resources/application.conf | 30 ++++ .../src/main/resources/application.properties | 9 + spring-cloud-alibaba-examples/pom.xml | 4 + spring-cloud-alibaba-fescar/pom.xml | 117 +++++++++++++ .../alibaba/fescar/FescarProperties.java | 42 +++++ .../GlobalTransactionAutoConfiguration.java | 60 +++++++ .../fescar/feign/FescarBeanPostProcessor.java | 44 +++++ .../feign/FescarContextBeanPostProcessor.java | 59 +++++++ .../fescar/feign/FescarFeignBuilder.java | 34 ++++ .../fescar/feign/FescarFeignClient.java | 85 ++++++++++ .../FescarFeignClientAutoConfiguration.java | 85 ++++++++++ .../fescar/feign/FescarFeignContext.java | 67 ++++++++ .../feign/FescarFeignObjectWrapper.java | 67 ++++++++ .../feign/FescarHystrixFeignBuilder.java | 37 +++++ .../feign/FescarLoadBalancerFeignClient.java | 53 ++++++ .../feign/FescarSentinelFeignBuilder.java | 39 +++++ .../FescarHystrixAutoConfiguration.java | 37 +++++ .../FescarHystrixConcurrencyStrategy.java | 80 +++++++++ .../FescarRestTemplateAutoConfiguration.java | 76 +++++++++ .../rest/FescarRestTemplateInterceptor.java | 46 ++++++ .../fescar/web/FescarHandlerInterceptor.java | 85 ++++++++++ ...FescarHandlerInterceptorConfiguration.java | 31 ++++ .../main/resources/META-INF/spring.factories | 7 + spring-cloud-starter-alibaba/pom.xml | 1 + .../pom.xml | 20 +++ 51 files changed, 2658 insertions(+) create mode 100644 spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml create mode 100644 spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf create mode 100644 spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties create mode 100644 spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml create mode 100644 spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf create mode 100644 spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf create mode 100644 spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties create mode 100644 spring-cloud-alibaba-examples/fescar-example/readme-zh.md create mode 100644 spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml create mode 100644 spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java create mode 100644 spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf create mode 100644 spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties create mode 100644 spring-cloud-alibaba-fescar/pom.xml create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java create mode 100644 spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java create mode 100644 spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml diff --git a/pom.xml b/pom.xml index bd0b9c847..30dd78f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,7 @@ spring-cloud-alibaba-sentinel-datasource spring-cloud-alibaba-nacos-config spring-cloud-alibaba-nacos-discovery + spring-cloud-alibaba-fescar spring-cloud-stream-binder-rocketmq spring-cloud-alibaba-nacos-config-server spring-cloud-alicloud-context diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index b2b9f8069..16b0582c1 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -19,6 +19,7 @@ 1.4.1 3.1.0 + 0.1.3 0.6.2 0.6.1 1.0.8 @@ -176,6 +177,29 @@ + + + + com.alibaba.fescar + fescar-core + ${fescar.version} + + + com.alibaba.fescar + fescar-common + ${fescar.version} + + + com.alibaba.fescar + fescar-spring + ${fescar.version} + + + com.alibaba.fescar + fescar-rm-datasource + ${fescar.version} + + com.aliyun.oss @@ -215,6 +239,11 @@ spring-cloud-alibaba-nacos-config-server ${project.version} + + org.springframework.cloud + spring-cloud-alibaba-fescar + ${project.version} + org.springframework.cloud spring-cloud-alicloud-acm @@ -258,6 +287,12 @@ ${project.version} + + org.springframework.cloud + spring-cloud-starter-alibaba-fescar + ${project.version} + + org.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml new file mode 100644 index 000000000..219187bcf --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml @@ -0,0 +1,63 @@ + + + + spring-cloud-alibaba-examples + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../../pom.xml + + 4.0.0 + account-service + + + + org.springframework.cloud + spring-cloud-starter-alibaba-fescar + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-jdbc + + + + mysql + mysql-connector-java + + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.codehaus.mojo + cobertura-maven-plugin + false + + true + + + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java new file mode 100644 index 000000000..893d34642 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author xiaojing + */ +@SpringBootApplication +public class AccountApplication { + + public static void main(String[] args) { + SpringApplication.run(AccountApplication.class, args); + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java new file mode 100644 index 000000000..3738fb87e --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.cloud.examples; + +import java.util.Random; + +import com.alibaba.fescar.core.context.RootContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author xiaojing + */ +@RestController +public class AccountController { + + private static final Logger LOGGER = LoggerFactory.getLogger(AccountController.class); + + private static final String SUCCESS = "SUCCESS"; + private static final String FAIL = "FAIL"; + + private final JdbcTemplate jdbcTemplate; + private Random random; + + public AccountController(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + this.random = new Random(); + } + + @RequestMapping(value = "/account", method = RequestMethod.POST, produces = "application/json") + public String account(String userId, int money) { + LOGGER.info("Account Service ... xid: " + RootContext.getXID()); + + if (random.nextBoolean()) { + throw new RuntimeException("this is a mock Exception"); + } + + int result = jdbcTemplate.update( + "update account_tbl set money = money - ? where user_id = ?", + new Object[] { money, userId }); + LOGGER.info("Account Service End ... "); + if (result == 1) { + return SUCCESS; + } + return FAIL; + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java new file mode 100644 index 000000000..62e11cd69 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.cloud.examples; + +import java.sql.SQLException; +import java.util.Random; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.fescar.rm.datasource.DataSourceProxy; + +/** + * @author xiaojing + */ +@Configuration +public class DatabaseConfiguration { + + private final ApplicationContext applicationContext; + + public DatabaseConfiguration(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean(initMethod = "init", destroyMethod = "close") + public DruidDataSource storageDataSource() throws SQLException { + + Environment environment = applicationContext.getEnvironment(); + + String ip = environment.getProperty("mysql.server.ip"); + String port = environment.getProperty("mysql.server.port"); + String dbName = environment.getProperty("mysql.db.name"); + + String userName = environment.getProperty("mysql.user.name"); + String password = environment.getProperty("mysql.user.password"); + + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName); + druidDataSource.setUsername(userName); + druidDataSource.setPassword(password); + druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); + druidDataSource.setInitialSize(0); + druidDataSource.setMaxActive(180); + druidDataSource.setMaxWait(60000); + druidDataSource.setMinIdle(0); + druidDataSource.setValidationQuery("Select 'x' from DUAL"); + druidDataSource.setTestOnBorrow(false); + druidDataSource.setTestOnReturn(false); + druidDataSource.setTestWhileIdle(true); + druidDataSource.setTimeBetweenEvictionRunsMillis(60000); + druidDataSource.setMinEvictableIdleTimeMillis(25200000); + druidDataSource.setRemoveAbandoned(true); + druidDataSource.setRemoveAbandonedTimeout(1800); + druidDataSource.setLogAbandoned(true); + druidDataSource.setFilters("mergeStat"); + return druidDataSource; + } + + @Bean + public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) { + return new DataSourceProxy(druidDataSource); + } + + @Bean + public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy); + + jdbcTemplate.update("delete from account_tbl where user_id = 'U100001'"); + jdbcTemplate.update( + "insert into account_tbl(user_id, money) values ('U100001', 10000)"); + + return jdbcTemplate; + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf new file mode 100644 index 000000000..b264dd9da --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf @@ -0,0 +1,30 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #thread factory for netty + thread-factory { + boss-thread-prefix = "NettyBoss" + worker-thread-prefix = "NettyServerNIOWorker" + server-executor-thread-prefix = "NettyServerBizHandler" + share-boss-worker = false + client-selector-thread-prefix = "NettyClientSelector" + client-selector-thread-size = 1 + client-worker-thread-prefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + boss-thread-size = 1 + #auto default pin or 8 + worker-thread-size = 8 + } +} +service { + #vgroup->rgroup + vgroup_mapping.account-service-fescar-service-group = "localRgroup" + #only support single node + localRgroup.grouplist = "127.0.0.1:8091" + #degrade current not support + enableDegrade = false + #disable + disable = false +} diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties new file mode 100644 index 000000000..10f45c59a --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.application.name=account-service +server.port=18084 + +mysql.server.ip=127.0.0.1 +mysql.server.port=3306 +mysql.db.name=demo + +mysql.user.name=xxxxx +mysql.user.password=xxxxx \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml new file mode 100644 index 000000000..6d77872a2 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml @@ -0,0 +1,62 @@ + + + + spring-cloud-alibaba-examples + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../../pom.xml + + 4.0.0 + business-service + + + + org.springframework.cloud + spring-cloud-starter-alibaba-fescar + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-alibaba-sentinel + + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + + + + + + org.codehaus.mojo + cobertura-maven-plugin + false + + true + + + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java new file mode 100644 index 000000000..c0ed45fc2 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.context.annotation.Bean; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ +@SpringBootApplication +@EnableFeignClients +public class BusinessApplication { + + public static void main(String[] args) { + SpringApplication.run(BusinessApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @FeignClient(value = "storage", url = "http://127.0.0.1:18082") + public interface StorageService { + + @RequestMapping(path = "/storage/{commodityCode}/{count}") + String storage(@RequestParam("commodityCode") String commodityCode, + @RequestParam("count") int count); + + } + + @FeignClient(value = "order", url = "http://127.0.0.1:18083") + public interface OrderService { + + @RequestMapping(path = "/order", method = RequestMethod.POST) + String order(@RequestParam("userId") String userId, + @RequestParam("commodityCode") String commodityCode, + @RequestParam("orderCount") int orderCount); + + } +} diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java new file mode 100644 index 000000000..039074ec0 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import com.alibaba.fescar.spring.annotation.GlobalTransactional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.alibaba.cloud.examples.BusinessApplication.OrderService; +import org.springframework.cloud.alibaba.cloud.examples.BusinessApplication.StorageService; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ +@RestController +public class HomeController { + + private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class); + + private static final String SUCCESS = "SUCCESS"; + private static final String FAIL = "FAIL"; + private static final String USER_ID = "U100001"; + private static final String COMMODITY_CODE = "C00321"; + private static final int ORDER_COUNT = 2; + + private final RestTemplate restTemplate; + private final OrderService orderService; + private final StorageService storageService; + + public HomeController(RestTemplate restTemplate, OrderService orderService, + StorageService storageService) { + this.restTemplate = restTemplate; + this.orderService = orderService; + this.storageService = storageService; + } + + @GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx") + @RequestMapping(value = "/fescar/rest", method = RequestMethod.GET, produces = "application/json") + public String rest() { + + String result = restTemplate.getForObject( + "http://127.0.0.1:18082/storage/" + COMMODITY_CODE + "/" + ORDER_COUNT, + String.class); + + if (!SUCCESS.equals(result)) { + throw new RuntimeException(); + } + + String url = "http://127.0.0.1:18083/order"; + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap map = new LinkedMultiValueMap(); + map.add("userId", USER_ID); + map.add("commodityCode", COMMODITY_CODE); + map.add("orderCount", ORDER_COUNT + ""); + + HttpEntity> request = new HttpEntity>( + map, headers); + + ResponseEntity response = restTemplate.postForEntity(url, request, + String.class); + + result = response.getBody(); + + if (!SUCCESS.equals(result)) { + throw new RuntimeException(); + } + + return SUCCESS; + } + + @GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx") + @RequestMapping(value = "/fescar/feign", method = RequestMethod.GET, produces = "application/json") + public String feign() { + + String result = storageService.storage(COMMODITY_CODE, ORDER_COUNT); + + if (!SUCCESS.equals(result)) { + throw new RuntimeException(); + } + + result = orderService.order(USER_ID, COMMODITY_CODE, ORDER_COUNT); + + if (!SUCCESS.equals(result)) { + throw new RuntimeException(); + } + + return SUCCESS; + + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java new file mode 100644 index 000000000..6594793a3 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import java.io.Serializable; + +public class Order implements Serializable { + public long id; + public String userId; + public String commodityCode; + public int count; + public int money; + + @Override + public String toString() { + return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='" + + commodityCode + '\'' + ", count=" + count + ", money=" + money + '}'; + } +} diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf new file mode 100644 index 000000000..65b695084 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf @@ -0,0 +1,30 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #thread factory for netty + thread-factory { + boss-thread-prefix = "NettyBoss" + worker-thread-prefix = "NettyServerNIOWorker" + server-executor-thread-prefix = "NettyServerBizHandler" + share-boss-worker = false + client-selector-thread-prefix = "NettyClientSelector" + client-selector-thread-size = 1 + client-worker-thread-prefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + boss-thread-size = 1 + #auto default pin or 8 + worker-thread-size = 8 + } +} +service { + #vgroup->rgroup + vgroup_mapping.business-service-fescar-service-group = "localRgroup" + #only support single node + localRgroup.grouplist = "127.0.0.1:8091" + #degrade current not support + enableDegrade = false + #disable + disable = false +} diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties new file mode 100644 index 000000000..1832ce6f5 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties @@ -0,0 +1,8 @@ +server.port=18081 +spring.application.name=business-service +# The following configuration can be omitted. + +#feign.hystrix.enabled=true +#feign.sentinel.enabled=true + +logging.level.com.alibaba.fescar=debug \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml new file mode 100644 index 000000000..7840c5462 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml @@ -0,0 +1,63 @@ + + + + spring-cloud-alibaba-examples + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../../pom.xml + + 4.0.0 + order-service + + + + org.springframework.cloud + spring-cloud-starter-alibaba-fescar + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-jdbc + + + + mysql + mysql-connector-java + + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.codehaus.mojo + cobertura-maven-plugin + false + + true + + + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java new file mode 100644 index 000000000..8e5c7d87b --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.cloud.examples; + +import java.sql.SQLException; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.fescar.rm.datasource.DataSourceProxy; + +/** + * @author xiaojing + */ +@Configuration +public class DatabaseConfiguration { + + private final ApplicationContext applicationContext; + + public DatabaseConfiguration(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean(initMethod = "init", destroyMethod = "close") + public DruidDataSource storageDataSource() throws SQLException { + + Environment env = applicationContext.getEnvironment(); + + String ip = env.getProperty("mysql.server.ip"); + String port = env.getProperty("mysql.server.port"); + String dbName = env.getProperty("mysql.db.name"); + + String userName = env.getProperty("mysql.user.name"); + String password = env.getProperty("mysql.user.password"); + + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName); + druidDataSource.setUsername(userName); + druidDataSource.setPassword(password); + druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); + druidDataSource.setInitialSize(0); + druidDataSource.setMaxActive(180); + druidDataSource.setMaxWait(60000); + druidDataSource.setMinIdle(0); + druidDataSource.setValidationQuery("Select 'x' from DUAL"); + druidDataSource.setTestOnBorrow(false); + druidDataSource.setTestOnReturn(false); + druidDataSource.setTestWhileIdle(true); + druidDataSource.setTimeBetweenEvictionRunsMillis(60000); + druidDataSource.setMinEvictableIdleTimeMillis(25200000); + druidDataSource.setRemoveAbandoned(true); + druidDataSource.setRemoveAbandonedTimeout(1800); + druidDataSource.setLogAbandoned(true); + druidDataSource.setFilters("mergeStat"); + return druidDataSource; + } + + @Bean + public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) { + return new DataSourceProxy(druidDataSource); + } + + @Bean + public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy); + + jdbcTemplate.execute("TRUNCATE TABLE order_tbl"); + + return jdbcTemplate; + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java new file mode 100644 index 000000000..1ab0dab11 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ +@SpringBootApplication +public class OderApplication { + + public static void main(String[] args) { + SpringApplication.run(OderApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java new file mode 100644 index 000000000..6594793a3 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import java.io.Serializable; + +public class Order implements Serializable { + public long id; + public String userId; + public String commodityCode; + public int count; + public int money; + + @Override + public String toString() { + return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='" + + commodityCode + '\'' + ", count=" + count + ", money=" + money + '}'; + } +} diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java new file mode 100644 index 000000000..2e0e0f81c --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Random; + +import com.alibaba.fescar.core.context.RootContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ +@RestController +public class OrderController { + + private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class); + private static final String SUCCESS = "SUCCESS"; + private static final String FAIL = "FAIL"; + private static final String USER_ID = "U100001"; + private static final String COMMODITY_CODE = "C00321"; + + private final JdbcTemplate jdbcTemplate; + private final RestTemplate restTemplate; + private Random random; + + public OrderController(JdbcTemplate jdbcTemplate, RestTemplate restTemplate) { + this.jdbcTemplate = jdbcTemplate; + this.restTemplate = restTemplate; + this.random = new Random(); + } + + @RequestMapping(value = "/order", method = RequestMethod.POST, produces = "application/json") + public String order(String userId, String commodityCode, int orderCount) { + LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID()); + + int orderMoney = calculate(commodityCode, orderCount); + + invokerAccountService(orderMoney); + + final Order order = new Order(); + order.userId = userId; + order.commodityCode = commodityCode; + order.count = orderCount; + order.money = orderMoney; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int result = jdbcTemplate.update(new PreparedStatementCreator() { + + @Override + public PreparedStatement createPreparedStatement(Connection con) + throws SQLException { + PreparedStatement pst = con.prepareStatement( + "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)", + PreparedStatement.RETURN_GENERATED_KEYS); + pst.setObject(1, order.userId); + pst.setObject(2, order.commodityCode); + pst.setObject(3, order.count); + pst.setObject(4, order.money); + return pst; + } + }, keyHolder); + + order.id = (long) keyHolder.getKey(); + + if (random.nextBoolean()) { + throw new RuntimeException("this is a mock Exception"); + } + + LOGGER.info("Order Service End ... Created " + order); + + if (result == 1) { + return SUCCESS; + } + return FAIL; + } + + private int calculate(String commodityId, int orderCount) { + return 2 * orderCount; + } + + private void invokerAccountService(int orderMoney) { + String url = "http://127.0.0.1:18084/account"; + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap map = new LinkedMultiValueMap(); + + map.add("userId", USER_ID); + map.add("money", orderMoney + ""); + + HttpEntity> request = new HttpEntity>( + map, headers); + + ResponseEntity response = restTemplate.postForEntity(url, request, + String.class); + } +} diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf new file mode 100644 index 000000000..c298ca0c2 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf @@ -0,0 +1,30 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #thread factory for netty + thread-factory { + boss-thread-prefix = "NettyBoss" + worker-thread-prefix = "NettyServerNIOWorker" + server-executor-thread-prefix = "NettyServerBizHandler" + share-boss-worker = false + client-selector-thread-prefix = "NettyClientSelector" + client-selector-thread-size = 1 + client-worker-thread-prefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + boss-thread-size = 1 + #auto default pin or 8 + worker-thread-size = 8 + } +} +service { + #vgroup->rgroup + vgroup_mapping.order-service-fescar-service-group = "localRgroup" + #only support single node + localRgroup.grouplist = "127.0.0.1:8091" + #degrade current not support + enableDegrade = false + #disable + disable = false +} diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties new file mode 100644 index 000000000..f3e417d8d --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.application.name=order-service +server.port=18083 + +mysql.server.ip=127.0.0.1 +mysql.server.port=3306 +mysql.db.name=demo + +mysql.user.name=xxxxx +mysql.user.password=xxxxx \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/readme-zh.md b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md new file mode 100644 index 000000000..be3919497 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md @@ -0,0 +1,156 @@ +# Fescar Example + +## 项目说明 + + +本项目演示如何使用 Fescar Starter 完成 Spring Cloud 应用的分布式事务接入。 + +[Fescar](https://github.com/alibaba/fescar) 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题。 + + + +## 准备工作 + +在运行此示例之前,你需要先完成如下几步准备工作: + +1. 配置数据库 + +1. Create UNDO_LOG table + +1. Create tables for examples business + +1. Start Fescar Server + + +### 配置数据库 + +首先,你需要有一个支持 InnoDB 引擎的 MySQL 数据库。 + +**注意**: 实际上,Fescar 支持不同的应用使用完全不相干的数据库,但是这里为了简单地演示一个原理,所以我们选择了只使用一个数据库。 + +将 `account-server`、`order-service`、`storage-service` 这三个应用中的 resources 目录下的 `application.properties` 文件中的如下配置修改成你运行环境中的实际配置。 + +``` +mysql.server.ip=your mysql server ip address +mysql.server.port=your mysql server listening port +mysql.db.name=your database name for test + +mysql.user.name=your mysql server username +mysql.user.password=your mysql server password + +``` + +### 创建 UNDO_LOG 表 + +[Fescar AT 模式]() 需要使用到 UNDO_LOG 表。 + +``` $sql +CREATE TABLE `undo_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `branch_id` bigint(20) NOT NULL, + `xid` varchar(100) NOT NULL, + `rollback_info` longblob NOT NULL, + `log_status` int(11) NOT NULL, + `log_created` datetime NOT NULL, + `log_modified` datetime NOT NULL, + `ext` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_unionkey` (`xid`,`branch_id`) +) ENGINE=InnoDB AUTO_INCREMENT=159 DEFAULT CHARSET=utf8 +``` + +### 创建 示例中 业务所需要的数据库表 + +```$sql +DROP TABLE IF EXISTS `storage_tbl`; +CREATE TABLE `storage_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `commodity_code` varchar(255) DEFAULT NULL, + `count` int(11) DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY (`commodity_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP TABLE IF EXISTS `order_tbl`; +CREATE TABLE `order_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `commodity_code` varchar(255) DEFAULT NULL, + `count` int(11) DEFAULT 0, + `money` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP TABLE IF EXISTS `account_tbl`; +CREATE TABLE `account_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `money` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` + +### 启动 Fescar Server + +点击这个页面 [https://github.com/alibaba/fescar/releases](https://github.com/alibaba/fescar/releases),下载最新版本的 Fescar Server 端. + + +进入解压之后的 bin 目录,执行如下命令来启动 + +```$shell +sh fescar-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA +``` + +在这个示例中,采用如下命令来启动 Fescar Server + +```$shell +sh fescar-server.sh 8091 ~/fescar/data/ +``` + +**注意** 如果你修改了端口号,那么记得需要在各个示例工程中的 `application.conf` 文件中,修改 grouplist 的值。 + + +## 运行示例 + +分别运行 `account-server`、`order-service`、`storage-service` 和 `business-service` 这三个应用的 Main 函数,启动示例。 + +启动示例后,通过 HTTP 的 GET 方法访问如下两个 URL,可以分别验证在 `business-service` 中 通过 RestTemplate 和 FeignClient 调用其他服务的场景。 + +```$xslt +http://127.0.0.1:18081/fescar/feign + +http://127.0.0.1:18081/fescar/rest +``` + +## 如何验证分布式事务成功? + +### Xid 信息是否成功传递 + +在 `account-server`、`order-service` 和 `storage-service` 三个 服务的 Controller 中,第一个执行的逻辑都是输出 RootContext 中的 Xid 信息,如果看到都输出了正确的 Xid 信息,即每次都发生变化,且同一次调用中所有服务的 Xid 都一致。则表明 Fescar 的 Xid 的传递和还原是正常的。 + +### 数据库中数据是否一致 + +在本示例中,我们模拟了一个用户购买货物的场景,StorageService 负责扣减库存数量,OrderService 负责保存订单,AccountService 负责扣减用户账户余额。 + +为了演示样例,我们在 OrderService 和 AccountService 中 使用 Random.nextBoolean() 的方式来随机抛出异常,模拟了在服务调用时随机发生异常的场景。 + +如果分布式事务生效的话, 那么以下等式应该成立 + + +- 用户原始金额(1000) = 用户现存的金额 + 货物单价 (2) * 订单数量 * 每单的货物数量(2) + +- 货物的初始数量(100) = 货物的现存数量 + 订单数量 * 每单的货物数量(2) + +## 对 Spring Cloud 支持点 + +- 通过 Spring MVC 提供服务的服务提供者,在收到 header 中含有 Fescar 信息的 HTTP 请求时,可以自动还原 Fescar 上下文。 + +- 支持服务调用者通过 RestTemplate 调用时,自动传递 Fescar 上下文。 + +- 支持服务调用者通过 FeignClient 调用时,自动传递 Fescar 上下文。 + +- 支持 FeignClient 和 Hystrix 同时使用的场景。 + +- 支持 FeignClient 和 Sentinel 同时使用的场景。 \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml new file mode 100644 index 000000000..bcdca22c0 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml @@ -0,0 +1,68 @@ + + + + spring-cloud-alibaba-examples + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../../pom.xml + + 4.0.0 + storage-service + + + + org.springframework.cloud + spring-cloud-starter-alibaba-fescar + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + com.alibaba + druid + 1.1.10 + + + org.springframework.boot + spring-boot-starter-jdbc + + + + mysql + mysql-connector-java + + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.codehaus.mojo + cobertura-maven-plugin + false + + true + + + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java new file mode 100644 index 000000000..2973f21ae --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import java.sql.SQLException; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.fescar.rm.datasource.DataSourceProxy; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * @author xiaojing + */ +@Configuration +public class DatabaseConfiguration { + + private final ApplicationContext applicationContext; + + public DatabaseConfiguration(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean(initMethod = "init", destroyMethod = "close") + public DruidDataSource storageDataSource() throws SQLException { + + Environment environment = applicationContext.getEnvironment(); + + String ip = environment.getProperty("mysql.server.ip"); + String port = environment.getProperty("mysql.server.port"); + String dbName = environment.getProperty("mysql.db.name"); + + String userName = environment.getProperty("mysql.user.name"); + String password = environment.getProperty("mysql.user.password"); + + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName); + druidDataSource.setUsername(userName); + druidDataSource.setPassword(password); + druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); + druidDataSource.setInitialSize(0); + druidDataSource.setMaxActive(180); + druidDataSource.setMaxWait(60000); + druidDataSource.setMinIdle(0); + druidDataSource.setValidationQuery("Select 'x' from DUAL"); + druidDataSource.setTestOnBorrow(false); + druidDataSource.setTestOnReturn(false); + druidDataSource.setTestWhileIdle(true); + druidDataSource.setTimeBetweenEvictionRunsMillis(60000); + druidDataSource.setMinEvictableIdleTimeMillis(25200000); + druidDataSource.setRemoveAbandoned(true); + druidDataSource.setRemoveAbandonedTimeout(1800); + druidDataSource.setLogAbandoned(true); + druidDataSource.setFilters("mergeStat"); + return druidDataSource; + } + + @Bean + public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) { + return new DataSourceProxy(druidDataSource); + } + + @Bean + public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) { + + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy); + + jdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'"); + jdbcTemplate.update( + "insert into storage_tbl(commodity_code, count) values ('C00321', 100)"); + + return jdbcTemplate; + + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java new file mode 100644 index 000000000..94bbac7f4 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author xiaojing + */ +@SpringBootApplication +public class StorageApplication { + + public static void main(String[] args) { + SpringApplication.run(StorageApplication.class, args); + } + +} diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java new file mode 100644 index 000000000..fd97ab2c8 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.cloud.examples; + +import com.alibaba.fescar.core.context.RootContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author xiaojing + */ +@RestController +public class StorageController { + + private static final Logger LOGGER = LoggerFactory.getLogger(StorageController.class); + + private static final String SUCCESS = "SUCCESS"; + private static final String FAIL = "FAIL"; + + private final JdbcTemplate jdbcTemplate; + + public StorageController(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @RequestMapping(value = "/storage/{commodityCode}/{count}", method = RequestMethod.GET, produces = "application/json") + public String echo(@PathVariable String commodityCode, @PathVariable int count) { + LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID()); + int result = jdbcTemplate.update( + "update storage_tbl set count = count - ? where commodity_code = ?", + new Object[] { count, commodityCode }); + LOGGER.info("Storage Service End ... "); + if (result == 1) { + return SUCCESS; + } + return FAIL; + } +} diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf new file mode 100644 index 000000000..4bc5989e1 --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf @@ -0,0 +1,30 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #thread factory for netty + thread-factory { + boss-thread-prefix = "NettyBoss" + worker-thread-prefix = "NettyServerNIOWorker" + server-executor-thread-prefix = "NettyServerBizHandler" + share-boss-worker = false + client-selector-thread-prefix = "NettyClientSelector" + client-selector-thread-size = 1 + client-worker-thread-prefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + boss-thread-size = 1 + #auto default pin or 8 + worker-thread-size = 8 + } +} +service { + #vgroup->rgroup + vgroup_mapping.storage-service-fescar-service-group = "localRgroup" + #only support single node + localRgroup.grouplist = "127.0.0.1:8091" + #degrade current not support + enableDegrade = false + #disable + disable = false +} diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties new file mode 100644 index 000000000..832eaecdf --- /dev/null +++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.application.name=storage-service +server.port=18082 + +mysql.server.ip=127.0.0.1 +mysql.server.port=3306 +mysql.db.name=demo + +mysql.user.name=xxxxx +mysql.user.password=xxxxx \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/pom.xml b/spring-cloud-alibaba-examples/pom.xml index 6e2790f97..6cd8e7311 100644 --- a/spring-cloud-alibaba-examples/pom.xml +++ b/spring-cloud-alibaba-examples/pom.xml @@ -29,6 +29,10 @@ ans-example/ans-consumer-feign-example ans-example/ans-consumer-ribbon-example ans-example/ans-provider-example + fescar-example/business-service + fescar-example/order-service + fescar-example/storage-service + fescar-example/account-service acm-example/acm-local-example rocketmq-example spring-cloud-bus-rocketmq-example diff --git a/spring-cloud-alibaba-fescar/pom.xml b/spring-cloud-alibaba-fescar/pom.xml new file mode 100644 index 000000000..15613f576 --- /dev/null +++ b/spring-cloud-alibaba-fescar/pom.xml @@ -0,0 +1,117 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba + 0.2.2.BUILD-SNAPSHOT + + 4.0.0 + + org.springframework.cloud + spring-cloud-alibaba-fescar + Spring Cloud Alibaba Fescar + + + + + com.alibaba.fescar + fescar-core + + + com.alibaba.fescar + fescar-common + + + com.alibaba.fescar + fescar-spring + + + com.alibaba.fescar + fescar-rm-datasource + + + + org.springframework.cloud + spring-cloud-starter-openfeign + provided + true + + + org.springframework.cloud + spring-cloud-starter-alibaba-sentinel + provided + true + + + + org.springframework.cloud + spring-cloud-commons + true + + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + provided + true + + + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-actuator + provided + true + + + + org.springframework.boot + spring-boot-actuator-autoconfigure + provided + true + + + + org.springframework.boot + spring-boot-configuration-processor + provided + true + + + + org.springframework.boot + spring-boot + provided + true + + + + org.springframework.boot + spring-boot-autoconfigure + provided + true + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java new file mode 100644 index 000000000..f7847d968 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author xiaojing + */ +@ConfigurationProperties("spring.cloud.alibaba.fescar") +public class FescarProperties { + + // todo support config Fescar server information + + /** + * Fescar tx service group.default is ${spring.application.name}-fescar-service-group. + */ + private String txServiceGroup; + + public String getTxServiceGroup() { + return txServiceGroup; + } + + public void setTxServiceGroup(String txServiceGroup) { + this.txServiceGroup = txServiceGroup; + } + +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java new file mode 100644 index 000000000..d876ad3bd --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar; + +import com.alibaba.fescar.spring.annotation.GlobalTransactionScanner; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +/** + * @author xiaojing + */ + +@Configuration +@EnableConfigurationProperties(FescarProperties.class) +public class GlobalTransactionAutoConfiguration { + + private final ApplicationContext applicationContext; + + private final FescarProperties fescarProperties; + + public GlobalTransactionAutoConfiguration(ApplicationContext applicationContext, + FescarProperties fescarProperties) { + this.applicationContext = applicationContext; + this.fescarProperties = fescarProperties; + } + + @Bean + public GlobalTransactionScanner globalTransactionScanner() { + + String applicationName = applicationContext.getEnvironment() + .getProperty("spring.application.name"); + + String txServiceGroup = fescarProperties.getTxServiceGroup(); + + if (StringUtils.isEmpty(txServiceGroup)) { + txServiceGroup = applicationName + "-fescar-service-group"; + fescarProperties.setTxServiceGroup(txServiceGroup); + } + + return new GlobalTransactionScanner(applicationName, txServiceGroup); + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java new file mode 100644 index 000000000..9d7b685c3 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * @author xiaojing + */ +final class FescarBeanPostProcessor implements BeanPostProcessor { + + private final FescarFeignObjectWrapper eagleEyeFeignObjectWrapper; + + FescarBeanPostProcessor(FescarFeignObjectWrapper eagleEyeFeignObjectWrapper) { + this.eagleEyeFeignObjectWrapper = eagleEyeFeignObjectWrapper; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return this.eagleEyeFeignObjectWrapper.wrap(bean); + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java new file mode 100644 index 000000000..39afc2792 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.cloud.openfeign.FeignContext; + +/** + * @author xiaojing + */ +public class FescarContextBeanPostProcessor implements BeanPostProcessor { + + private final BeanFactory beanFactory; + private FescarFeignObjectWrapper eagleEyeFeignObjectWrapper; + + FescarContextBeanPostProcessor(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof FeignContext && !(bean instanceof FescarFeignContext)) { + return new FescarFeignContext(getEagleEyeFeignObjectWrapper(), + (FeignContext) bean); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + private FescarFeignObjectWrapper getEagleEyeFeignObjectWrapper() { + if (this.eagleEyeFeignObjectWrapper == null) { + this.eagleEyeFeignObjectWrapper = this.beanFactory + .getBean(FescarFeignObjectWrapper.class); + } + return this.eagleEyeFeignObjectWrapper; + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java new file mode 100644 index 000000000..acab33ff9 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import org.springframework.beans.factory.BeanFactory; + +import feign.Feign; + +/** + * @author xiaojing + */ +final class FescarFeignBuilder { + + private FescarFeignBuilder() { + } + + static Feign.Builder builder(BeanFactory beanFactory) { + return Feign.builder().client(new FescarFeignClient(beanFactory)); + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java new file mode 100644 index 000000000..9fc9d527c --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.fescar.core.context.RootContext; + +import org.springframework.beans.factory.BeanFactory; + +import feign.Client; +import feign.Request; +import feign.Response; +import org.springframework.util.StringUtils; + +/** + * @author xiaojing + */ +public class FescarFeignClient implements Client { + + private final Client delegate; + private final BeanFactory beanFactory; + + FescarFeignClient(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + this.delegate = new Client.Default(null, null); + } + + FescarFeignClient(BeanFactory beanFactory, Client delegate) { + this.delegate = delegate; + this.beanFactory = beanFactory; + } + + @Override + public Response execute(Request request, Request.Options options) throws IOException { + + Request modifiedRequest = getModifyRequest(request); + + try { + return this.delegate.execute(modifiedRequest, options); + } + finally { + + } + } + + private Request getModifyRequest(Request request) { + + String xid = RootContext.getXID(); + + if (StringUtils.isEmpty(xid)) { + return request; + } + + Map> headers = new HashMap<>(); + headers.putAll(request.headers()); + + List fescarXid = new ArrayList<>(); + fescarXid.add(xid); + headers.put(RootContext.KEY_XID, fescarXid); + + return Request.create(request.method(), request.url(), headers, request.body(), + request.charset()); + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java new file mode 100644 index 000000000..cdf1f6863 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.openfeign.FeignAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import feign.Client; +import feign.Feign; + +/** + * @author xiaojing + */ + +@Configuration +@ConditionalOnClass(Client.class) +@AutoConfigureBefore(FeignAutoConfiguration.class) +public class FescarFeignClientAutoConfiguration { + + @Bean + @Scope("prototype") + @ConditionalOnClass(name = "com.netflix.hystrix.HystrixCommand") + @ConditionalOnProperty(name = "feign.hystrix.enabled", havingValue = "true") + Feign.Builder feignHystrixBuilder(BeanFactory beanFactory) { + return FescarHystrixFeignBuilder.builder(beanFactory); + } + + @Bean + @Scope("prototype") + @ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU") + @ConditionalOnProperty(name = "feign.sentinel.enabled", havingValue = "true") + Feign.Builder feignSentinelBuilder(BeanFactory beanFactory) { + return FescarSentinelFeignBuilder.builder(beanFactory); + } + + @Bean + @ConditionalOnMissingBean + @Scope("prototype") + Feign.Builder feignBuilder(BeanFactory beanFactory) { + return FescarFeignBuilder.builder(beanFactory); + } + + @Configuration + protected static class FeignBeanPostProcessorConfiguration { + + @Bean + FescarBeanPostProcessor eagleEyeBeanPostProcessor( + FescarFeignObjectWrapper eagleEyeFeignObjectWrapper) { + return new FescarBeanPostProcessor(eagleEyeFeignObjectWrapper); + } + + @Bean + FescarContextBeanPostProcessor eagleEyeContextBeanPostProcessor( + BeanFactory beanFactory) { + return new FescarContextBeanPostProcessor(beanFactory); + } + + @Bean + FescarFeignObjectWrapper eagleEyeFeignObjectWrapper(BeanFactory beanFactory) { + return new FescarFeignObjectWrapper(beanFactory); + } + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java new file mode 100644 index 000000000..1ae5ea8d4 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import java.util.HashMap; +import java.util.Map; + +import feign.Client; +import org.springframework.cloud.openfeign.FeignContext; + +/** + * + * @author xiaojing + */ +public class FescarFeignContext extends FeignContext { + + private final FescarFeignObjectWrapper fescarFeignObjectWrapper; + private final FeignContext delegate; + + FescarFeignContext(FescarFeignObjectWrapper eagleEyeFeignObjectWrapper, + FeignContext delegate) { + this.fescarFeignObjectWrapper = eagleEyeFeignObjectWrapper; + this.delegate = delegate; + } + + @Override + public T getInstance(String name, Class type) { + T object = this.delegate.getInstance(name, type); + if (object instanceof Client) { + return object; + } + return (T) this.fescarFeignObjectWrapper.wrap(object); + } + + @Override + public Map getInstances(String name, Class type) { + Map instances = this.delegate.getInstances(name, type); + if (instances == null) { + return null; + } + Map convertedInstances = new HashMap<>(); + for (Map.Entry entry : instances.entrySet()) { + if (entry.getValue() instanceof Client) { + convertedInstances.put(entry.getKey(), entry.getValue()); + } + else { + convertedInstances.put(entry.getKey(), + (T) this.fescarFeignObjectWrapper.wrap(entry.getValue())); + } + } + return convertedInstances; + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java new file mode 100644 index 000000000..9b42b2f98 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; + +import feign.Client; +import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory; +import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient; + +/** + * @author xiaojing + */ +public class FescarFeignObjectWrapper { + + private final BeanFactory beanFactory; + + private CachingSpringLoadBalancerFactory cachingSpringLoadBalancerFactory; + private SpringClientFactory springClientFactory; + + FescarFeignObjectWrapper(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + Object wrap(Object bean) { + if (bean instanceof Client && !(bean instanceof FescarFeignClient)) { + if (bean instanceof LoadBalancerFeignClient) { + LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean); + return new FescarLoadBalancerFeignClient(client.getDelegate(), factory(), + clientFactory(), this.beanFactory); + } + return new FescarFeignClient(this.beanFactory, (Client) bean); + } + return bean; + } + + CachingSpringLoadBalancerFactory factory() { + if (this.cachingSpringLoadBalancerFactory == null) { + this.cachingSpringLoadBalancerFactory = this.beanFactory + .getBean(CachingSpringLoadBalancerFactory.class); + } + return this.cachingSpringLoadBalancerFactory; + } + + SpringClientFactory clientFactory() { + if (this.springClientFactory == null) { + this.springClientFactory = this.beanFactory + .getBean(SpringClientFactory.class); + } + return this.springClientFactory; + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java new file mode 100644 index 000000000..b67a9d840 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import feign.Retryer; +import feign.hystrix.HystrixFeign; +import org.springframework.beans.factory.BeanFactory; + +import feign.Feign; + +/** + * @author xiaojing + */ +final class FescarHystrixFeignBuilder { + + private FescarHystrixFeignBuilder() { + } + + static Feign.Builder builder(BeanFactory beanFactory) { + return HystrixFeign.builder().retryer(Retryer.NEVER_RETRY) + .client(new FescarFeignClient(beanFactory)); + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java new file mode 100644 index 000000000..7f00d0585 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import java.io.IOException; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; + +import feign.Client; +import feign.Request; +import feign.Response; +import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory; +import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient; + +/** + * @author xiaojing + */ +public class FescarLoadBalancerFeignClient extends LoadBalancerFeignClient { + + private final BeanFactory beanFactory; + + FescarLoadBalancerFeignClient(Client delegate, + CachingSpringLoadBalancerFactory lbClientFactory, + SpringClientFactory clientFactory, BeanFactory beanFactory) { + super(wrap(delegate, beanFactory), lbClientFactory, clientFactory); + this.beanFactory = beanFactory; + } + + @Override + public Response execute(Request request, Request.Options options) throws IOException { + return super.execute(request, options); + } + + private static Client wrap(Client delegate, BeanFactory beanFactory) { + return (Client) new FescarFeignObjectWrapper(beanFactory).wrap(delegate); + } + +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.java new file mode 100644 index 000000000..42f632144 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.feign; + +import org.springframework.beans.factory.BeanFactory; + +import feign.Feign; +import feign.Retryer; +import feign.hystrix.HystrixFeign; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel; +import org.springframework.cloud.alibaba.sentinel.feign.SentinelFeign; + +/** + * @author xiaojing + */ +final class FescarSentinelFeignBuilder { + + private FescarSentinelFeignBuilder() { + } + + static Feign.Builder builder(BeanFactory beanFactory) { + return SentinelFeign.builder().retryer(Retryer.NEVER_RETRY) + .client(new FescarFeignClient(beanFactory)); + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java new file mode 100644 index 000000000..f7db4b0d9 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.fescar.feign.hystrix; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.netflix.hystrix.HystrixCommand; + +/** + * @author xiaojing + */ + +@Configuration +@ConditionalOnClass(HystrixCommand.class) +public class FescarHystrixAutoConfiguration { + + @Bean + FescarHystrixConcurrencyStrategy fescarHystrixConcurrencyStrategy() { + return new FescarHystrixConcurrencyStrategy(); + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java new file mode 100644 index 000000000..e21ff1680 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.fescar.feign.hystrix; + +import java.util.concurrent.Callable; + +import com.alibaba.fescar.core.context.RootContext; + +import com.netflix.hystrix.strategy.HystrixPlugins; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; + +/** + * @author xiaojing + */ +public class FescarHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy { + + private HystrixConcurrencyStrategy delegate; + + public FescarHystrixConcurrencyStrategy() { + this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy(); + HystrixPlugins.reset(); + HystrixPlugins.getInstance().registerConcurrencyStrategy(this); + } + + @Override + public Callable wrapCallable(Callable c) { + if (c instanceof FescarContextCallable) { + return c; + } + + Callable wrappedCallable; + if (this.delegate != null) { + wrappedCallable = this.delegate.wrapCallable(c); + } + else { + wrappedCallable = c; + } + if (wrappedCallable instanceof FescarContextCallable) { + return wrappedCallable; + } + + return new FescarContextCallable<>(wrappedCallable); + } + + private static class FescarContextCallable implements Callable { + + private final Callable actual; + private final String xid; + + FescarContextCallable(Callable actual) { + this.actual = actual; + this.xid = RootContext.getXID(); + } + + @Override + public K call() throws Exception { + try { + RootContext.bind(xid); + return actual.call(); + } + finally { + RootContext.unbind(); + } + } + + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java new file mode 100644 index 000000000..91191ed0d --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.rest; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ + +@Configuration +public class FescarRestTemplateAutoConfiguration { + + @Bean + public FescarRestTemplateInterceptor fescarRestTemplateInterceptor() { + return new FescarRestTemplateInterceptor(); + } + + @Autowired(required = false) + private Collection restTemplates; + + @Autowired + private FescarRestTemplateInterceptor fescarRestTemplateInterceptor; + + @PostConstruct + public void init() { + if (this.restTemplates != null) { + for (RestTemplate restTemplate : restTemplates) { + List interceptors = new ArrayList( + restTemplate.getInterceptors()); + interceptors.add(this.fescarRestTemplateInterceptor); + restTemplate.setInterceptors(interceptors); + } + } + } + +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java new file mode 100644 index 000000000..5a5b2a10a --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.rest; + +import java.io.IOException; + +import com.alibaba.fescar.core.context.RootContext; + +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; +import org.springframework.util.StringUtils; + +/** + * @author xiaojing + */ +public class FescarRestTemplateInterceptor implements ClientHttpRequestInterceptor { + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, + ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest); + + String xid = RootContext.getXID(); + + if (!StringUtils.isEmpty(xid)) { + requestWrapper.getHeaders().add(RootContext.KEY_XID, xid); + } + return clientHttpRequestExecution.execute(requestWrapper, bytes); + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java new file mode 100644 index 000000000..84ffee8e8 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.web; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.fescar.core.context.RootContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.HandlerInterceptor; + +/** + * @author xiaojing + * + * Fescar HandlerInterceptor, Convert Fescar information into + * @see com.alibaba.fescar.core.context.RootContext from http request's header in + * {@link org.springframework.web.servlet.HandlerInterceptor#preHandle(HttpServletRequest , HttpServletResponse , Object )}, + * And clean up Fescar information after servlet method invocation in + * {@link org.springframework.web.servlet.HandlerInterceptor#afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)} + */ +public class FescarHandlerInterceptor implements HandlerInterceptor { + + private static final Logger log = LoggerFactory + .getLogger(FescarHandlerInterceptor.class); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, + Object handler) throws Exception { + + String xid = RootContext.getXID(); + String rpcXid = request.getHeader(RootContext.KEY_XID); + if (log.isDebugEnabled()) { + log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid); + } + + if (xid == null && rpcXid != null) { + RootContext.bind(rpcXid); + if (log.isDebugEnabled()) { + log.debug("bind {} to RootContext", rpcXid); + } + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, + Object handler, Exception e) throws Exception { + + String rpcXid = request.getHeader(RootContext.KEY_XID); + + if (StringUtils.isEmpty(rpcXid)) { + return; + } + + String unbindXid = RootContext.unbind(); + if (log.isDebugEnabled()) { + log.debug("unbind {} from RootContext", unbindXid); + } + if (!rpcXid.equalsIgnoreCase(unbindXid)) { + log.warn("xid in change during RPC from {} to {}", rpcXid, unbindXid); + if (unbindXid != null) { + RootContext.bind(unbindXid); + log.warn("bind {} back to RootContext", unbindXid); + } + } + } + +} diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java new file mode 100644 index 000000000..c510b1ac7 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.fescar.web; + +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @author xiaojing + */ +public class FescarHandlerInterceptorConfiguration implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new FescarHandlerInterceptor()).addPathPatterns("/**"); + } +} diff --git a/spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..3560bcee4 --- /dev/null +++ b/spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories @@ -0,0 +1,7 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.alibaba.fescar.rest.FescarRestTemplateAutoConfiguration,\ +org.springframework.cloud.alibaba.fescar.web.FescarHandlerInterceptorConfiguration,\ +org.springframework.cloud.alibaba.fescar.GlobalTransactionAutoConfiguration,\ +org.springframework.cloud.alibaba.fescar.feign.FescarFeignClientAutoConfiguration,\ +org.springframework.cloud.alibaba.fescar.feign.hystrix.FescarHystrixAutoConfiguration + diff --git a/spring-cloud-starter-alibaba/pom.xml b/spring-cloud-starter-alibaba/pom.xml index 3c91f8d7c..c0de36447 100644 --- a/spring-cloud-starter-alibaba/pom.xml +++ b/spring-cloud-starter-alibaba/pom.xml @@ -16,6 +16,7 @@ spring-cloud-starter-alibaba-nacos-config-server spring-cloud-starter-alibaba-nacos-discovery spring-cloud-starter-alibaba-sentinel + spring-cloud-starter-alibaba-fescar spring-cloud-starter-stream-rocketmq spring-cloud-starter-bus-rocketmq diff --git a/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml new file mode 100644 index 000000000..8376bfc13 --- /dev/null +++ b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.springframework.cloud + spring-cloud-starter-alibaba + 0.2.2.BUILD-SNAPSHOT + + spring-cloud-starter-alibaba-fescar + Spring Cloud Starter Alibaba Fescar + + + + org.springframework.cloud + spring-cloud-alibaba-fescar + + + + From ef8d204f957f1d77e992bd174b9393ce4d89c64e Mon Sep 17 00:00:00 2001 From: flystar32 Date: Wed, 30 Jan 2019 16:39:17 +0800 Subject: [PATCH 30/50] rename --- .../fescar/feign/FescarBeanPostProcessor.java | 8 ++++---- .../fescar/feign/FescarContextBeanPostProcessor.java | 12 ++++++------ .../feign/FescarFeignClientAutoConfiguration.java | 10 +++++----- .../alibaba/fescar/feign/FescarFeignContext.java | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java index 9d7b685c3..02bd6c32a 100644 --- a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java @@ -24,16 +24,16 @@ import org.springframework.beans.factory.config.BeanPostProcessor; */ final class FescarBeanPostProcessor implements BeanPostProcessor { - private final FescarFeignObjectWrapper eagleEyeFeignObjectWrapper; + private final FescarFeignObjectWrapper fescarFeignObjectWrapper; - FescarBeanPostProcessor(FescarFeignObjectWrapper eagleEyeFeignObjectWrapper) { - this.eagleEyeFeignObjectWrapper = eagleEyeFeignObjectWrapper; + FescarBeanPostProcessor(FescarFeignObjectWrapper fescarFeignObjectWrapper) { + this.fescarFeignObjectWrapper = fescarFeignObjectWrapper; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return this.eagleEyeFeignObjectWrapper.wrap(bean); + return this.fescarFeignObjectWrapper.wrap(bean); } @Override diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java index 39afc2792..ffd8e88e7 100644 --- a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java @@ -27,7 +27,7 @@ import org.springframework.cloud.openfeign.FeignContext; public class FescarContextBeanPostProcessor implements BeanPostProcessor { private final BeanFactory beanFactory; - private FescarFeignObjectWrapper eagleEyeFeignObjectWrapper; + private FescarFeignObjectWrapper fescarFeignObjectWrapper; FescarContextBeanPostProcessor(BeanFactory beanFactory) { this.beanFactory = beanFactory; @@ -37,7 +37,7 @@ public class FescarContextBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof FeignContext && !(bean instanceof FescarFeignContext)) { - return new FescarFeignContext(getEagleEyeFeignObjectWrapper(), + return new FescarFeignContext(getFescarFeignObjectWrapper(), (FeignContext) bean); } return bean; @@ -49,11 +49,11 @@ public class FescarContextBeanPostProcessor implements BeanPostProcessor { return bean; } - private FescarFeignObjectWrapper getEagleEyeFeignObjectWrapper() { - if (this.eagleEyeFeignObjectWrapper == null) { - this.eagleEyeFeignObjectWrapper = this.beanFactory + private FescarFeignObjectWrapper getFescarFeignObjectWrapper() { + if (this.fescarFeignObjectWrapper == null) { + this.fescarFeignObjectWrapper = this.beanFactory .getBean(FescarFeignObjectWrapper.class); } - return this.eagleEyeFeignObjectWrapper; + return this.fescarFeignObjectWrapper; } } diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java index cdf1f6863..1cb2c0cbb 100644 --- a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java @@ -65,19 +65,19 @@ public class FescarFeignClientAutoConfiguration { protected static class FeignBeanPostProcessorConfiguration { @Bean - FescarBeanPostProcessor eagleEyeBeanPostProcessor( - FescarFeignObjectWrapper eagleEyeFeignObjectWrapper) { - return new FescarBeanPostProcessor(eagleEyeFeignObjectWrapper); + FescarBeanPostProcessor fescarBeanPostProcessor( + FescarFeignObjectWrapper fescarFeignObjectWrapper) { + return new FescarBeanPostProcessor(fescarFeignObjectWrapper); } @Bean - FescarContextBeanPostProcessor eagleEyeContextBeanPostProcessor( + FescarContextBeanPostProcessor fescarContextBeanPostProcessor( BeanFactory beanFactory) { return new FescarContextBeanPostProcessor(beanFactory); } @Bean - FescarFeignObjectWrapper eagleEyeFeignObjectWrapper(BeanFactory beanFactory) { + FescarFeignObjectWrapper fescarFeignObjectWrapper(BeanFactory beanFactory) { return new FescarFeignObjectWrapper(beanFactory); } } diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java index 1ae5ea8d4..bd8d2251a 100644 --- a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java +++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java @@ -31,9 +31,9 @@ public class FescarFeignContext extends FeignContext { private final FescarFeignObjectWrapper fescarFeignObjectWrapper; private final FeignContext delegate; - FescarFeignContext(FescarFeignObjectWrapper eagleEyeFeignObjectWrapper, + FescarFeignContext(FescarFeignObjectWrapper fescarFeignObjectWrapper, FeignContext delegate) { - this.fescarFeignObjectWrapper = eagleEyeFeignObjectWrapper; + this.fescarFeignObjectWrapper = fescarFeignObjectWrapper; this.delegate = delegate; } From 04908741bb96b0cd9d19b17890bd87cb61c60f54 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Wed, 30 Jan 2019 17:57:26 +0800 Subject: [PATCH 31/50] Update readme-zh.md --- spring-cloud-alibaba-examples/fescar-example/readme-zh.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-cloud-alibaba-examples/fescar-example/readme-zh.md b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md index be3919497..e93f6866e 100644 --- a/spring-cloud-alibaba-examples/fescar-example/readme-zh.md +++ b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md @@ -15,11 +15,11 @@ 1. 配置数据库 -1. Create UNDO_LOG table +1. 创建 UNDO_LOG 表 -1. Create tables for examples business +1. 创建 示例中 业务所需要的数据库表 -1. Start Fescar Server +1. 启动 Fescar Server ### 配置数据库 @@ -153,4 +153,4 @@ http://127.0.0.1:18081/fescar/rest - 支持 FeignClient 和 Hystrix 同时使用的场景。 -- 支持 FeignClient 和 Sentinel 同时使用的场景。 \ No newline at end of file +- 支持 FeignClient 和 Sentinel 同时使用的场景。 From a1ae7b50ed8c19ca2e260810d821f6f1e9f43f46 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 30 Jan 2019 16:25:59 -0500 Subject: [PATCH 32/50] Ignores broken test. --- .../AnsAutoServiceRegistrationIpNetworkInterfaceTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java index 0259c27b9..1f8ee29bb 100644 --- a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java @@ -25,6 +25,7 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.util.Enumeration; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -63,6 +64,7 @@ public class AnsAutoServiceRegistrationIpNetworkInterfaceTests { private InetUtils inetUtils; @Test + @Ignore public void contextLoads() throws Exception { assertNotNull("AnsRegistration was not created", registration); From 4a62526b2a77c70651455dd11dfb6b152d57d971 Mon Sep 17 00:00:00 2001 From: flystar32 Date: Thu, 31 Jan 2019 14:57:30 +0800 Subject: [PATCH 33/50] Fixes #333 ,make @EnableDiscoveryClient Optional --- .../alibaba/nacos/NacosDiscoveryAutoConfiguration.java | 4 +--- .../src/main/resources/META-INF/spring.factories | 5 ++--- .../cloud/alicloud/ans/AnsAutoConfiguration.java | 6 +----- .../src/main/resources/META-INF/spring.factories | 3 +-- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index ac2872808..cbdf71524 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -41,9 +41,7 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnNacosDiscoveryEnabled @ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent") @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class, - NacosDiscoveryClientAutoConfiguration.class }) -@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class) +@AutoConfigureAfter({ AutoServiceRegistrationAutoConfiguration.class }) public class NacosDiscoveryAutoConfiguration { @Bean diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories index 723407fe5..91d5ff599 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories @@ -1,6 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.nacos.NacosDiscoveryAutoConfiguration,\ org.springframework.cloud.alibaba.nacos.ribbon.RibbonNacosAutoConfiguration,\ - org.springframework.cloud.alibaba.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration -org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ -org.springframework.cloud.alibaba.nacos.NacosDiscoveryClientAutoConfiguration + org.springframework.cloud.alibaba.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\ + org.springframework.cloud.alibaba.nacos.NacosDiscoveryClientAutoConfiguration diff --git a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java index 8d0f0fe64..d5ab0935e 100644 --- a/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java +++ b/spring-cloud-alicloud-ans/src/main/java/org/springframework/cloud/alicloud/ans/AnsAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.cloud.alicloud.ans; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -28,7 +27,6 @@ import org.springframework.cloud.alicloud.ans.registry.AnsRegistration; import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry; import org.springframework.cloud.alicloud.context.ans.AnsProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; -import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -44,9 +42,7 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnClass(name = "org.springframework.boot.web.context.WebServerInitializedEvent") @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @ConditionalOnAnsEnabled -@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class, - AnsDiscoveryClientAutoConfiguration.class }) -@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class) +@AutoConfigureAfter(AutoServiceRegistrationAutoConfiguration.class) public class AnsAutoConfiguration { @Bean diff --git a/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories b/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories index f733a74e1..63f543297 100644 --- a/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alicloud-ans/src/main/resources/META-INF/spring.factories @@ -3,6 +3,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alicloud.ans.ribbon.RibbonAnsAutoConfiguration,\ org.springframework.cloud.alicloud.ans.AnsAutoConfiguration,\ org.springframework.cloud.alicloud.ans.migrate.MigrateEndpointAutoConfiguration,\ - org.springframework.cloud.alicloud.ans.migrate.MigrationAutoconfiguration -org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ + org.springframework.cloud.alicloud.ans.migrate.MigrationAutoconfiguration,\ org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration \ No newline at end of file From 450f1e826957331f287eeaacc8426f84386b9972 Mon Sep 17 00:00:00 2001 From: flystar32 Date: Thu, 31 Jan 2019 15:02:30 +0800 Subject: [PATCH 34/50] modify example to verify . --- .../cloud/alibaba/cloud/examples/ProviderApplication.java | 1 - .../cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java index 843f5cbe0..c8b4a1c2f 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java @@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RestController; * @author xiaojing */ @SpringBootApplication -@EnableDiscoveryClient public class ProviderApplication { public static void main(String[] args) { diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index cbdf71524..38396bb9f 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -41,7 +41,7 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnNacosDiscoveryEnabled @ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent") @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureAfter({ AutoServiceRegistrationAutoConfiguration.class }) +@AutoConfigureAfter(AutoServiceRegistrationAutoConfiguration.class) public class NacosDiscoveryAutoConfiguration { @Bean From 6296bd8b5da2b0db48d386b28300d3eb7f5966d7 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Thu, 31 Jan 2019 16:52:59 +0800 Subject: [PATCH 35/50] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 31 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/custom.md | 10 ++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 23 +++++++++++++++++ .github/ISSUE_TEMPLATE/question.md | 17 +++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/custom.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..8b2127692 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Which Component** +eg. Nacos Discovery, Sentinel + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. +e.g. MacOS 、Java8 、 Version 0.2.1.RELEASE diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md new file mode 100644 index 000000000..48d5f81fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -0,0 +1,10 @@ +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..42310f5f3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,23 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Which Component** +eg. Nacos Discovery, Sentinel + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000..a053ad182 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,17 @@ +--- +name: Question +about: how to ask an valid question +title: '' +labels: '' +assignees: '' + +--- + +**Which Component** +eg. Nacos Discovery, Sentinel + +**Describe what problem you have encountered** +A clear and concise description of what you want to do. + +**Describe what information you have read** +eg. I have read the reference doc of Sentinel From 0dd3a1fb483521e86706d2a7cda4204c58e39ae7 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Thu, 31 Jan 2019 16:58:43 +0800 Subject: [PATCH 36/50] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 3 +++ .github/ISSUE_TEMPLATE/custom.md | 10 ---------- .github/ISSUE_TEMPLATE/feature_request.md | 4 ++++ .github/ISSUE_TEMPLATE/question.md | 4 ++++ 4 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/custom.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8b2127692..5c2cb13c2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,6 +7,9 @@ assignees: '' --- +我们鼓励使用英文,如果不能直接使用,可以使用翻译软件,您仍旧可以保留中文原文。 +We recommend using English. If you are non-native English speaker, you can use the translation software. + **Which Component** eg. Nacos Discovery, Sentinel diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md deleted file mode 100644 index 48d5f81fa..000000000 --- a/.github/ISSUE_TEMPLATE/custom.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Custom issue template -about: Describe this issue template's purpose here. -title: '' -labels: '' -assignees: '' - ---- - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 42310f5f3..f4117418d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,6 +7,10 @@ assignees: '' --- +我们鼓励使用英文,如果不能直接使用,可以使用翻译软件,您仍旧可以保留中文原文。 +We recommend using English. If you are non-native English speaker, you can use the translation software. + + **Which Component** eg. Nacos Discovery, Sentinel diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index a053ad182..6ef2bf0a0 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -7,6 +7,10 @@ assignees: '' --- +我们鼓励使用英文,如果不能直接使用,可以使用翻译软件,您仍旧可以保留中文原文。 +We recommend using English. If you are non-native English speaker, you can use the translation software. + + **Which Component** eg. Nacos Discovery, Sentinel From 494e7ea117a213b12c82560be4dffa3357943d14 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 10:41:16 +0800 Subject: [PATCH 37/50] Update README.md --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 40e6fd242..ad4672cd7 100644 --- a/README.md +++ b/README.md @@ -20,21 +20,33 @@ With Spring Cloud Alibaba, you only need to add some annotations and a small amo * **Service registration and discovery**:Service can be registered and clients can discover the instances using Spring-managed beans, auto integration Ribbon. * **Distributed configuration**:support for externalized configuration in a distributed system, auto refresh when configuration changes. * **Event-driven**:support for building highly scalable event-driven microservices connected with shared messaging systems. +* **Distributed Transaction**:support for distributed transaction solution with high performance and ease of use. * **Alibaba Cloud Object Storage**:massive, secure, low-cost, and highly reliable cloud storage services. Support for storing and accessing any type of data in any application, anytime, anywhere. +* **Alibaba Cloud SchedulerX**:accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds. +* **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. + For more features, please refer to [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap.md). ## Components **[Sentinel](https://github.com/alibaba/Sentinel)**: Sentinel takes "traffic flow" as the breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability. -**[Nacos](https://github.com/alibaba/Nacos)**: an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. +**[Nacos](https://github.com/alibaba/Nacos)**: An easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. + +**[RocketMQ](https://rocketmq.apache.org/)**:A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability. + +**[Dubbo](https://github.com/apache/incubator-dubbo)**:A high-performance, Java based open source RPC framework. -**[RocketMQ](https://rocketmq.apache.org/)**:a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability. +**[Fescar](https://github.com/alibaba/fescar)**:A distributed transaction solution with high performance and ease of use for microservices architecture. -**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**:an application configuration center that enables you to centralize the management of application configurations, and accomplish real-time configuration push in a distributed environment. +**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**:An application configuration center that enables you to centralize the management of application configurations, and accomplish real-time configuration push in a distributed environment. **[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world. +**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers. + +**[Alibaba Cloud SchedulerX](https://www.aliyun.com/product/SchedulerX)**:accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds.. + For more features please refer to [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap.md). ## How to build From 41b3cb0968f4f1cfa4ce68878d8f536418bc0ffd Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 10:42:11 +0800 Subject: [PATCH 38/50] Update Roadmap.md --- Roadmap.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Roadmap.md b/Roadmap.md index 66cb84f66..7fa392b7e 100644 --- a/Roadmap.md +++ b/Roadmap.md @@ -32,8 +32,6 @@ Alibaba Cloud Object Storage Service, An encrypted and secure cloud storage serv A distributed task scheduling product developed by Alibaba Middleware team. It supports both periodical tasks and tasks to be triggered at specified time points. -More components will be supported by Spring Cloud Alibaba in the future, which may include but are not limited to the following: - **Dubbo** Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC framework. @@ -41,7 +39,3 @@ Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC f **Fescar** A distributed transaction solution with high performance and ease of use for microservices architecture. - -**Alibaba Cloud SLS** - -Aliyun Log Service is an all-in-one service for log-type data. It helps increase Operations & Management and operational efficiency, as well as build the processing capability to deal with massive logs. From 1d47d3859fcfded787390ea54d2620e3cc40cc31 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 10:42:57 +0800 Subject: [PATCH 39/50] Update Roadmap-zh.md --- Roadmap-zh.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Roadmap-zh.md b/Roadmap-zh.md index 78e09e0ed..5d49fb660 100644 --- a/Roadmap-zh.md +++ b/Roadmap-zh.md @@ -29,9 +29,6 @@ Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和 阿里中间件团队开发的一款分布式任务调度产品,支持周期性的任务与固定时间点触发任务。 - -## 即将加入的组件 - **Dubbo** Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。 @@ -40,6 +37,6 @@ Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。 -**Alibaba Cloud SLS** +**Alibaba Cloud SMS** -针对日志类数据的一站式服务,在阿里巴巴集团经历大量大数据场景锤炼而成。您无需开发就能快捷完成日志数据采集、消费、投递以及查询分析等功能,提升运维、运营效率,建立 DT 时代海量日志处理能力。 \ No newline at end of file +覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。 From 2cb7123f0080296d85d67dbca50708b0dd733a09 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 10:43:49 +0800 Subject: [PATCH 40/50] Update Roadmap-zh.md --- Roadmap-zh.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Roadmap-zh.md b/Roadmap-zh.md index 5d49fb660..8bf69a79d 100644 --- a/Roadmap-zh.md +++ b/Roadmap-zh.md @@ -17,18 +17,10 @@ Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解 阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 -**Alibaba Cloud OSS** - -阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 - **RocketMQ** Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和流计算平台。 -**Alibaba Cloud SchedulerX** - -阿里中间件团队开发的一款分布式任务调度产品,支持周期性的任务与固定时间点触发任务。 - **Dubbo** Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。 @@ -37,6 +29,14 @@ Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。 +**Alibaba Cloud OSS** + +阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 + +**Alibaba Cloud SchedulerX** + +阿里中间件团队开发的一款分布式任务调度产品,支持周期性的任务与固定时间点触发任务。 + **Alibaba Cloud SMS** 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。 From 744788fd6298929277941fb4628253c064a6f9f8 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 10:45:13 +0800 Subject: [PATCH 41/50] Update Roadmap.md --- Roadmap.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Roadmap.md b/Roadmap.md index 7fa392b7e..e7b99498d 100644 --- a/Roadmap.md +++ b/Roadmap.md @@ -24,6 +24,14 @@ An opensource project of Alibaba, an easy-to-use dynamic service discovery, conf Apache RocketMQ™ is an open source distributed messaging and streaming data platform. +**Dubbo** + +Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC framework. + +**Fescar** + +A distributed transaction solution with high performance and ease of use for microservices architecture. + **Alibaba Cloud OSS** Alibaba Cloud Object Storage Service, An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world. @@ -32,10 +40,7 @@ Alibaba Cloud Object Storage Service, An encrypted and secure cloud storage serv A distributed task scheduling product developed by Alibaba Middleware team. It supports both periodical tasks and tasks to be triggered at specified time points. -**Dubbo** - -Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC framework. +**Alibaba Cloud SMS** -**Fescar** +A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers. -A distributed transaction solution with high performance and ease of use for microservices architecture. From fe66f83da5e9a2afdd94e69f9895732eb7550fbe Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 11:21:48 +0800 Subject: [PATCH 42/50] Update README-zh.md --- README-zh.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README-zh.md b/README-zh.md index c76e149e2..951094497 100644 --- a/README-zh.md +++ b/README-zh.md @@ -19,8 +19,10 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。 * **服务注册与发现**:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。 * **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。 * **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。 +* **分布式事务**:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。。 * **阿里云对象存储**:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。 * **分布式任务调度**:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。 +* **阿里云短信服务**:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。 更多功能请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 @@ -33,11 +35,17 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。 **[RocketMQ](https://rocketmq.apache.org/)**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。 +**[Dubbo](https://github.com/apache/incubator-dubbo)**:Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。 + +**[Fescar](https://github.com/alibaba/fescar)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。 + **[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。 **[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 -**[Alibaba Cloud SchedulerX](https://help.aliyun.com/document_detail/43136.html?spm=a2c4g.11186623.6.709.baef7da9QVICiD)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。 +**[Alibaba Cloud SchedulerX](https://help.aliyun.com/document_detail/43136.html)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。 + +**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。 更多组件请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 From c5fa7068a4dda4dd90599a43b0f1db32d877d854 Mon Sep 17 00:00:00 2001 From: xiaojing Date: Fri, 1 Feb 2019 11:28:10 +0800 Subject: [PATCH 43/50] Update README-zh.md --- README-zh.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README-zh.md b/README-zh.md index 951094497..bfe834aaa 100644 --- a/README-zh.md +++ b/README-zh.md @@ -108,6 +108,8 @@ Example 列表: [RocketMQ Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md) +[Fescar Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/fescar-example/readme-zh.md) + [Alibaba Cloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme-zh.md) [Alibaba Cloud ANS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/ans-example/ans-provider-example/readme-zh.md) From e6a1ba09fbc1c9d097e6af3e9ec574fd382681b6 Mon Sep 17 00:00:00 2001 From: flystar32 Date: Fri, 1 Feb 2019 12:48:43 +0800 Subject: [PATCH 44/50] Fixes #331 --- .../AnsAutoServiceRegistrationIpNetworkInterfaceTests.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java index 1f8ee29bb..7a31f30d7 100644 --- a/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java +++ b/spring-cloud-alicloud-ans/src/test/java/org/springframework/cloud/alicloud/ans/registry/AnsAutoServiceRegistrationIpNetworkInterfaceTests.java @@ -64,7 +64,6 @@ public class AnsAutoServiceRegistrationIpNetworkInterfaceTests { private InetUtils inetUtils; @Test - @Ignore public void contextLoads() throws Exception { assertNotNull("AnsRegistration was not created", registration); @@ -132,7 +131,7 @@ public class AnsAutoServiceRegistrationIpNetworkInterfaceTests { hasValidNetworkInterface = true; netWorkInterfaceName = networkInterface.getName(); System.setProperty( - "spring.cloud.alicloud.ans.client-interface-ame", + "spring.cloud.alicloud.ans.client-interface-name", networkInterface.getName()); break; } From fd6d3a771715b8bbb8df370856932732e6342ed8 Mon Sep 17 00:00:00 2001 From: fangjian0423 Date: Fri, 1 Feb 2019 14:04:54 +0800 Subject: [PATCH 45/50] remove sentinel commercialization logic & optimize NacosDataSource --- .../SentinelDataSourceConstants.java | 10 -- .../config/NacosDataSourceProperties.java | 51 +----- .../NacosDataSourceFactoryBean.java | 16 +- .../NacosDataSourcePropertiesTests.java | 67 -------- ...cePropertiesWithSystemPropertiesTests.java | 151 ------------------ .../custom/SentinelDataSourceHandler.java | 39 ----- 6 files changed, 16 insertions(+), 318 deletions(-) delete mode 100644 spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesWithSystemPropertiesTests.java diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceConstants.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceConstants.java index 8903b700b..345b443db 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceConstants.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceConstants.java @@ -23,14 +23,4 @@ public interface SentinelDataSourceConstants { String PROPERTY_PREFIX = "spring.cloud.sentinel"; - String NACOS_DATASOURCE_AK = PROPERTY_PREFIX + ".nacos.config.access-key"; - - String NACOS_DATASOURCE_SK = PROPERTY_PREFIX + ".nacos.config.secret-key"; - - String NACOS_DATASOURCE_NAMESPACE = PROPERTY_PREFIX + ".nacos.config.namespace"; - - String NACOS_DATASOURCE_ENDPOINT = PROPERTY_PREFIX + ".nacos.config.endpoint"; - - String PROJECT_NAME = PROPERTY_PREFIX + ".nacos.config.project-name"; - } diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java index 353d4fab7..f8bf8528b 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/config/NacosDataSourceProperties.java @@ -2,8 +2,6 @@ package org.springframework.cloud.alibaba.sentinel.datasource.config; import javax.validation.constraints.NotEmpty; -import org.springframework.cloud.alibaba.sentinel.datasource.RuleType; -import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants; import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean; import org.springframework.util.StringUtils; @@ -18,13 +16,11 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { private String serverAddr; @NotEmpty - private String groupId; + private String groupId = "DEFAULT_GROUP"; @NotEmpty private String dataId; - // commercialized usage - private String endpoint; private String namespace; private String accessKey; @@ -36,17 +32,9 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { @Override public void preCheck(String dataSourceName) { - if (!StringUtils.isEmpty(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) { - this.setServerAddr(null); - this.setEndpoint(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT)); - this.setNamespace(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE)); - this.setAccessKey(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK)); - this.setSecretKey(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK)); + if (StringUtils.isEmpty(serverAddr) && acmPropertiesInvalid()) { + throw new IllegalArgumentException( + "NacosDataSource properties value not correct. serverAddr is empty but there is empty value in accessKey, secretKey, endpoint, namespace property"); } } @@ -106,34 +94,9 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties { this.secretKey = secretKey; } - public static NacosDataSourceProperties buildFlowByEDAS() { - return buildByEDAS("flow"); - } - - public static NacosDataSourceProperties buildDegradeByEDAS() { - return buildByEDAS("degrade"); + public boolean acmPropertiesInvalid() { + return StringUtils.isEmpty(endpoint) || StringUtils.isEmpty(accessKey) + || StringUtils.isEmpty(secretKey) || StringUtils.isEmpty(namespace); } - public static NacosDataSourceProperties buildByEDAS(String type) { - NacosDataSourceProperties result = new NacosDataSourceProperties(); - result.setEndpoint(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT)); - result.setNamespace(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE)); - result.setAccessKey(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK)); - result.setSecretKey(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK)); - result.setDataType("json"); - result.setDataId(System.getProperties() - .getProperty(SentinelDataSourceConstants.PROJECT_NAME) + "-" + type); - result.setGroupId("nacos-sentinel"); - if (type.equals(RuleType.FLOW.getName())) { - result.setRuleType(RuleType.FLOW); - } - else { - result.setRuleType(RuleType.DEGRADE); - } - return result; - } } diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java index 58b4d9209..7d4e65b48 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java @@ -3,7 +3,6 @@ package org.springframework.cloud.alibaba.sentinel.datasource.factorybean; import java.util.Properties; import org.springframework.beans.factory.FactoryBean; -import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants; import org.springframework.util.StringUtils; import com.alibaba.csp.sentinel.datasource.Converter; @@ -30,16 +29,19 @@ public class NacosDataSourceFactoryBean implements FactoryBean @Override public NacosDataSource getObject() throws Exception { - if (!StringUtils.isEmpty(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) { - Properties properties = new Properties(); + Properties properties = new Properties(); + if (!StringUtils.isEmpty(this.serverAddr)) { + properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr); + } + else { properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey); - properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.secretKey); + properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey); properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint); + } + if (!StringUtils.isEmpty(this.namespace)) { properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace); - return new NacosDataSource(properties, groupId, dataId, converter); } - return new NacosDataSource(serverAddr, groupId, dataId, converter); + return new NacosDataSource(properties, groupId, dataId, converter); } @Override diff --git a/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesTests.java b/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesTests.java index 51f3a1f71..fd2a157ca 100644 --- a/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesTests.java +++ b/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesTests.java @@ -17,7 +17,6 @@ package org.springframework.cloud.alibaba.sentinel.datasource; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import org.junit.Test; import org.springframework.cloud.alibaba.sentinel.datasource.config.NacosDataSourceProperties; @@ -71,70 +70,4 @@ public class NacosDataSourcePropertiesTests { nacosDataSourceProperties.getRuleType()); } - @Test - public void testNacosWithEDASAndWithoutSystemProperties() { - NacosDataSourceProperties nacosDataSourceProperties = NacosDataSourceProperties - .buildByEDAS(RuleType.DEGRADE.getName()); - assertEquals("Nacos groupId was wrong", "nacos-sentinel", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", "null-" + RuleType.DEGRADE.getName(), - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos rule type was wrong", RuleType.DEGRADE, - nacosDataSourceProperties.getRuleType()); - assertNull("Nacos ak was not null", nacosDataSourceProperties.getAccessKey()); - assertNull("Nacos sk was not null", nacosDataSourceProperties.getSecretKey()); - assertNull("Nacos endpoint was not null", - nacosDataSourceProperties.getEndpoint()); - assertNull("Nacos namespace was not null", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - } - - @Test - public void testNacosWithEDASDegradeAndWithoutSystemProperties() { - NacosDataSourceProperties nacosDataSourceProperties = NacosDataSourceProperties - .buildDegradeByEDAS(); - assertEquals("Nacos groupId was wrong", "nacos-sentinel", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", "null-" + RuleType.DEGRADE.getName(), - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos rule type was wrong", RuleType.DEGRADE, - nacosDataSourceProperties.getRuleType()); - assertNull("Nacos ak was not null", nacosDataSourceProperties.getAccessKey()); - assertNull("Nacos sk was not null", nacosDataSourceProperties.getSecretKey()); - assertNull("Nacos endpoint was not null", - nacosDataSourceProperties.getEndpoint()); - assertNull("Nacos namespace was not null", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - } - - @Test - public void testNacosWithEDASFlowAndWithoutSystemProperties() { - NacosDataSourceProperties nacosDataSourceProperties = NacosDataSourceProperties - .buildFlowByEDAS(); - assertEquals("Nacos groupId was wrong", "nacos-sentinel", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", "null-" + RuleType.FLOW.getName(), - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos rule type was wrong", RuleType.FLOW, - nacosDataSourceProperties.getRuleType()); - assertNull("Nacos ak was not null", nacosDataSourceProperties.getAccessKey()); - assertNull("Nacos sk was not null", nacosDataSourceProperties.getSecretKey()); - assertNull("Nacos endpoint was not null", - nacosDataSourceProperties.getEndpoint()); - assertNull("Nacos namespace was not null", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - } - } diff --git a/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesWithSystemPropertiesTests.java b/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesWithSystemPropertiesTests.java deleted file mode 100644 index 7537f3b8b..000000000 --- a/spring-cloud-alibaba-sentinel-datasource/src/test/java/org/springframework/cloud/alibaba/sentinel/datasource/NacosDataSourcePropertiesWithSystemPropertiesTests.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.alibaba.sentinel.datasource; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.junit.Test; -import org.springframework.cloud.alibaba.sentinel.datasource.config.NacosDataSourceProperties; - -/** - * @author Jim - */ -public class NacosDataSourcePropertiesWithSystemPropertiesTests { - - @Test - public void testNacosWithSystemProperties() { - setSystemProperties(); - - NacosDataSourceProperties nacosDataSourceProperties = new NacosDataSourceProperties(); - nacosDataSourceProperties.setServerAddr("127.0.0.1:8848"); - nacosDataSourceProperties.setGroupId("custom-group"); - nacosDataSourceProperties.setDataId("sentinel"); - nacosDataSourceProperties.preCheck("test-ds"); - - assertEquals("Nacos groupId was wrong", "custom-group", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", "sentinel", - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos ak was wrong", "ak", - nacosDataSourceProperties.getAccessKey()); - assertEquals("Nacos sk was wrong", "sk", - nacosDataSourceProperties.getSecretKey()); - assertEquals("Nacos endpoint was wrong", "endpoint", - nacosDataSourceProperties.getEndpoint()); - assertEquals("Nacos namespace was wrong", "namespace", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - - } - - @Test - public void testNacosWithEDASAndSystemProperties() { - setSystemProperties(); - - NacosDataSourceProperties nacosDataSourceProperties = NacosDataSourceProperties - .buildByEDAS(RuleType.FLOW.getName()); - - assertEquals("Nacos groupId was wrong", "nacos-sentinel", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", "project-name-" + RuleType.FLOW.getName(), - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos rule type was wrong", RuleType.FLOW, - nacosDataSourceProperties.getRuleType()); - assertEquals("Nacos ak was wrong", "ak", - nacosDataSourceProperties.getAccessKey()); - assertEquals("Nacos sk was wrong", "sk", - nacosDataSourceProperties.getSecretKey()); - assertEquals("Nacos endpoint was wrong", "endpoint", - nacosDataSourceProperties.getEndpoint()); - assertEquals("Nacos namespace was wrong", "namespace", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - - } - - @Test - public void testNacosWithEDASDegradeAndSystemProperties() { - setSystemProperties(); - - NacosDataSourceProperties nacosDataSourceProperties = NacosDataSourceProperties - .buildDegradeByEDAS(); - assertEquals("Nacos groupId was wrong", "nacos-sentinel", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", - "project-name-" + RuleType.DEGRADE.getName(), - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos rule type was wrong", RuleType.DEGRADE, - nacosDataSourceProperties.getRuleType()); - assertEquals("Nacos ak was wrong", "ak", - nacosDataSourceProperties.getAccessKey()); - assertEquals("Nacos sk was wrong", "sk", - nacosDataSourceProperties.getSecretKey()); - assertEquals("Nacos endpoint was wrong", "endpoint", - nacosDataSourceProperties.getEndpoint()); - assertEquals("Nacos namespace was wrong", "namespace", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - - } - - @Test - public void testNacosWithEDASFlowAndSystemProperties() { - setSystemProperties(); - - NacosDataSourceProperties nacosDataSourceProperties = NacosDataSourceProperties - .buildFlowByEDAS(); - assertEquals("Nacos groupId was wrong", "nacos-sentinel", - nacosDataSourceProperties.getGroupId()); - assertEquals("Nacos dataId was wrong", "project-name-" + RuleType.FLOW.getName(), - nacosDataSourceProperties.getDataId()); - assertEquals("Nacos default data type was wrong", "json", - nacosDataSourceProperties.getDataType()); - assertEquals("Nacos rule type was wrong", RuleType.FLOW, - nacosDataSourceProperties.getRuleType()); - assertEquals("Nacos ak was wrong", "ak", - nacosDataSourceProperties.getAccessKey()); - assertEquals("Nacos sk was wrong", "sk", - nacosDataSourceProperties.getSecretKey()); - assertEquals("Nacos endpoint was wrong", "endpoint", - nacosDataSourceProperties.getEndpoint()); - assertEquals("Nacos namespace was wrong", "namespace", - nacosDataSourceProperties.getNamespace()); - assertNull("Nacos serverAddr was not null", - nacosDataSourceProperties.getServerAddr()); - } - - private void setSystemProperties() { - System.setProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT, - "endpoint"); - System.setProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE, - "namespace"); - System.setProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK, "ak"); - System.setProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK, "sk"); - System.setProperty(SentinelDataSourceConstants.PROJECT_NAME, "project-name"); - } - -} diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java index a6cf6dfa3..f781a4ab6 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,12 +13,8 @@ import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.cloud.alibaba.sentinel.SentinelConstants; import org.springframework.cloud.alibaba.sentinel.SentinelProperties; -import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants; import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties; -import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration; -import org.springframework.cloud.alibaba.sentinel.datasource.config.NacosDataSourceProperties; import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter; import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter; import org.springframework.util.CollectionUtils; @@ -29,8 +24,6 @@ import org.springframework.util.StringUtils; import com.alibaba.csp.sentinel.datasource.AbstractDataSource; import com.alibaba.csp.sentinel.datasource.ReadableDataSource; import com.alibaba.csp.sentinel.slots.block.AbstractRule; -import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; -import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; /** * Sentinel {@link ReadableDataSource} Handler Handle the configurations of @@ -63,27 +56,6 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton { @Override public void afterSingletonsInstantiated() { - // commercialization - if (!StringUtils.isEmpty(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) { - Map newDataSourceMap = new TreeMap<>( - String.CASE_INSENSITIVE_ORDER); - for (Map.Entry entry : sentinelProperties - .getDatasource().entrySet()) { - if (entry.getValue().getValidDataSourceProperties() - .getClass() != NacosDataSourceProperties.class) { - newDataSourceMap.put(entry.getKey(), entry.getValue()); - } - } - newDataSourceMap.put(SentinelConstants.FLOW_DATASOURCE_NAME, - new DataSourcePropertiesConfiguration( - NacosDataSourceProperties.buildFlowByEDAS())); - newDataSourceMap.put(SentinelConstants.DEGRADE_DATASOURCE_NAME, - new DataSourcePropertiesConfiguration( - NacosDataSourceProperties.buildDegradeByEDAS())); - sentinelProperties.setDatasource(newDataSourceMap); - } - sentinelProperties.getDatasource() .forEach((dataSourceName, dataSourceProperties) -> { try { @@ -214,17 +186,6 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton { // register property in RuleManager dataSourceProperties.postRegister(newDataSource); - - // commercialization - if (!StringUtils.isEmpty(System.getProperties() - .getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) { - if (dataSourceName.contains(SentinelConstants.FLOW_DATASOURCE_NAME)) { - FlowRuleManager.register2Property(newDataSource.getProperty()); - } - else if (dataSourceName.contains(SentinelConstants.DEGRADE_DATASOURCE_NAME)) { - DegradeRuleManager.register2Property(newDataSource.getProperty()); - } - } } private void logAndCheckRuleType(AbstractDataSource dataSource, String dataSourceName, From ff6e68d522f1169a773e86925a0ca5736167f4da Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 1 Feb 2019 22:33:47 +0800 Subject: [PATCH 46/50] Update Dubbo Spring Boot 0.2.1.RELEASE --- spring-cloud-alibaba-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index 9c55f47f5..9034205a6 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -30,7 +30,7 @@ 4.3.1 2.1.6 2.6.5 - 0.2.1-SNAPSHOT + 0.2.1.RELEASE 0.0.2 1.1.0 1.1.8 From 8d44c7ee01387900d2fee79c29dc0432e305bc8c Mon Sep 17 00:00:00 2001 From: carlWangTao Date: Tue, 12 Feb 2019 09:51:40 +0800 Subject: [PATCH 47/50] Update NacosDiscoveryProperties.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当配置属性cloud.nacos.discovery.server-addr以 '/' 结束会造成服务提供方无法注册到NacosServer --- .../cloud/alibaba/nacos/NacosDiscoveryProperties.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java index 775a502b6..ed4ff36e6 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java @@ -149,6 +149,9 @@ public class NacosDiscoveryProperties { } serverAddr = Objects.toString(serverAddr, ""); + if(serverAddr.lastIndexOf("/") != -1) { + serverAddr.substring(0,serverAddr.length()-1); + } endpoint = Objects.toString(endpoint, ""); namespace = Objects.toString(namespace, ""); logName = Objects.toString(logName, ""); From 910068c91fbfae6996ad19c8bbb1ff043a530234 Mon Sep 17 00:00:00 2001 From: xiaolongzuo <150349407@qq.com> Date: Wed, 13 Feb 2019 17:16:52 +0800 Subject: [PATCH 48/50] Add test case. --- spring-cloud-alicloud-context/pom.xml | 14 +++ .../AbstractOnceApplicationListener.java | 5 +- .../nacos/NacosParameterInitListener.java | 6 +- .../oss/OssContextAutoConfiguration.java | 2 + .../scx/ScxContextAutoConfiguration.java | 8 +- .../context/sms/SmsConfigProperties.java | 107 ------------------ .../context/sms/SmsConfigRegistration.java | 26 ----- .../sms/SmsContextAutoConfiguration.java | 22 +--- .../alicloud/context/sms/SmsProperties.java | 74 ++++++++++++ .../statistics/StatisticsTaskStarter.java | 8 ++ .../datasource/nacos/NacosDataSource.java | 23 ++++ .../model/v20170525/SendSmsRequest.java | 23 ++++ .../nacos/NacosConfigAutoConfiguration.java | 23 ++++ ...ava => BaseAliCloudSpringApplication.java} | 29 +++-- .../AnsContextApplicationListenerTests.java | 37 ++++++ .../context/ans/AnsPropertiesTests.java | 50 +++++++- .../NacosParameterInitListenerTests.java | 58 ++++++++++ .../oss/OssAutoConfigurationTests.java | 40 ++++++- .../SentinelAliCloudListenerTests.java | 56 +++++++++ .../context/sms/SmsPropertiesTests.java | 69 +++++++++++ .../alicloud/utils/ChangeOrderUtils.java | 54 +++++++++ .../alicloud/sms/AbstractSmsService.java | 5 +- .../sms/SmsInitializerEventListener.java | 10 +- .../cloud/alicloud/sms/SmsServiceImpl.java | 53 +++++---- .../sms/config/SmsAutoConfiguration.java | 12 +- 25 files changed, 600 insertions(+), 214 deletions(-) delete mode 100644 spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java delete mode 100644 spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java create mode 100644 spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsProperties.java create mode 100644 spring-cloud-alicloud-context/src/test/java/com/alibaba/csp/sentinel/datasource/nacos/NacosDataSource.java create mode 100644 spring-cloud-alicloud-context/src/test/java/com/aliyuncs/dysmsapi/model/v20170525/SendSmsRequest.java create mode 100644 spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java rename spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/{AliCloudSpringApplicationTests.java => BaseAliCloudSpringApplication.java} (62%) create mode 100644 spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsContextApplicationListenerTests.java create mode 100644 spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListenerTests.java create mode 100644 spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sentinel/SentinelAliCloudListenerTests.java create mode 100644 spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sms/SmsPropertiesTests.java create mode 100644 spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/utils/ChangeOrderUtils.java diff --git a/spring-cloud-alicloud-context/pom.xml b/spring-cloud-alicloud-context/pom.xml index 496aea377..b87d920d9 100644 --- a/spring-cloud-alicloud-context/pom.xml +++ b/spring-cloud-alicloud-context/pom.xml @@ -113,6 +113,20 @@ test + + org.powermock + powermock-module-junit4 + 2.0.0 + test + + + + org.powermock + powermock-api-mockito2 + 2.0.0 + test + + diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/listener/AbstractOnceApplicationListener.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/listener/AbstractOnceApplicationListener.java index d8b822a9b..dbe554d99 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/listener/AbstractOnceApplicationListener.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/listener/AbstractOnceApplicationListener.java @@ -42,9 +42,8 @@ public abstract class AbstractOnceApplicationListener { private static final Logger log = LoggerFactory @@ -33,7 +36,8 @@ public class NacosParameterInitListener log.info("Initialize Nacos Parameter from edas change order,is edas managed {}.", edasChangeOrderConfiguration.isEdasManaged()); - + System.getProperties().setProperty("spring.cloud.nacos.config.server-mode", + "EDAS"); // initialize nacos configuration System.getProperties().setProperty("spring.cloud.nacos.config.server-addr", ""); System.getProperties().setProperty("spring.cloud.nacos.config.endpoint", diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/oss/OssContextAutoConfiguration.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/oss/OssContextAutoConfiguration.java index 0a3e13092..f197a0f08 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/oss/OssContextAutoConfiguration.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/oss/OssContextAutoConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.cloud.alicloud.context.oss; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.alicloud.context.AliCloudContextAutoConfiguration; import org.springframework.cloud.alicloud.context.AliCloudProperties; @@ -39,6 +40,7 @@ import com.aliyun.oss.OSSClientBuilder; */ @Configuration @ConditionalOnClass(name = "org.springframework.cloud.alicloud.oss.OssAutoConfiguration") +@ConditionalOnProperty(name = "spring.cloud.alicloud.oss.enabled", matchIfMissing = true) @EnableConfigurationProperties(OssProperties.class) @ImportAutoConfiguration(AliCloudContextAutoConfiguration.class) public class OssContextAutoConfiguration { diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/scx/ScxContextAutoConfiguration.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/scx/ScxContextAutoConfiguration.java index a2b738fd9..2953858c5 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/scx/ScxContextAutoConfiguration.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/scx/ScxContextAutoConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.cloud.alicloud.context.scx; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.alicloud.context.AliCloudProperties; import org.springframework.cloud.alicloud.context.edas.EdasContextAutoConfiguration; @@ -35,6 +36,7 @@ import com.alibaba.edas.schedulerx.SchedulerXClient; */ @Configuration @ConditionalOnClass(name = "org.springframework.cloud.alicloud.scx.ScxAutoConfiguration") +@ConditionalOnProperty(name = "spring.cloud.alicloud.scx.enabled", matchIfMissing = true) @EnableConfigurationProperties(ScxProperties.class) @ImportAutoConfiguration(EdasContextAutoConfiguration.class) public class ScxContextAutoConfiguration { @@ -42,10 +44,10 @@ public class ScxContextAutoConfiguration { @Bean(initMethod = "init") @ConditionalOnMissingBean public SchedulerXClient schedulerXClient(AliCloudProperties aliCloudProperties, - EdasProperties edasProperties, ScxProperties scxProperties, - AliCloudEdasSdk aliCloudEdasSdk) { + EdasProperties edasProperties, ScxProperties scxProperties, + AliCloudEdasSdk aliCloudEdasSdk) { return AliCloudScxInitializer.initialize(aliCloudProperties, edasProperties, - scxProperties, aliCloudEdasSdk); + scxProperties, aliCloudEdasSdk); } } diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java deleted file mode 100644 index 022c5e19d..000000000 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigProperties.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.springframework.cloud.alicloud.context.sms; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.alicloud.context.AliCloudProperties; -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - -import java.io.Serializable; - -/** - * @author pbting - */ -@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms") -public class SmsConfigProperties implements Serializable { - - // 产品名称:云通信短信API产品,开发者无需替换 - public static final String smsProduct = "Dysmsapi"; - // 产品域名,开发者无需替换 - public static final String smsDomain = "dysmsapi.aliyuncs.com"; - - private AliCloudProperties aliCloudProperties; - - /** - * - */ - private String reportQueueName; - /** - * - */ - private String upQueueName; - - /** - * - */ - protected String connnectTimeout = "10000"; - - /** - * - */ - protected String readTimeout = "10000"; - - public SmsConfigProperties(AliCloudProperties aliCloudProperties) { - this.aliCloudProperties = aliCloudProperties; - } - - public String getConnnectTimeout() { - return connnectTimeout; - } - - public void setConnnectTimeout(String connnectTimeout) { - this.connnectTimeout = connnectTimeout; - } - - public String getReadTimeout() { - return readTimeout; - } - - public void setReadTimeout(String readTimeout) { - this.readTimeout = readTimeout; - } - - public void overiideFromEnv(Environment environment) { - overiideCustomFromEnv(environment); - if (StringUtils.isEmpty(connnectTimeout)) { - String resolveResult = environment.resolveRequiredPlaceholders( - "${spring.cloud.alibaba.sms.connect-timeout:}"); - this.setConnnectTimeout( - StringUtils.isEmpty(resolveResult) ? "10000" : resolveResult); - } - - if (StringUtils.isEmpty(readTimeout)) { - String resolveResult = environment.resolveRequiredPlaceholders( - "${spring.cloud.alibaba.sms.read-timeout:}"); - this.setReadTimeout( - StringUtils.isEmpty(resolveResult) ? "10000" : resolveResult); - } - } - - public void overiideCustomFromEnv(Environment environment) { - // nothing to do - } - - public String getReportQueueName() { - return reportQueueName; - } - - public void setReportQueueName(String reportQueueName) { - this.reportQueueName = reportQueueName; - } - - public String getUpQueueName() { - return upQueueName; - } - - public String getAccessKeyId() { - return aliCloudProperties.getAccessKey(); - } - - public String getAccessKeySecret() { - return aliCloudProperties.getSecretKey(); - } - - public void setUpQueueName(String upQueueName) { - this.upQueueName = upQueueName; - } - -} \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java deleted file mode 100644 index 555642627..000000000 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsConfigRegistration.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.springframework.cloud.alicloud.context.sms; - -import org.springframework.core.env.Environment; - -import javax.annotation.PostConstruct; - -/** - * @author pbting - */ -public class SmsConfigRegistration { - - private Environment environment; - - private SmsConfigProperties smsConfigProperties; - - public SmsConfigRegistration(Environment environment, - SmsConfigProperties smsConfigProperties) { - this.environment = environment; - this.smsConfigProperties = smsConfigProperties; - } - - @PostConstruct - public void initSmsConfigRegistration() { - smsConfigProperties.overiideFromEnv(environment); - } -} \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java index 6f1e44160..664647ddc 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsContextAutoConfiguration.java @@ -3,28 +3,16 @@ package org.springframework.cloud.alicloud.context.sms; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.alicloud.context.AliCloudProperties; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; +/** + * @author pbting + * @author xiaolongzuo + */ @Configuration -@EnableConfigurationProperties +@EnableConfigurationProperties(SmsProperties.class) @ConditionalOnClass(name = "com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest") @ConditionalOnProperty(value = "spring.cloud.alibaba.deshao.enable.sms", matchIfMissing = true) public class SmsContextAutoConfiguration { - @Bean - public SmsConfigProperties smsConfigProperties( - AliCloudProperties aliCloudProperties) { - - return new SmsConfigProperties(aliCloudProperties); - } - - @Bean - public SmsConfigRegistration smsConfigRegistration(Environment environment, - SmsConfigProperties smsConfigProperties) { - - return new SmsConfigRegistration(environment, smsConfigProperties); - } } \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsProperties.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsProperties.java new file mode 100644 index 000000000..33577863b --- /dev/null +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/sms/SmsProperties.java @@ -0,0 +1,74 @@ +package org.springframework.cloud.alicloud.context.sms; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author pbting + * @author xiaolongzuo + */ +@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms") +public class SmsProperties { + + /** + * Product name. + */ + public static final String smsProduct = "Dysmsapi"; + + /** + * Product domain. + */ + public static final String smsDomain = "dysmsapi.aliyuncs.com"; + + /** + * Report queue name. + */ + private String reportQueueName; + + /** + * Up queue name. + */ + private String upQueueName; + + /** + * Connect timeout. + */ + private String connectTimeout = "10000"; + + /** + * Read timeout. + */ + private String readTimeout = "10000"; + + public String getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(String connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public String getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(String readTimeout) { + this.readTimeout = readTimeout; + } + + public String getReportQueueName() { + return reportQueueName; + } + + public void setReportQueueName(String reportQueueName) { + this.reportQueueName = reportQueueName; + } + + public String getUpQueueName() { + return upQueueName; + } + + public void setUpQueueName(String upQueueName) { + this.upQueueName = upQueueName; + } + +} \ No newline at end of file diff --git a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/statistics/StatisticsTaskStarter.java b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/statistics/StatisticsTaskStarter.java index 41c3591b4..709315d8b 100644 --- a/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/statistics/StatisticsTaskStarter.java +++ b/spring-cloud-alicloud-context/src/main/java/org/springframework/cloud/alicloud/context/statistics/StatisticsTaskStarter.java @@ -46,6 +46,10 @@ import com.alibaba.cloud.context.statistics.StatisticsTask; AcmContextBootstrapConfiguration.class }) public class StatisticsTaskStarter implements InitializingBean { + private static final String NACOS_CONFIG_SERVER_MODE_KEY = "spring.cloud.nacos.config.server-mode"; + + private static final String NACOS_CONFIG_SERVER_MODE_VALUE = "EDAS"; + @Autowired(required = false) private AliCloudEdasSdk aliCloudEdasSdk; @@ -102,6 +106,10 @@ public class StatisticsTaskStarter implements InitializingBean { if (acmContextBootstrapConfiguration != null && acmEnableEdas) { components.add("SC-ACM"); } + if (NACOS_CONFIG_SERVER_MODE_VALUE + .equals(System.getProperty(NACOS_CONFIG_SERVER_MODE_KEY))) { + components.add("SC-NACOS-CONFIG"); + } return components; } diff --git a/spring-cloud-alicloud-context/src/test/java/com/alibaba/csp/sentinel/datasource/nacos/NacosDataSource.java b/spring-cloud-alicloud-context/src/test/java/com/alibaba/csp/sentinel/datasource/nacos/NacosDataSource.java new file mode 100644 index 000000000..7159a2f41 --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/com/alibaba/csp/sentinel/datasource/nacos/NacosDataSource.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.csp.sentinel.datasource.nacos; + +/** + * @author xiaolongzuo + */ +public class NacosDataSource { +} diff --git a/spring-cloud-alicloud-context/src/test/java/com/aliyuncs/dysmsapi/model/v20170525/SendSmsRequest.java b/spring-cloud-alicloud-context/src/test/java/com/aliyuncs/dysmsapi/model/v20170525/SendSmsRequest.java new file mode 100644 index 000000000..ef660e84e --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/com/aliyuncs/dysmsapi/model/v20170525/SendSmsRequest.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.aliyuncs.dysmsapi.model.v20170525; + +/** + * @author xiaolongzuo + */ +public class SendSmsRequest { +} diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java new file mode 100644 index 000000000..3ae897f43 --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +/** + * @author xiaolongzuo + */ +public class NacosConfigAutoConfiguration { +} diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/AliCloudSpringApplicationTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/BaseAliCloudSpringApplication.java similarity index 62% rename from spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/AliCloudSpringApplicationTests.java rename to spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/BaseAliCloudSpringApplication.java index 471ffbb97..6cc999ff0 100644 --- a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/AliCloudSpringApplicationTests.java +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/BaseAliCloudSpringApplication.java @@ -16,36 +16,35 @@ package org.springframework.cloud.alicloud.context; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - -import org.junit.Test; import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; /** * @author xiaolongzuo */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = AliCloudSpringApplicationTests.AliCloudDisabledApp.class, properties = { +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(SpringRunner.class) +@PowerMockIgnore("javax.management.*") +@SpringBootTest(classes = BaseAliCloudSpringApplication.AliCloudApplication.class, properties = { "spring.application.name=myapp", "spring.cloud.alicloud.edas.application.name=myapp", "spring.cloud.alicloud.access-key=ak", "spring.cloud.alicloud.secret-key=sk", "spring.cloud.alicloud.oss.endpoint=test", "spring.cloud.alicloud.scx.group-id=1-2-3-4", - "spring.cloud.alicloud.edas.namespace=cn-test" }, webEnvironment = RANDOM_PORT) -@DirtiesContext -public class AliCloudSpringApplicationTests { - - @Test - public void contextLoads() { - System.out.println("Context load..."); - } + "spring.cloud.alicloud.edas.namespace=cn-test", + "spring.cloud.alicloud.ans.server-list=192.168.1.100", + "spring.cloud.alicloud.ans.server-port=8888", + "spring.cloud.alicloud.oss.enabled=false", + "spring.cloud.alicloud.scx.enabled=false" }) +public abstract class BaseAliCloudSpringApplication { @SpringBootApplication - public static class AliCloudDisabledApp { + public static class AliCloudApplication { } diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsContextApplicationListenerTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsContextApplicationListenerTests.java new file mode 100644 index 000000000..153e234df --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsContextApplicationListenerTests.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.context.ans; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import org.junit.Test; +import org.springframework.cloud.alicloud.context.BaseAliCloudSpringApplication; + +/** + * @author xiaolongzuo + */ +public class AnsContextApplicationListenerTests extends BaseAliCloudSpringApplication { + + @Test + public void testAnsContextApplicationListenerDefault() { + assertThat(System + .getProperty("com.alibaba.ans.shaded.com.taobao.vipserver.serverlist")) + .isEqualTo("192.168.1.100"); + assertThat(System.getProperty("vipserver.server.port")).isEqualTo("8888"); + } + +} diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsPropertiesTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsPropertiesTests.java index a81f0ab5b..023c5ad86 100644 --- a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsPropertiesTests.java +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/ans/AnsPropertiesTests.java @@ -18,7 +18,17 @@ package org.springframework.cloud.alicloud.context.ans; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Vector; + import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.alicloud.context.AliCloudContextAutoConfiguration; @@ -29,6 +39,8 @@ import com.alibaba.cloud.context.AliCloudServerMode; /** * @author xiaolongzuo */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ NetworkInterface.class, AnsProperties.class }) public class AnsPropertiesTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() @@ -37,8 +49,7 @@ public class AnsPropertiesTests { AliCloudContextAutoConfiguration.class)); @Test - public void testConfigurationValueDefaultsAreAsExpected() - throws ClassNotFoundException { + public void testConfigurationValueDefaultsAreAsExpected() { this.contextRunner.withPropertyValues().run(context -> { AnsProperties ansProperties = context.getBean(AnsProperties.class); assertThat(ansProperties.getServerMode()).isEqualTo(AliCloudServerMode.LOCAL); @@ -65,7 +76,7 @@ public class AnsPropertiesTests { } @Test - public void testConfigurationValuesAreCorrectlyLoaded() { + public void testConfigurationValuesAreCorrectlyLoaded1() { this.contextRunner .withPropertyValues("spring.cloud.alicloud.ans.server-mode=EDAS", "spring.cloud.alicloud.ans.server-port=11111", @@ -99,4 +110,37 @@ public class AnsPropertiesTests { }); } + @Test(expected = RuntimeException.class) + public void testConfigurationValuesAreCorrectlyLoaded2() { + this.contextRunner.withPropertyValues( + "spring.cloud.alicloud.ans.client-interface-name=noneinterfacename") + .run(context -> { + AnsProperties ansProperties = context.getBean(AnsProperties.class); + assertThat(ansProperties.getClientInterfaceName()) + .isEqualTo("noneinterfacename"); + }); + } + + @Test + public void testConfigurationValuesAreCorrectlyLoaded3() throws SocketException { + NetworkInterface networkInterface = PowerMockito.mock(NetworkInterface.class); + Vector inetAddressList = new Vector<>(); + Inet4Address inetAddress = PowerMockito.mock(Inet4Address.class); + PowerMockito.when(inetAddress.getHostAddress()).thenReturn("192.168.1.100"); + inetAddressList.add(inetAddress); + PowerMockito.when(networkInterface.getInetAddresses()) + .thenReturn(inetAddressList.elements()); + PowerMockito.mockStatic(NetworkInterface.class); + PowerMockito.when(NetworkInterface.getByName("eth0")) + .thenReturn(networkInterface); + this.contextRunner + .withPropertyValues( + "spring.cloud.alicloud.ans.client-interface-name=eth0") + .run(context -> { + AnsProperties ansProperties = context.getBean(AnsProperties.class); + assertThat(ansProperties.getClientInterfaceName()).isEqualTo("eth0"); + assertThat(ansProperties.getClientIp()).isEqualTo("192.168.1.100"); + }); + } + } diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListenerTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListenerTests.java new file mode 100644 index 000000000..fe0451fde --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/nacos/NacosParameterInitListenerTests.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.context.nacos; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.cloud.alicloud.context.BaseAliCloudSpringApplication; +import org.springframework.cloud.alicloud.utils.ChangeOrderUtils; + +import com.alibaba.cloud.context.ans.AliCloudAnsInitializer; +import com.alibaba.cloud.context.edas.EdasChangeOrderConfigurationFactory; + +/** + * @author xiaolongzuo + */ +@PrepareForTest({ EdasChangeOrderConfigurationFactory.class, + NacosParameterInitListener.class, AliCloudAnsInitializer.class }) +public class NacosParameterInitListenerTests extends BaseAliCloudSpringApplication { + + @BeforeClass + public static void setUp() { + ChangeOrderUtils.mockChangeOrder(); + } + + @Test + public void testNacosParameterInitListener() { + assertThat(System.getProperty("spring.cloud.nacos.config.server-mode")) + .isEqualTo("EDAS"); + assertThat(System.getProperty("spring.cloud.nacos.config.server-addr")) + .isEqualTo(""); + assertThat(System.getProperty("spring.cloud.nacos.config.endpoint")) + .isEqualTo("testDomain"); + assertThat(System.getProperty("spring.cloud.nacos.config.namespace")) + .isEqualTo("testTenantId"); + assertThat(System.getProperty("spring.cloud.nacos.config.access-key")) + .isEqualTo("testAK"); + assertThat(System.getProperty("spring.cloud.nacos.config.secret-key")) + .isEqualTo("testSK"); + + } +} diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/oss/OssAutoConfigurationTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/oss/OssAutoConfigurationTests.java index 042ec0873..44297f596 100644 --- a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/oss/OssAutoConfigurationTests.java +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/oss/OssAutoConfigurationTests.java @@ -35,11 +35,13 @@ public class OssAutoConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(OssContextAutoConfiguration.class)) - .withPropertyValues("spring.cloud.alicloud.accessKey=your-ak") - .withPropertyValues("spring.cloud.alicloud.secretKey=your-sk") - .withPropertyValues( - "spring.cloud.alicloud.oss.endpoint=http://oss-cn-beijing.aliyuncs.com") - .withPropertyValues("spring.cloud.alicloud.oss.config.userAgent=alibaba"); + .withPropertyValues("spring.cloud.alicloud.accessKey=your-ak", + "spring.cloud.alicloud.secretKey=your-sk", + "spring.cloud.alicloud.oss.endpoint=http://oss-cn-beijing.aliyuncs.com", + "spring.cloud.alicloud.oss.config.userAgent=alibaba", + "spring.cloud.alicloud.oss.sts.access-key=your-sts-ak", + "spring.cloud.alicloud.oss.sts.secret-key=your-sts-sk", + "spring.cloud.alicloud.oss.sts.security-token=your-sts-token"); @Test public void testOSSProperties() { @@ -53,11 +55,15 @@ public class OssAutoConfigurationTests { assertThat(ossProperties.getEndpoint()) .isEqualTo("http://oss-cn-beijing.aliyuncs.com"); assertThat(ossProperties.getConfig().getUserAgent()).isEqualTo("alibaba"); + assertThat(ossProperties.getSts().getAccessKey()).isEqualTo("your-sts-ak"); + assertThat(ossProperties.getSts().getSecretKey()).isEqualTo("your-sts-sk"); + assertThat(ossProperties.getSts().getSecurityToken()) + .isEqualTo("your-sts-token"); }); } @Test - public void testOSSClient() { + public void testOSSClient1() { this.contextRunner.run(context -> { assertThat(context.getBeansOfType(OSS.class).size() == 1).isTrue(); assertThat(context.getBeanNamesForType(OSS.class)[0]).isEqualTo("ossClient"); @@ -74,4 +80,26 @@ public class OssAutoConfigurationTests { }); } + @Test + public void testOSSClient2() { + this.contextRunner + .withPropertyValues("spring.cloud.alicloud.oss.authorization-mode=STS") + .run(context -> { + assertThat(context.getBeansOfType(OSS.class).size() == 1).isTrue(); + assertThat(context.getBeanNamesForType(OSS.class)[0]) + .isEqualTo("ossClient"); + OSSClient ossClient = (OSSClient) context.getBean(OSS.class); + assertThat(ossClient.getEndpoint().toString()) + .isEqualTo("http://oss-cn-beijing.aliyuncs.com"); + assertThat(ossClient.getClientConfiguration().getUserAgent()) + .isEqualTo("alibaba"); + assertThat(ossClient.getCredentialsProvider().getCredentials() + .getAccessKeyId()).isEqualTo("your-sts-ak"); + assertThat(ossClient.getCredentialsProvider().getCredentials() + .getSecretAccessKey()).isEqualTo("your-sts-sk"); + assertThat(ossClient.getCredentialsProvider().getCredentials() + .getSecurityToken()).isEqualTo("your-sts-token"); + }); + } + } diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sentinel/SentinelAliCloudListenerTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sentinel/SentinelAliCloudListenerTests.java new file mode 100644 index 000000000..6a812daf8 --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sentinel/SentinelAliCloudListenerTests.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.context.sentinel; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.cloud.alicloud.context.BaseAliCloudSpringApplication; +import org.springframework.cloud.alicloud.context.Constants; +import org.springframework.cloud.alicloud.utils.ChangeOrderUtils; + +import com.alibaba.cloud.context.edas.EdasChangeOrderConfigurationFactory; + +/** + * @author xiaolongzuo + */ +@PrepareForTest({ EdasChangeOrderConfigurationFactory.class, + SentinelAliCloudListener.class }) +public class SentinelAliCloudListenerTests extends BaseAliCloudSpringApplication { + + @BeforeClass + public static void setUp() { + ChangeOrderUtils.mockChangeOrder(); + } + + @Test + public void testNacosParameterInitListener() { + assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_ENDPOINT)) + .isEqualTo("testDomain"); + assertThat(System.getProperty(Constants.Sentinel.PROJECT_NAME)) + .isEqualTo("testProjectName"); + assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_NAMESPACE)) + .isEqualTo("testTenantId"); + assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_AK)) + .isEqualTo("testAK"); + assertThat(System.getProperty(Constants.Sentinel.NACOS_DATASOURCE_SK)) + .isEqualTo("testSK"); + + } +} diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sms/SmsPropertiesTests.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sms/SmsPropertiesTests.java new file mode 100644 index 000000000..4a2f74eaf --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/context/sms/SmsPropertiesTests.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.context.sms; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import org.assertj.core.api.AssertionsForClassTypes; +import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.alicloud.context.AliCloudContextAutoConfiguration; +import org.springframework.cloud.alicloud.context.edas.EdasContextAutoConfiguration; + +/** + * @author xiaolongzuo + */ +public class SmsPropertiesTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SmsContextAutoConfiguration.class, + EdasContextAutoConfiguration.class, + AliCloudContextAutoConfiguration.class)); + + @Test + public void testConfigurationValueDefaultsAreAsExpected() { + this.contextRunner.run(context -> { + SmsProperties config = context.getBean(SmsProperties.class); + assertThat(config.getReportQueueName()).isNull(); + assertThat(config.getUpQueueName()).isNull(); + assertThat(config.getConnectTimeout()).isEqualTo("10000"); + assertThat(config.getReadTimeout()).isEqualTo("10000"); + }); + } + + @Test + public void testConfigurationValuesAreCorrectlyLoaded() { + this.contextRunner + .withPropertyValues("spring.cloud.alicloud.sms.reportQueueName=q1", + "spring.cloud.alicloud.sms.upQueueName=q2", + "spring.cloud.alicloud.sms.connect-timeout=20", + "spring.cloud.alicloud.sms.read-timeout=30") + .run(context -> { + SmsProperties config = context.getBean(SmsProperties.class); + AssertionsForClassTypes.assertThat(config.getReportQueueName()) + .isEqualTo("q1"); + AssertionsForClassTypes.assertThat(config.getUpQueueName()) + .isEqualTo("q2"); + AssertionsForClassTypes.assertThat(config.getConnectTimeout()) + .isEqualTo("20"); + AssertionsForClassTypes.assertThat(config.getReadTimeout()) + .isEqualTo("30"); + }); + } + +} diff --git a/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/utils/ChangeOrderUtils.java b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/utils/ChangeOrderUtils.java new file mode 100644 index 000000000..adfd750f2 --- /dev/null +++ b/spring-cloud-alicloud-context/src/test/java/org/springframework/cloud/alicloud/utils/ChangeOrderUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alicloud.utils; + +import org.powermock.api.mockito.PowerMockito; + +import com.alibaba.cloud.context.edas.EdasChangeOrderConfiguration; +import com.alibaba.cloud.context.edas.EdasChangeOrderConfigurationFactory; + +/** + * @author xiaolongzuo + */ +public class ChangeOrderUtils { + + private ChangeOrderUtils() { + } + + public static void mockChangeOrder() { + EdasChangeOrderConfiguration edasChangeOrderConfiguration = PowerMockito + .mock(EdasChangeOrderConfiguration.class); + PowerMockito.when(edasChangeOrderConfiguration.isEdasManaged()).thenReturn(true); + PowerMockito.when(edasChangeOrderConfiguration.getAddressServerDomain()) + .thenReturn("testDomain"); + PowerMockito.when(edasChangeOrderConfiguration.getTenantId()) + .thenReturn("testTenantId"); + PowerMockito.when(edasChangeOrderConfiguration.getDauthAccessKey()) + .thenReturn("testAK"); + PowerMockito.when(edasChangeOrderConfiguration.getDauthSecretKey()) + .thenReturn("testSK"); + PowerMockito.when(edasChangeOrderConfiguration.getProjectName()) + .thenReturn("testProjectName"); + PowerMockito.when(edasChangeOrderConfiguration.getAddressServerPort()) + .thenReturn("8080"); + PowerMockito.mockStatic(EdasChangeOrderConfigurationFactory.class); + PowerMockito + .when(EdasChangeOrderConfigurationFactory + .getEdasChangeOrderConfiguration()) + .thenReturn(edasChangeOrderConfiguration); + } +} diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java index 02273a696..5d25bcc06 100644 --- a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/AbstractSmsService.java @@ -15,12 +15,12 @@ */ package org.springframework.cloud.alicloud.sms; +import java.util.concurrent.ConcurrentHashMap; + import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.profile.DefaultProfile; -import java.util.concurrent.ConcurrentHashMap; - /** * * @author pbting @@ -29,6 +29,7 @@ public abstract class AbstractSmsService implements ISmsService { private ConcurrentHashMap acsClientConcurrentHashMap = new ConcurrentHashMap<>(); + @Override public IAcsClient getHangZhouRegionClientProfile(String accessKeyId, String accessKeySecret) { diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java index 0556ea068..78253878b 100644 --- a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsInitializerEventListener.java @@ -18,7 +18,7 @@ package org.springframework.cloud.alicloud.sms; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.profile.DefaultProfile; import org.springframework.boot.context.event.ApplicationStartedEvent; -import org.springframework.cloud.alicloud.context.sms.SmsConfigProperties; +import org.springframework.cloud.alicloud.context.sms.SmsProperties; import org.springframework.cloud.alicloud.sms.base.MessageListener; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @@ -35,11 +35,11 @@ public class SmsInitializerEventListener private final AtomicBoolean isCalled = new AtomicBoolean(false); - private SmsConfigProperties msConfigProperties; + private SmsProperties msConfigProperties; private ISmsService smsService; - public SmsInitializerEventListener(SmsConfigProperties msConfigProperties, + public SmsInitializerEventListener(SmsProperties msConfigProperties, ISmsService smsService) { this.msConfigProperties = msConfigProperties; this.smsService = smsService; @@ -54,13 +54,13 @@ public class SmsInitializerEventListener // 整个application context refreshed then do // 可自助调整超时时间 System.setProperty("sun.net.client.defaultConnectTimeout", - msConfigProperties.getConnnectTimeout()); + msConfigProperties.getConnectTimeout()); System.setProperty("sun.net.client.defaultReadTimeout", msConfigProperties.getReadTimeout()); // 初始化acsClient,暂不支持region化 try { DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", - SmsConfigProperties.smsProduct, SmsConfigProperties.smsDomain); + SmsProperties.smsProduct, SmsProperties.smsDomain); Collection messageListeners = event.getApplicationContext() .getBeansOfType(MessageListener.class).values(); if (messageListeners.isEmpty()) { diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java index d32c8c64a..3b83cfb62 100644 --- a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/SmsServiceImpl.java @@ -15,17 +15,19 @@ */ package org.springframework.cloud.alicloud.sms; -import com.aliyuncs.dysmsapi.model.v20170525.*; -import com.aliyuncs.exceptions.ClientException; -import com.aliyuncs.exceptions.ServerException; +import java.text.ParseException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.cloud.alicloud.context.sms.SmsConfigProperties; +import org.springframework.cloud.alicloud.context.AliCloudProperties; +import org.springframework.cloud.alicloud.context.sms.SmsProperties; import org.springframework.cloud.alicloud.sms.base.DefaultAlicomMessagePuller; import org.springframework.cloud.alicloud.sms.endpoint.EndpointManager; import org.springframework.cloud.alicloud.sms.endpoint.ReceiveMessageEntity; -import java.text.ParseException; +import com.aliyuncs.dysmsapi.model.v20170525.*; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; /** * @author pbting @@ -38,17 +40,22 @@ public final class SmsServiceImpl extends AbstractSmsService { * @param sendSmsRequest * @return */ - private SmsConfigProperties smsConfigProperties; + private SmsProperties smsProperties; - public SmsServiceImpl(SmsConfigProperties smsConfigProperties) { - this.smsConfigProperties = smsConfigProperties; + private AliCloudProperties aliCloudProperties; + + public SmsServiceImpl(AliCloudProperties aliCloudProperties, + SmsProperties smsProperties) { + this.aliCloudProperties = aliCloudProperties; + this.smsProperties = smsProperties; } + @Override public SendSmsResponse sendSmsRequest(SendSmsRequest sendSmsRequest) throws ClientException { - return sendSmsRequest(sendSmsRequest, smsConfigProperties.getAccessKeyId(), - smsConfigProperties.getAccessKeySecret()); + return sendSmsRequest(sendSmsRequest, aliCloudProperties.getAccessKey(), + aliCloudProperties.getSecretKey()); } /** @@ -62,6 +69,7 @@ public final class SmsServiceImpl extends AbstractSmsService { * @throws ClientException * @return SendSmsResponse */ + @Override public SendSmsResponse sendSmsRequest(SendSmsRequest sendSmsRequest, String accessKeyId, String accessKeySecret) throws ServerException, ClientException { @@ -76,10 +84,12 @@ public final class SmsServiceImpl extends AbstractSmsService { * @param smsReportMessageListener * @return boolean */ + @Override public boolean startSmsReportMessageListener( SmsReportMessageListener smsReportMessageListener) { - String messageType = "SmsReport";// 短信回执:SmsReport,短信上行:SmsUp - String queueName = smsConfigProperties.getReportQueueName(); + // 短信回执:SmsReport,短信上行:SmsUp + String messageType = "SmsReport"; + String queueName = smsProperties.getReportQueueName(); return startReceiveMsg(messageType, queueName, smsReportMessageListener); } @@ -88,9 +98,11 @@ public final class SmsServiceImpl extends AbstractSmsService { * @param smsUpMessageListener * @return boolean */ + @Override public boolean startSmsUpMessageListener(SmsUpMessageListener smsUpMessageListener) { - String messageType = "SmsUp";// 短信回执:SmsReport,短信上行:SmsUp - String queueName = smsConfigProperties.getUpQueueName(); + // 短信回执:SmsReport,短信上行:SmsUp + String messageType = "SmsUp"; + String queueName = smsProperties.getUpQueueName(); return startReceiveMsg(messageType, queueName, smsUpMessageListener); } @@ -103,8 +115,8 @@ public final class SmsServiceImpl extends AbstractSmsService { */ private boolean startReceiveMsg(String messageType, String queueName, SmsMessageListener messageListener) { - String accessKeyId = smsConfigProperties.getAccessKeyId(); - String accessKeySecret = smsConfigProperties.getAccessKeySecret(); + String accessKeyId = aliCloudProperties.getAccessKey(); + String accessKeySecret = aliCloudProperties.getSecretKey(); boolean result = true; try { new DefaultAlicomMessagePuller().startReceiveMsg(accessKeyId, accessKeySecret, @@ -135,9 +147,8 @@ public final class SmsServiceImpl extends AbstractSmsService { SendBatchSmsRequest sendBatchSmsRequest) throws ServerException, ClientException { - return sendSmsBatchRequest(sendBatchSmsRequest, - smsConfigProperties.getAccessKeyId(), - smsConfigProperties.getAccessKeySecret()); + return sendSmsBatchRequest(sendBatchSmsRequest, aliCloudProperties.getAccessKey(), + aliCloudProperties.getSecretKey()); } /** @@ -181,7 +192,7 @@ public final class SmsServiceImpl extends AbstractSmsService { @Override public QuerySendDetailsResponse querySendDetails(QuerySendDetailsRequest request) throws ClientException { - return querySendDetails(request, smsConfigProperties.getAccessKeyId(), - smsConfigProperties.getAccessKeySecret()); + return querySendDetails(request, aliCloudProperties.getAccessKey(), + aliCloudProperties.getSecretKey()); } } \ No newline at end of file diff --git a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java index 12e1760ba..6fb5727dd 100644 --- a/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java +++ b/spring-cloud-alicloud-sms/src/main/java/org/springframework/cloud/alicloud/sms/config/SmsAutoConfiguration.java @@ -18,7 +18,8 @@ package org.springframework.cloud.alicloud.sms.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.alicloud.context.sms.SmsConfigProperties; +import org.springframework.cloud.alicloud.context.AliCloudProperties; +import org.springframework.cloud.alicloud.context.sms.SmsProperties; import org.springframework.cloud.alicloud.sms.ISmsService; import org.springframework.cloud.alicloud.sms.SmsInitializerEventListener; import org.springframework.cloud.alicloud.sms.SmsServiceImpl; @@ -37,13 +38,14 @@ import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; public class SmsAutoConfiguration { @Bean - public SmsServiceImpl smsService(SmsConfigProperties smsConfigProperties) { - return new SmsServiceImpl(smsConfigProperties); + public SmsServiceImpl smsService(AliCloudProperties aliCloudProperties, + SmsProperties smsProperties) { + return new SmsServiceImpl(aliCloudProperties, smsProperties); } @Bean public SmsInitializerEventListener smsInitializePostListener( - SmsConfigProperties msConfigProperties, ISmsService smsService) { - return new SmsInitializerEventListener(msConfigProperties, smsService); + SmsProperties smsProperties, ISmsService smsService) { + return new SmsInitializerEventListener(smsProperties, smsService); } } \ No newline at end of file From 76775072943bd9a026fd97c0e341f2e0490d2da5 Mon Sep 17 00:00:00 2001 From: flystar32 Date: Thu, 14 Feb 2019 10:46:51 +0800 Subject: [PATCH 49/50] Polish #345 , fixes @AutoConfigureAfter(AutoServiceRegistrationAutoConfiguration.class) --- .../NacosDiscoveryAutoConfiguration.java | 83 ++++++++++--------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index ffd67df53..27456512c 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -41,48 +41,53 @@ import org.springframework.context.annotation.Configuration; @EnableConfigurationProperties @ConditionalOnNacosDiscoveryEnabled @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class, - NacosDiscoveryClientAutoConfiguration.class}) -@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class) +@AutoConfigureBefore(NacosDiscoveryClientAutoConfiguration.class) +@AutoConfigureAfter(AutoServiceRegistrationAutoConfiguration.class) public class NacosDiscoveryAutoConfiguration { - @Bean - public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) { - return new NacosServiceRegistry(nacosDiscoveryProperties); - } + @Bean + public NacosServiceRegistry nacosServiceRegistry( + NacosDiscoveryProperties nacosDiscoveryProperties) { + return new NacosServiceRegistry(nacosDiscoveryProperties); + } - @Bean - @ConditionalOnBean(AutoServiceRegistrationProperties.class) - public NacosRegistration nacosRegistration( - NacosDiscoveryProperties nacosDiscoveryProperties, - ApplicationContext context) { - return new NacosRegistration(nacosDiscoveryProperties, context); - } + @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + public NacosRegistration nacosRegistration( + NacosDiscoveryProperties nacosDiscoveryProperties, + ApplicationContext context) { + return new NacosRegistration(nacosDiscoveryProperties, context); + } - @Bean - @ConditionalOnBean(AutoServiceRegistrationProperties.class) - public NacosAutoServiceRegistration nacosAutoServiceRegistration( - NacosServiceRegistry registry, - AutoServiceRegistrationProperties autoServiceRegistrationProperties, - NacosRegistration registration) { - return new NacosAutoServiceRegistration(registry, - autoServiceRegistrationProperties, registration); - } + @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + public NacosAutoServiceRegistration nacosAutoServiceRegistration( + NacosServiceRegistry registry, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + NacosRegistration registration) { + return new NacosAutoServiceRegistration(registry, + autoServiceRegistrationProperties, registration); + } - @Bean - @ConditionalOnBean(NacosAutoServiceRegistration.class) // NacosAutoServiceRegistration should be present - @ConditionalOnNotWebApplication // Not Web Application - public ApplicationRunner applicationRunner(NacosAutoServiceRegistration nacosAutoServiceRegistration) { - return args -> { - // WebServerInitializedEvent should not be multicast in Non-Web environment. - // Whatever, NacosAutoServiceRegistration must be checked it's running or not. - if (!nacosAutoServiceRegistration.isRunning()) { // If it's not running, let it start. - // FIXME: Please make sure "spring.cloud.nacos.discovery.port" must be configured on an available port, - // or the startup or Nacos health check will be failed. - nacosAutoServiceRegistration.start(); - // NacosAutoServiceRegistration will be stopped after its destroy() method is invoked. - // @PreDestroy destroy() -> stop() - } - }; - } + @Bean + @ConditionalOnBean(NacosAutoServiceRegistration.class) // NacosAutoServiceRegistration + // should be present + @ConditionalOnNotWebApplication // Not Web Application + public ApplicationRunner applicationRunner( + NacosAutoServiceRegistration nacosAutoServiceRegistration) { + return args -> { + // WebServerInitializedEvent should not be multicast in Non-Web environment. + // Whatever, NacosAutoServiceRegistration must be checked it's running or not. + if (!nacosAutoServiceRegistration.isRunning()) { // If it's not running, let + // it start. + // FIXME: Please make sure "spring.cloud.nacos.discovery.port" must be + // configured on an available port, + // or the startup or Nacos health check will be failed. + nacosAutoServiceRegistration.start(); + // NacosAutoServiceRegistration will be stopped after its destroy() method + // is invoked. + // @PreDestroy destroy() -> stop() + } + }; + } } \ No newline at end of file From 8d41c885c0ee2c96807b62703d172dcf0784369e Mon Sep 17 00:00:00 2001 From: flystar32 Date: Mon, 18 Feb 2019 10:43:06 +0800 Subject: [PATCH 50/50] Fixes #352 --- .../alibaba/nacos/NacosDiscoveryAutoConfiguration.java | 8 +++++++- .../nacos/NacosDiscoveryClientAutoConfiguration.java | 6 ------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index 27456512c..7b018ae2c 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -20,6 +20,7 @@ import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -27,7 +28,6 @@ import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistra import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; -import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -45,6 +45,12 @@ import org.springframework.context.annotation.Configuration; @AutoConfigureAfter(AutoServiceRegistrationAutoConfiguration.class) public class NacosDiscoveryAutoConfiguration { + @Bean + @ConditionalOnMissingBean + public NacosDiscoveryProperties nacosProperties() { + return new NacosDiscoveryProperties(); + } + @Bean public NacosServiceRegistry nacosServiceRegistry( NacosDiscoveryProperties nacosDiscoveryProperties) { diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java index 02f970783..60a76cf77 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java @@ -37,10 +37,4 @@ public class NacosDiscoveryClientAutoConfiguration { return new NacosDiscoveryClient(discoveryProperties); } - @Bean - @ConditionalOnMissingBean - public NacosDiscoveryProperties nacosProperties() { - return new NacosDiscoveryProperties(); - } - }