From f34633ebf4f0ac22a5a3ab1db24ec1126339906b Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 10 Jan 2019 15:37:36 +0800 Subject: [PATCH 01/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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 3c51f9f8d8da2fbcf7763b964bd4892e50c0beb8 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 00:25:55 +0800 Subject: [PATCH 11/16] 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 12/16] 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 13/16] 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 054e95dd450256baec8bffb1389dd8f208ab3ee2 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 22 Jan 2019 14:45:39 +0800 Subject: [PATCH 14/16] 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 15/16] 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 ff6e68d522f1169a773e86925a0ca5736167f4da Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 1 Feb 2019 22:33:47 +0800 Subject: [PATCH 16/16] 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