mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Temporary commit
This commit is contained in:
parent
7aa17d3760
commit
26a05cbefb
@ -260,8 +260,8 @@ public class NacosConsumerApp {
|
|||||||
@GetMapping("/echo/app-name")
|
@GetMapping("/echo/app-name")
|
||||||
public String echoAppName(){
|
public String echoAppName(){
|
||||||
//使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问
|
//使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问
|
||||||
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
|
ServiceInstance delegate = loadBalancerClient.choose("nacos-provider");
|
||||||
String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
|
String url = String.format("http://%s:%s/echo/%s",delegate.getHost(),delegate.getPort(),appName);
|
||||||
System.out.println("request url:"+url);
|
System.out.println("request url:"+url);
|
||||||
return restTemplate.getForObject(url,String.class);
|
return restTemplate.getForObject(url,String.class);
|
||||||
}
|
}
|
||||||
|
@ -260,8 +260,8 @@ public class NacosConsumerApp {
|
|||||||
@GetMapping("/echo/app-name")
|
@GetMapping("/echo/app-name")
|
||||||
public String echoAppName(){
|
public String echoAppName(){
|
||||||
//Access through the combination of LoadBalanceClient and RestTemolate
|
//Access through the combination of LoadBalanceClient and RestTemolate
|
||||||
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
|
ServiceInstance delegate = loadBalancerClient.choose("nacos-provider");
|
||||||
String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
|
String url = String.format("http://%s:%s/echo/%s",delegate.getHost(),delegate.getPort(),appName);
|
||||||
System.out.println("request url:" +url);
|
System.out.println("request url:" +url);
|
||||||
return restTemplate.getForObject(url,String.class);
|
return restTemplate.getForObject(url,String.class);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,17 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>org.springframework.cloud</groupId>-->
|
||||||
|
<!--<artifactId>spring-cloud-config-monitor</artifactId>-->
|
||||||
|
<!--<optional>true</optional>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
@ -126,6 +137,11 @@
|
|||||||
<version>9.7.0</version>
|
<version>9.7.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
@ -159,11 +175,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Eureka Service Discovery -->
|
<!-- Eureka Service Discovery -->
|
||||||
<dependency>
|
<!--<dependency>-->
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<!--<groupId>org.springframework.cloud</groupId>-->
|
||||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
<!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
|
||||||
<scope>test</scope>
|
<!--<scope>test</scope>-->
|
||||||
</dependency>
|
<!--</dependency>-->
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -17,17 +17,13 @@
|
|||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import feign.Contract;
|
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||||
import feign.jaxrs2.JAXRS2Contract;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Boot Auto-Configuration class for Dubbo REST
|
* Spring Boot Auto-Configuration class for Dubbo REST
|
||||||
@ -35,34 +31,22 @@ import javax.ws.rs.Path;
|
|||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
|
||||||
public class DubboRestAutoConfiguration {
|
public class DubboRestAutoConfiguration {
|
||||||
|
|
||||||
// /**
|
|
||||||
// * A Feign Contract bean for JAX-RS if available
|
|
||||||
// */
|
|
||||||
// @ConditionalOnClass(Path.class)
|
|
||||||
// @Bean
|
|
||||||
// public Contract jaxrs2Contract() {
|
|
||||||
// return new JAXRS2Contract();
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public ObjectMapper objectMapper() {
|
public ObjectMapper objectMapper() {
|
||||||
return new ObjectMapper();
|
return new ObjectMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * A Feign Contract bean for Spring MVC if available
|
|
||||||
// */
|
|
||||||
// @ConditionalOnClass(RequestMapping.class)
|
|
||||||
// @Bean
|
|
||||||
// public Contract springMvcContract() {
|
|
||||||
// return new SpringMvcContract();
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) {
|
public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) {
|
||||||
return new RestMetadataResolver(objectMapper);
|
return new RestMetadataResolver(objectMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MetadataConfigUtils metadataConfigUtils() {
|
||||||
|
return new MetadataConfigUtils();
|
||||||
|
}
|
||||||
}
|
}
|
@ -16,31 +16,36 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
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.ApplicationConfig;
|
||||||
import com.alibaba.dubbo.config.RegistryConfig;
|
import com.alibaba.dubbo.config.RegistryConfig;
|
||||||
import com.alibaba.dubbo.config.spring.ReferenceBean;
|
import com.alibaba.dubbo.config.spring.ReferenceBean;
|
||||||
import feign.Client;
|
import feign.Client;
|
||||||
import feign.Request;
|
import feign.Request;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.ListableBeanFactory;
|
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.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
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.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.ServiceInstance;
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
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.context.named.NamedContextFactory;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.event.ContextRefreshedEvent;
|
import org.springframework.context.event.ContextRefreshedEvent;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -51,17 +56,18 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Auto-Configuration class for Dubbo REST Discovery
|
* The Auto-Configuration class for Dubbo REST Discovery
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = true)
|
||||||
@AutoConfigureAfter(value = {
|
@AutoConfigureAfter(value = {
|
||||||
|
DubboAutoConfiguration.class,
|
||||||
DubboRestAutoConfiguration.class,
|
DubboRestAutoConfiguration.class,
|
||||||
DubboRestMetadataRegistrationAutoConfiguration.class})
|
DubboRestMetadataRegistrationAutoConfiguration.class})
|
||||||
|
@Configuration
|
||||||
public class DubboRestDiscoveryAutoConfiguration {
|
public class DubboRestDiscoveryAutoConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -81,29 +87,66 @@ public class DubboRestDiscoveryAutoConfiguration {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationConfig applicationConfig;
|
private ApplicationConfig applicationConfig;
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String applicationName;
|
||||||
|
|
||||||
@Value("${spring.cloud.nacos.discovery.server-addr}")
|
@Value("${spring.cloud.nacos.discovery.server-addr}")
|
||||||
private String nacosServerAddress;
|
private String nacosServerAddress;
|
||||||
|
|
||||||
|
|
||||||
private volatile boolean initialized = false;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ListableBeanFactory beanFactory;
|
private ListableBeanFactory beanFactory;
|
||||||
|
|
||||||
@Scheduled(initialDelay = 10 * 1000, fixedRate = 5000)
|
@Autowired
|
||||||
public void init() {
|
private MetadataConfigUtils metadataConfigUtils;
|
||||||
|
|
||||||
if (initialized) {
|
/**
|
||||||
|
* 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;
|
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<ServiceRestMetadata> metadata = objectMapper.readValue(serviceRestMetaData, Set.class);
|
||||||
|
|
||||||
|
System.out.println(serviceRestMetaData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RequestInterceptor requestInterceptor() {
|
||||||
|
return template -> {
|
||||||
|
System.out.println(template);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void noop() {
|
||||||
Map<String, NamedContextFactory.Specification> specifications =
|
Map<String, NamedContextFactory.Specification> specifications =
|
||||||
beanFactory.getBeansOfType(NamedContextFactory.Specification.class);
|
beanFactory.getBeansOfType(NamedContextFactory.Specification.class);
|
||||||
ServiceAnnotationBeanPostProcessor
|
|
||||||
// 1. Get all service names from Spring beans that was annotated by @FeignClient
|
// 1. Get all service names from Spring beans that was annotated by @FeignClient
|
||||||
List<String> serviceNames = new LinkedList<>();
|
List<String> serviceNames = new LinkedList<>();
|
||||||
|
|
||||||
specifications.forEach((beanName, specification) -> {
|
specifications.forEach((beanName, specification) ->
|
||||||
|
|
||||||
|
{
|
||||||
String serviceName = beanName.substring(0, beanName.indexOf("."));
|
String serviceName = beanName.substring(0, beanName.indexOf("."));
|
||||||
serviceNames.add(serviceName);
|
serviceNames.add(serviceName);
|
||||||
|
|
||||||
@ -139,11 +182,32 @@ public class DubboRestDiscoveryAutoConfiguration {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReferenceBean buildReferenceBean(ServiceInstance serviceInstance) {
|
||||||
|
|
||||||
|
ReferenceBean referenceBean = new ReferenceBean();
|
||||||
|
Map<String, String> metadata = serviceInstance.getMetadata();
|
||||||
|
// 4. Resolve REST metadata from the @FeignClient instance
|
||||||
|
String restMetadataJson = metadata.get("restMetadata");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, List<String>> 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) {
|
private ReferenceBean buildReferenceBean(String dubboServiceName) {
|
||||||
ReferenceBean referenceBean = new ReferenceBean();
|
ReferenceBean referenceBean = new ReferenceBean();
|
||||||
applicationConfig.setName("service-consumer");
|
applicationConfig.setName("service-consumer");
|
||||||
@ -204,6 +268,7 @@ public class DubboRestDiscoveryAutoConfiguration {
|
|||||||
|
|
||||||
return delegate.execute(request, options);
|
return delegate.execute(request, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventListener(ContextRefreshedEvent.class)
|
@EventListener(ContextRefreshedEvent.class)
|
||||||
|
@ -16,36 +16,26 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
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.ServiceBean;
|
||||||
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
|
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import feign.Contract;
|
|
||||||
import feign.jaxrs2.JAXRS2Contract;
|
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
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.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.discovery.event.InstancePreRegisteredEvent;
|
||||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
import org.springframework.cloud.openfeign.support.SpringMvcContract;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.event.EventListener;
|
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.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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,
|
* The Auto-Configuration class for Dubbo REST metadata registration,
|
||||||
@ -54,21 +44,19 @@ import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegist
|
|||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
||||||
@AutoConfigureAfter(value = {
|
@AutoConfigureAfter(value = {
|
||||||
DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class})
|
DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class})
|
||||||
|
@Configuration
|
||||||
public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClassLoaderAware {
|
public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClassLoaderAware {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service,
|
* 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.
|
* the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods.
|
||||||
*/
|
*/
|
||||||
private final Map<String, Set<String>> restMetadata = new LinkedHashMap<>();
|
private final Map<String, Map<String, Map<String, Object>>> restMetadata = new LinkedHashMap<>();
|
||||||
|
|
||||||
/**
|
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||||
* Feign Contracts
|
|
||||||
*/
|
|
||||||
private Collection<Contract> contracts = Collections.emptyList();
|
|
||||||
|
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
@ -78,42 +66,16 @@ public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClass
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RestMetadataResolver restMetadataResolver;
|
private RestMetadataResolver restMetadataResolver;
|
||||||
|
|
||||||
@PostConstruct
|
@Autowired
|
||||||
public void init() {
|
private MetadataConfigUtils metadataConfigUtils;
|
||||||
contracts = initFeignContracts();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<Contract> initFeignContracts() {
|
|
||||||
Collection<Contract> 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)
|
@EventListener(ServiceBeanExportedEvent.class)
|
||||||
public void recordRestMetadata(ServiceBeanExportedEvent event) {
|
public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
|
||||||
ServiceBean serviceBean = event.getServiceBean();
|
ServiceBean serviceBean = event.getServiceBean();
|
||||||
List<URL> urls = serviceBean.getExportedUrls();
|
// Map<String, Map<String, Map<String, Object>>> metadata = restMetadataResolver.resolve(serviceBean);
|
||||||
Object bean = serviceBean.getRef();
|
// restMetadata.putAll(metadata);
|
||||||
|
serviceRestMetadata.addAll(restMetadataResolver.resolve(serviceBean));
|
||||||
Set<String> 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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,15 +88,20 @@ public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClass
|
|||||||
* @param event {@link InstancePreRegisteredEvent} instance
|
* @param event {@link InstancePreRegisteredEvent} instance
|
||||||
*/
|
*/
|
||||||
@EventListener(InstancePreRegisteredEvent.class)
|
@EventListener(InstancePreRegisteredEvent.class)
|
||||||
public void registerRestMetadata(InstancePreRegisteredEvent event) throws JsonProcessingException {
|
public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception {
|
||||||
Registration registration = event.getRegistration();
|
Registration registration = event.getRegistration();
|
||||||
Map<String, String> serviceInstanceMetadata = registration.getMetadata();
|
|
||||||
String restMetadataJson = objectMapper.writeValueAsString(restMetadata);
|
String restMetadataJson = objectMapper.writeValueAsString(serviceRestMetadata);
|
||||||
serviceInstanceMetadata.put("restMetadata", restMetadataJson);
|
|
||||||
|
metadataConfigUtils.publishServiceRestMetadata(registration.getServiceId(), restMetadataJson);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,21 +16,39 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.rest.feign;
|
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.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import feign.Contract;
|
||||||
import feign.MethodMetadata;
|
import feign.MethodMetadata;
|
||||||
import feign.Request;
|
import feign.Request;
|
||||||
import feign.RequestTemplate;
|
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.io.IOException;
|
||||||
import java.util.Collection;
|
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.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The JSON resolver for {@link MethodMetadata}
|
* 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 METHOD_PROPERTY_NAME = "method";
|
||||||
private static final String URL_PROPERTY_NAME = "url";
|
private static final String URL_PROPERTY_NAME = "url";
|
||||||
@ -38,26 +56,108 @@ public class RestMetadataResolver {
|
|||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feign Contracts
|
||||||
|
*/
|
||||||
|
private Collection<Contract> contracts;
|
||||||
|
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectProvider<Contract> contractObjectProvider;
|
||||||
|
|
||||||
public RestMetadataResolver(ObjectMapper objectMapper) {
|
public RestMetadataResolver(ObjectMapper objectMapper) {
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String resolve(MethodMetadata methodMetadata) {
|
@Override
|
||||||
|
public void afterSingletonsInstantiated() {
|
||||||
|
|
||||||
|
Collection<Contract> 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<ServiceRestMetadata> resolve(ServiceBean serviceBean) {
|
||||||
|
|
||||||
|
Object bean = serviceBean.getRef();
|
||||||
|
|
||||||
|
Class<?> beanType = bean.getClass();
|
||||||
|
|
||||||
|
Class<?> interfaceClass = serviceBean.getInterfaceClass();
|
||||||
|
|
||||||
|
Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
Set<MethodRestMetadata> methodRestMetadata = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
contracts.stream()
|
||||||
|
.map(contract -> contract.parseAndValidatateMetadata(bean.getClass()))
|
||||||
|
.flatMap(v -> v.stream())
|
||||||
|
.forEach(methodMetadata -> {
|
||||||
|
methodRestMetadata.add(resolveMethodRestMetadata(methodMetadata, beanType, interfaceClass));
|
||||||
|
});
|
||||||
|
|
||||||
|
List<URL> 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;
|
String jsonContent = null;
|
||||||
Map<String, Object> 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 {
|
try {
|
||||||
jsonContent = objectMapper.writeValueAsString(metadata);
|
jsonContent = objectMapper.writeValueAsString(object);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
return jsonContent;
|
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) {
|
public Request resolveRequest(String json) {
|
||||||
Request request = null;
|
Request request = null;
|
||||||
try {
|
try {
|
||||||
@ -71,4 +171,10 @@ public class RestMetadataResolver {
|
|||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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<String, Collection<String>> headers;
|
||||||
|
|
||||||
|
private Map<Integer, Collection<String>> 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<String, Collection<String>> getHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeaders(Map<String, Collection<String>> headers) {
|
||||||
|
this.headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Collection<String>> getIndexToName() {
|
||||||
|
return indexToName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndexToName(Map<Integer, Collection<String>> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<MethodRestMetadata> meta;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<MethodRestMetadata> getMeta() {
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMeta(Set<MethodRestMetadata> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,9 @@ spring:
|
|||||||
nacos:
|
nacos:
|
||||||
discovery:
|
discovery:
|
||||||
server-addr: 127.0.0.1:8848
|
server-addr: 127.0.0.1:8848
|
||||||
|
config:
|
||||||
|
server-addr: 127.0.0.1:8848
|
||||||
|
|
||||||
eureka:
|
eureka:
|
||||||
client:
|
client:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -1,13 +1,30 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples;
|
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.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
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
|
* @author xiaojing
|
||||||
@ -20,16 +37,114 @@ public class ProviderApplication {
|
|||||||
SpringApplication.run(ProviderApplication.class, args);
|
SpringApplication.run(ProviderApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestController
|
@Autowired
|
||||||
class EchoController {
|
private ConfigurableListableBeanFactory beanFactory;
|
||||||
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
|
|
||||||
public String echo(@PathVariable String string) {
|
@Autowired
|
||||||
return "hello Nacos Discovery " + string;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@EventListener(ServiceBeanExportedEvent.class)
|
||||||
|
public void onServiceBeanExportedEvent(ServiceBeanExportedEvent event) {
|
||||||
|
ServiceBean serviceBean = event.getServiceBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/divide", method = RequestMethod.GET)
|
@EventListener(InstancePreRegisteredEvent.class)
|
||||||
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
|
public void onInstancePreRegisteredEvent(InstancePreRegisteredEvent event) throws JsonProcessingException {
|
||||||
return String.valueOf(a / b);
|
Registration registration = event.getRegistration();
|
||||||
|
Map<String, ServiceBean> serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class);
|
||||||
|
Map<String, String> metaData = registration.getMetadata();
|
||||||
|
String serviceBeansJson = objectMapper.writeValueAsString(services(serviceBeansMap));
|
||||||
|
metaData.put("serviceBeans", serviceBeansJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Map<String, Object>> services(Map<String, ServiceBean> serviceBeansMap) {
|
||||||
|
|
||||||
|
Map<String, Map<String, Object>> servicesMetadata = new LinkedHashMap<>(serviceBeansMap.size());
|
||||||
|
|
||||||
|
for (Map.Entry<String, ServiceBean> entry : serviceBeansMap.entrySet()) {
|
||||||
|
|
||||||
|
String serviceBeanName = entry.getKey();
|
||||||
|
|
||||||
|
ServiceBean serviceBean = entry.getValue();
|
||||||
|
|
||||||
|
Map<String, Object> 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<String, Object> resolveBeanMetadata(final Object bean) {
|
||||||
|
|
||||||
|
final Map<String, Object> 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
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,3 +2,11 @@ server.port=18082
|
|||||||
spring.application.name=service-provider
|
spring.application.name=service-provider
|
||||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
||||||
management.endpoints.web.exposure.include=*
|
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
|
@ -15,11 +15,47 @@
|
|||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<description>Example demonstrating how to use nacos discovery</description>
|
<description>Example demonstrating how to use nacos discovery</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<dubbo.version>2.6.5</dubbo.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>nacos-discovery-consumer-example</module>
|
<module>nacos-discovery-consumer-example</module>
|
||||||
<module>nacos-discovery-provider-example</module>
|
<module>nacos-discovery-provider-example</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- Dubbo Spring Boot Starter -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.boot</groupId>
|
||||||
|
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>dubbo</artifactId>
|
||||||
|
<version>${dubbo.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Netty -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Dubbo Nacos registry dependency -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>dubbo-registry-nacos</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Keep latest Nacos client version -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<artifactId>nacos-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -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.actuate.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.cloud.alibaba.nacos.ConditionalOnNacosDiscoveryEnabled;
|
||||||
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
|
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -29,6 +30,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(Endpoint.class)
|
@ConditionalOnClass(Endpoint.class)
|
||||||
|
@ConditionalOnNacosDiscoveryEnabled
|
||||||
public class NacosDiscoveryEndpointAutoConfiguration {
|
public class NacosDiscoveryEndpointAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
Loading…
x
Reference in New Issue
Block a user