Temporary commit

pull/320/head
mercyblitz 6 years ago
parent 7aa17d3760
commit 26a05cbefb

@ -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);
}

@ -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);
}

@ -59,6 +59,17 @@
<optional>true</optional>
</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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
@ -126,6 +137,11 @@
<version>9.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
@ -159,11 +175,11 @@
</dependency>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<scope>test</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
</dependencies>
</project>

@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@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();
}
}

@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@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<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 =
beanFactory.getBeansOfType(NamedContextFactory.Specification.class);
ServiceAnnotationBeanPostProcessor
// 1. Get all service names from Spring beans that was annotated by @FeignClient
List<String> 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<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) {
ReferenceBean referenceBean = new ReferenceBean();
applicationConfig.setName("service-consumer");
@ -204,6 +268,7 @@ public class DubboRestDiscoveryAutoConfiguration {
return delegate.execute(request, options);
}
}
@EventListener(ContextRefreshedEvent.class)

@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@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<String, Set<String>> restMetadata = new LinkedHashMap<>();
private final Map<String, Map<String, Map<String, Object>>> restMetadata = new LinkedHashMap<>();
/**
* Feign Contracts
*/
private Collection<Contract> contracts = Collections.emptyList();
private final Set<ServiceRestMetadata> 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<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;
}
@Autowired
private MetadataConfigUtils metadataConfigUtils;
@EventListener(ServiceBeanExportedEvent.class)
public void recordRestMetadata(ServiceBeanExportedEvent event) {
public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
ServiceBean serviceBean = event.getServiceBean();
List<URL> urls = serviceBean.getExportedUrls();
Object bean = serviceBean.getRef();
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);
});
// Map<String, Map<String, Map<String, Object>>> 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<String, String> 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;
}
}

@ -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<Contract> contracts;
private ClassLoader classLoader;
@Autowired
private ObjectProvider<Contract> contractObjectProvider;
public RestMetadataResolver(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;
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 {
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;
}
}

@ -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:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
eureka:
client:
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;
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<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
;
}
}

@ -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=*
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>
<description>Example demonstrating how to use nacos discovery</description>
<properties>
<dubbo.version>2.6.5</dubbo.version>
</properties>
<modules>
<module>nacos-discovery-consumer-example</module>
<module>nacos-discovery-provider-example</module>
</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>

@ -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

Loading…
Cancel
Save