mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Polish the first GA for spring-cloud-alibaba-dubbo
This commit is contained in:
parent
5c2b118523
commit
3c51f9f8d8
@ -16,34 +16,31 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import feign.Contract;
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService;
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.service.NacosMetadataConfigService;
|
||||||
|
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring Boot Auto-Configuration class for Dubbo REST
|
* Spring Boot Auto-Configuration class for Dubbo Metadata
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@Import(DubboServiceMetadataRepository.class)
|
||||||
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
|
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
|
||||||
public class DubboRestAutoConfiguration {
|
public class DubboMetadataAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public FeignRestMetadataResolver metadataJsonResolver(
|
@ConditionalOnBean(NacosConfigProperties.class)
|
||||||
ObjectProvider<ObjectMapper> objectMapper, ObjectProvider<Contract> contract) {
|
public MetadataConfigService metadataConfigService() {
|
||||||
return new FeignRestMetadataResolver(objectMapper, contract);
|
return new NacosMetadataConfigService();
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public RestMetadataConfigService restMetadataConfigService() {
|
|
||||||
return new RestMetadataConfigService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -16,28 +16,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
||||||
|
|
||||||
|
import feign.Contract;
|
||||||
import feign.Feign;
|
import feign.Feign;
|
||||||
import feign.RequestInterceptor;
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.FeignMetadataResolver;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
|
||||||
import org.springframework.cloud.alibaba.dubbo.openfeign.DubboFeignClientsConfiguration;
|
import org.springframework.cloud.alibaba.dubbo.openfeign.DubboFeignClientsConfiguration;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
||||||
import org.springframework.cloud.openfeign.FeignContext;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,52 +37,18 @@ import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFei
|
|||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@ConditionalOnClass(value = Feign.class, name = FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME)
|
@ConditionalOnClass(value = Feign.class)
|
||||||
@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class)
|
|
||||||
@AutoConfigureAfter(FeignAutoConfiguration.class)
|
@AutoConfigureAfter(FeignAutoConfiguration.class)
|
||||||
|
@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class)
|
||||||
@Configuration
|
@Configuration
|
||||||
public class DubboOpenFeignAutoConfiguration {
|
public class DubboOpenFeignAutoConfiguration {
|
||||||
|
|
||||||
static final String FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME =
|
@Value("${spring.application.name}")
|
||||||
"org.springframework.cloud.openfeign.FeignClientFactoryBean";
|
private String currentApplicationName;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ObjectProvider<FeignContext> feignContextObjectProvider;
|
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
|
||||||
public void onApplicationReady(ApplicationReadyEvent event) {
|
|
||||||
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
|
|
||||||
// Resolve the subscribed service names for @FeignClient
|
|
||||||
Set<String> feignClientServiceNames = resolveFeignClientServiceNames(applicationContext);
|
|
||||||
// FeignContext
|
|
||||||
FeignContext feignContext = feignContextObjectProvider.getIfAvailable();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve the subscribed service names for @FeignClient
|
|
||||||
*
|
|
||||||
* @param applicationContext Current {@link ConfigurableApplicationContext}
|
|
||||||
* @return non-null {@link Set}
|
|
||||||
*/
|
|
||||||
private Set<String> resolveFeignClientServiceNames(ConfigurableApplicationContext applicationContext) {
|
|
||||||
Set<String> feignClientServiceNames = new LinkedHashSet<>();
|
|
||||||
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
|
|
||||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
|
||||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
|
||||||
if (FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME.equals(beanDefinition.getBeanClassName())) {
|
|
||||||
String feignClientServiceName = (String) beanDefinition.getPropertyValues().get("name");
|
|
||||||
feignClientServiceNames.add(feignClientServiceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return feignClientServiceNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RequestInterceptor requestInterceptor() {
|
@ConditionalOnMissingBean
|
||||||
return template -> {
|
public MetadataResolver metadataJsonResolver(ObjectProvider<Contract> contract) {
|
||||||
System.out.println(template);
|
return new FeignMetadataResolver(currentApplicationName, contract);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,269 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
|
||||||
|
|
||||||
import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration;
|
|
||||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
|
||||||
import com.alibaba.dubbo.config.RegistryConfig;
|
|
||||||
import com.alibaba.dubbo.config.spring.ReferenceBean;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import feign.Client;
|
|
||||||
import feign.Request;
|
|
||||||
import feign.Response;
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService;
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver;
|
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Auto-Configuration class for Dubbo REST Discovery
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
|
||||||
*/
|
|
||||||
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = true)
|
|
||||||
@AutoConfigureAfter(value = {
|
|
||||||
DubboAutoConfiguration.class,
|
|
||||||
DubboRestAutoConfiguration.class,
|
|
||||||
DubboRestMetadataRegistrationAutoConfiguration.class})
|
|
||||||
@Configuration
|
|
||||||
public class DubboRestDiscoveryAutoConfiguration {
|
|
||||||
|
|
||||||
private static final String FEIGN_CLIENT_FACTORY_BEAN_CLASS_NAME =
|
|
||||||
"org.springframework.cloud.openfeign.FeignClientFactoryBean";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DiscoveryClient discoveryClient;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private FeignRestMetadataResolver feignRestMetadataResolver;
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
private ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feign Request -> Dubbo ReferenceBean
|
|
||||||
*/
|
|
||||||
private Map<String, ReferenceBean> referenceBeanCache = new HashMap<>();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ApplicationConfig applicationConfig;
|
|
||||||
|
|
||||||
@Value("${spring.application.name}")
|
|
||||||
private String applicationName;
|
|
||||||
|
|
||||||
@Value("${spring.cloud.nacos.discovery.server-addr}")
|
|
||||||
private String nacosServerAddress;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RestMetadataConfigService restMetadataConfigService;
|
|
||||||
|
|
||||||
private ReferenceBean buildReferenceBean(String dubboServiceName) {
|
|
||||||
ReferenceBean referenceBean = new ReferenceBean();
|
|
||||||
applicationConfig.setName("service-consumer");
|
|
||||||
referenceBean.setApplication(applicationConfig);
|
|
||||||
RegistryConfig registryConfig = new RegistryConfig();
|
|
||||||
// requires dubbo-registry-nacos
|
|
||||||
registryConfig.setAddress("nacos://" + nacosServerAddress);
|
|
||||||
referenceBean.setRegistry(registryConfig);
|
|
||||||
String[] parts = StringUtils.delimitedListToStringArray(dubboServiceName, ":");
|
|
||||||
referenceBean.setInterface(parts[1]);
|
|
||||||
referenceBean.setVersion(parts[2]);
|
|
||||||
referenceBean.setGroup(parts.length > 3 ? parts[3] : null);
|
|
||||||
referenceBean.get();
|
|
||||||
return referenceBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public BeanPostProcessor wrapClientBeanPostProcessor() {
|
|
||||||
return new BeanPostProcessor() {
|
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
|
||||||
if (bean instanceof Client) {
|
|
||||||
Client client = (Client) bean;
|
|
||||||
// wrapper
|
|
||||||
return new DubboFeignClientProxy(client);
|
|
||||||
}
|
|
||||||
return bean;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class DubboFeignClientProxy implements Client {
|
|
||||||
|
|
||||||
private final Client delegate;
|
|
||||||
|
|
||||||
DubboFeignClientProxy(Client delegate) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Response execute(Request request, Request.Options options) throws IOException {
|
|
||||||
|
|
||||||
ReferenceBean referenceBean = referenceBeanCache.get(request.toString());
|
|
||||||
|
|
||||||
if (referenceBean != null) {
|
|
||||||
Object dubboClient = referenceBean.get();
|
|
||||||
Method method = null;
|
|
||||||
Object[] params = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Object result = method.invoke(dubboClient, params);
|
|
||||||
// wrapper as a Response
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return delegate.execute(request, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// private Method getRegistrationMethod;
|
|
||||||
//
|
|
||||||
// @PostConstruct
|
|
||||||
// public void init() throws NoSuchMethodException {
|
|
||||||
// getRegistrationMethod = initGetRegistrationMethod();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Initializes {@link AbstractAutoServiceRegistration#getRegistration() getRegistration method} that is is protected.
|
|
||||||
// *
|
|
||||||
// * @return {@link Method}
|
|
||||||
// * @throws NoSuchMethodException
|
|
||||||
// */
|
|
||||||
// private Method initGetRegistrationMethod() throws NoSuchMethodException {
|
|
||||||
// Method method = AbstractAutoServiceRegistration.class.getDeclaredMethod("getRegistration");
|
|
||||||
// method.setAccessible(true);
|
|
||||||
// return method;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private Registration getRegistration(AbstractAutoServiceRegistration source) {
|
|
||||||
// return (Registration) ReflectionUtils.invokeMethod(getRegistrationMethod, source);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void noop() {
|
|
||||||
// Map<String, NamedContextFactory.Specification> specifications =
|
|
||||||
// beanFactory.getBeansOfType(NamedContextFactory.Specification.class);
|
|
||||||
// // 1. Get all service names from Spring beans that was annotated by @FeignClient
|
|
||||||
// List<String> serviceNames = new LinkedList<>();
|
|
||||||
//
|
|
||||||
// specifications.forEach((beanName, specification) ->
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// String serviceName = beanName.substring(0, beanName.indexOf("."));
|
|
||||||
// serviceNames.add(serviceName);
|
|
||||||
//
|
|
||||||
// // 2. Get all service instances by echo specified service name
|
|
||||||
// List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
|
|
||||||
// if (!serviceInstances.isEmpty()) {
|
|
||||||
// ServiceInstance serviceInstance = serviceInstances.get(0);
|
|
||||||
// // 3. Get Rest metadata from service instance
|
|
||||||
// Map<String, String> metadata = serviceInstance.getMetadata();
|
|
||||||
// // 4. Resolve REST metadata from the @FeignClient instance
|
|
||||||
// String restMetadataJson = metadata.get("restMetadata");
|
|
||||||
// /**
|
|
||||||
// * {
|
|
||||||
// * "providers:org.springframework.cloud.alibaba.dubbo.service.EchoService:1.0.0": [
|
|
||||||
// * "{\"method\":\"POST\",\"url\":\"/plus?a={a}&b={b}\",\"headers\":{}}",
|
|
||||||
// * "{\"method\":\"GET\",\"url\":\"/echo?message={message}\",\"headers\":{}}"
|
|
||||||
// * ]
|
|
||||||
// * }
|
|
||||||
// */
|
|
||||||
// try {
|
|
||||||
// Map<String, List<String>> restMetadata = objectMapper.readValue(restMetadataJson, Map.class);
|
|
||||||
//
|
|
||||||
// restMetadata.forEach((dubboServiceName, restJsons) -> {
|
|
||||||
// restJsons.stream().map(feignRestMetadataResolver::resolveRequest).forEach(request -> {
|
|
||||||
// referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName));
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// //
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private ReferenceBean buildReferenceBean(ServiceInstance serviceInstance) {
|
|
||||||
//
|
|
||||||
// ReferenceBean referenceBean = new ReferenceBean();
|
|
||||||
// Map<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(feignRestMetadataResolver::resolveRequest).forEach(request -> {
|
|
||||||
// referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName));
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return referenceBean;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Handle on self instance registered.
|
|
||||||
// *
|
|
||||||
// * @param event {@link InstanceRegisteredEvent}
|
|
||||||
// */
|
|
||||||
// @EventListener(InstanceRegisteredEvent.class)
|
|
||||||
// public void onSelfInstanceRegistered(InstanceRegisteredEvent event) throws Exception {
|
|
||||||
//
|
|
||||||
// Class<?> targetClass = AbstractAutoServiceRegistration.class;
|
|
||||||
//
|
|
||||||
// Object source = event.getSource();
|
|
||||||
//
|
|
||||||
// Assert.isInstanceOf(targetClass, source,
|
|
||||||
// format("The source of %s must implement %s", source, targetClass.getName()));
|
|
||||||
//
|
|
||||||
// Registration registration = getRegistration((AbstractAutoServiceRegistration) source);
|
|
||||||
//
|
|
||||||
// String serviceRestMetaDataConfig =
|
|
||||||
// restMetadataConfigService.getServiceRestMetadata(registration.getServiceId());
|
|
||||||
//
|
|
||||||
// Set<ServiceRestMetadata> serviceRestMetadata = objectMapper.readValue(serviceRestMetaDataConfig,
|
|
||||||
// TypeFactory.defaultInstance().constructCollectionType(Set.class, ServiceRestMetadata.class));
|
|
||||||
//
|
|
||||||
// }
|
|
@ -19,13 +19,13 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
|||||||
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 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.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.FeignRestMetadataResolver;
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataConfigService;
|
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
|
||||||
import org.springframework.cloud.alibaba.dubbo.rest.metadata.ServiceRestMetadata;
|
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
|
||||||
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.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -42,8 +42,14 @@ import java.util.Set;
|
|||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
||||||
|
@ConditionalOnMissingBean(value = {
|
||||||
|
MetadataResolver.class,
|
||||||
|
MetadataConfigService.class
|
||||||
|
})
|
||||||
@AutoConfigureAfter(value = {
|
@AutoConfigureAfter(value = {
|
||||||
DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class})
|
DubboMetadataAutoConfiguration.class,
|
||||||
|
DubboServiceRegistrationAutoConfiguration.class
|
||||||
|
})
|
||||||
@Configuration
|
@Configuration
|
||||||
public class DubboRestMetadataRegistrationAutoConfiguration {
|
public class DubboRestMetadataRegistrationAutoConfiguration {
|
||||||
|
|
||||||
@ -54,19 +60,15 @@ public class DubboRestMetadataRegistrationAutoConfiguration {
|
|||||||
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ObjectMapper objectMapper;
|
private MetadataResolver metadataResolver;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FeignRestMetadataResolver feignRestMetadataResolver;
|
private MetadataConfigService metadataConfigService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RestMetadataConfigService metadataConfigService;
|
|
||||||
|
|
||||||
|
|
||||||
@EventListener(ServiceBeanExportedEvent.class)
|
@EventListener(ServiceBeanExportedEvent.class)
|
||||||
public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
|
public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
|
||||||
ServiceBean serviceBean = event.getServiceBean();
|
ServiceBean serviceBean = event.getServiceBean();
|
||||||
serviceRestMetadata.addAll(feignRestMetadataResolver.resolveServiceRestMetadata(serviceBean));
|
serviceRestMetadata.addAll(metadataResolver.resolveServiceRestMetadata(serviceBean));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,11 +83,7 @@ public class DubboRestMetadataRegistrationAutoConfiguration {
|
|||||||
@EventListener(InstancePreRegisteredEvent.class)
|
@EventListener(InstancePreRegisteredEvent.class)
|
||||||
public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception {
|
public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception {
|
||||||
Registration registration = event.getRegistration();
|
Registration registration = event.getRegistration();
|
||||||
|
metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), serviceRestMetadata);
|
||||||
String restMetadataJson = objectMapper.writeValueAsString(serviceRestMetadata);
|
|
||||||
|
|
||||||
metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), restMetadataJson);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.metadata;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Method} Metadata
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class MethodMetadata {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String returnType;
|
||||||
|
|
||||||
|
private List<MethodParameterMetadata> params;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
private Method method;
|
||||||
|
|
||||||
|
public MethodMetadata() {
|
||||||
|
this.params = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodMetadata(Method method) {
|
||||||
|
this.name = method.getName();
|
||||||
|
this.returnType = ClassUtils.getName(method.getReturnType());
|
||||||
|
this.params = initParameters(method);
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MethodParameterMetadata> initParameters(Method method) {
|
||||||
|
int parameterCount = method.getParameterCount();
|
||||||
|
if (parameterCount < 1) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<MethodParameterMetadata> params = new ArrayList<>(parameterCount);
|
||||||
|
Parameter[] parameters = method.getParameters();
|
||||||
|
for (int i = 0; i < parameterCount; i++) {
|
||||||
|
Parameter parameter = parameters[i];
|
||||||
|
MethodParameterMetadata param = toMethodParameterMetadata(i, parameter);
|
||||||
|
params.add(param);
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodParameterMetadata toMethodParameterMetadata(int index, Parameter parameter) {
|
||||||
|
MethodParameterMetadata metadata = new MethodParameterMetadata();
|
||||||
|
metadata.setIndex(index);
|
||||||
|
metadata.setName(parameter.getName());
|
||||||
|
metadata.setType(parameter.getType().getTypeName());
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReturnType(String returnType) {
|
||||||
|
this.returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MethodParameterMetadata> getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParams(List<MethodParameterMetadata> params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
MethodMetadata that = (MethodMetadata) o;
|
||||||
|
return Objects.equals(name, that.name) &&
|
||||||
|
Objects.equals(returnType, that.returnType) &&
|
||||||
|
Objects.equals(params, that.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name, returnType, params);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.metadata;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Method} Parameter Metadata
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class MethodParameterMetadata {
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
MethodParameterMetadata that = (MethodParameterMetadata) o;
|
||||||
|
return index == that.index &&
|
||||||
|
Objects.equals(name, that.name) &&
|
||||||
|
Objects.equals(type, that.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(index, name, type);
|
||||||
|
}
|
||||||
|
}
|
@ -14,32 +14,37 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.rest.metadata;
|
package org.springframework.cloud.alibaba.dubbo.metadata;
|
||||||
|
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* Request Metadata
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class MethodRestMetadata {
|
public class RequestMetadata {
|
||||||
|
|
||||||
private String configKey;
|
|
||||||
|
|
||||||
private String method;
|
private String method;
|
||||||
|
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
|
private Map<String, Collection<String>> queries;
|
||||||
|
|
||||||
private Map<String, Collection<String>> headers;
|
private Map<String, Collection<String>> headers;
|
||||||
|
|
||||||
private Map<Integer, Collection<String>> indexToName;
|
public RequestMetadata() {
|
||||||
|
|
||||||
public String getConfigKey() {
|
|
||||||
return configKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConfigKey(String configKey) {
|
public RequestMetadata(RequestTemplate requestTemplate) {
|
||||||
this.configKey = configKey;
|
this.method = requestTemplate.method();
|
||||||
|
this.url = requestTemplate.url();
|
||||||
|
this.queries = requestTemplate.queries();
|
||||||
|
this.headers = requestTemplate.headers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMethod() {
|
public String getMethod() {
|
||||||
@ -66,35 +71,27 @@ public class MethodRestMetadata {
|
|||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, Collection<String>> getIndexToName() {
|
public Map<String, Collection<String>> getQueries() {
|
||||||
return indexToName;
|
return queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIndexToName(Map<Integer, Collection<String>> indexToName) {
|
public void setQueries(Map<String, Collection<String>> queries) {
|
||||||
this.indexToName = indexToName;
|
this.queries = queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
RequestMetadata that = (RequestMetadata) o;
|
||||||
MethodRestMetadata that = (MethodRestMetadata) o;
|
return Objects.equals(method, that.method) &&
|
||||||
|
Objects.equals(url, that.url) &&
|
||||||
if (configKey != null ? !configKey.equals(that.configKey) : that.configKey != null) return false;
|
Objects.equals(queries, that.queries) &&
|
||||||
if (method != null ? !method.equals(that.method) : that.method != null) return false;
|
Objects.equals(headers, that.headers);
|
||||||
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = configKey != null ? configKey.hashCode() : 0;
|
return Objects.hash(method, url, queries, headers);
|
||||||
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,72 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.metadata;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method Request Metadata
|
||||||
|
*/
|
||||||
|
public class RestMethodMetadata {
|
||||||
|
|
||||||
|
private MethodMetadata method;
|
||||||
|
|
||||||
|
private RequestMetadata request;
|
||||||
|
|
||||||
|
private Map<Integer, Collection<String>> indexToName;
|
||||||
|
|
||||||
|
public MethodMetadata getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMethod(MethodMetadata method) {
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestMetadata getRequest() {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequest(RequestMetadata request) {
|
||||||
|
this.request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<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;
|
||||||
|
RestMethodMetadata that = (RestMethodMetadata) o;
|
||||||
|
return Objects.equals(method, that.method) &&
|
||||||
|
Objects.equals(request, that.request) &&
|
||||||
|
Objects.equals(indexToName, that.indexToName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(method, request, indexToName);
|
||||||
|
}
|
||||||
|
}
|
@ -14,18 +14,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.rest.metadata;
|
package org.springframework.cloud.alibaba.dubbo.metadata;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* Service Rest Metadata
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
* @see RestMethodMetadata
|
||||||
*/
|
*/
|
||||||
public class ServiceRestMetadata {
|
public class ServiceRestMetadata {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private Set<MethodRestMetadata> meta;
|
private Set<RestMethodMetadata> meta;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
@ -35,11 +38,11 @@ public class ServiceRestMetadata {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<MethodRestMetadata> getMeta() {
|
public Set<RestMethodMetadata> getMeta() {
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMeta(Set<MethodRestMetadata> meta) {
|
public void setMeta(Set<RestMethodMetadata> meta) {
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.metadata.repository;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.config.spring.ReferenceBean;
|
||||||
|
import com.alibaba.dubbo.rpc.service.GenericService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceGroup;
|
||||||
|
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceInterface;
|
||||||
|
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceSegments;
|
||||||
|
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo Service Metadata {@link Repository}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public class DubboServiceMetadataRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key is application name
|
||||||
|
* Value is Map<RequestMetadata, GenericService>
|
||||||
|
*/
|
||||||
|
private Map<String, Map<RequestMetadata, GenericService>> genericServicesRepository = new HashMap<>();
|
||||||
|
|
||||||
|
private Map<String, Map<RequestMetadata, MethodMetadata>> methodMetadataRepository = new HashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MetadataConfigService metadataConfigService;
|
||||||
|
|
||||||
|
@Value("${dubbo.target.protocol:dubbo}")
|
||||||
|
private String targetProtocol;
|
||||||
|
|
||||||
|
@Value("${dubbo.target.cluster:failover}")
|
||||||
|
private String targetCluster;
|
||||||
|
|
||||||
|
public void updateMetadata(String serviceName) {
|
||||||
|
|
||||||
|
Map<RequestMetadata, GenericService> genericServicesMap = genericServicesRepository.computeIfAbsent(serviceName, k -> new HashMap<>());
|
||||||
|
|
||||||
|
Map<RequestMetadata, MethodMetadata> methodMetadataMap = methodMetadataRepository.computeIfAbsent(serviceName, k -> new HashMap<>());
|
||||||
|
|
||||||
|
Set<ServiceRestMetadata> serviceRestMetadataSet = metadataConfigService.getServiceRestMetadata(serviceName);
|
||||||
|
|
||||||
|
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
|
||||||
|
|
||||||
|
ReferenceBean<GenericService> referenceBean = adaptReferenceBean(serviceRestMetadata);
|
||||||
|
|
||||||
|
serviceRestMetadata.getMeta().forEach(restMethodMetadata -> {
|
||||||
|
RequestMetadata requestMetadata = restMethodMetadata.getRequest();
|
||||||
|
genericServicesMap.put(requestMetadata, referenceBean.get());
|
||||||
|
methodMetadataMap.put(requestMetadata, restMethodMetadata.getMethod());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericService getGenericService(String serviceName, RequestMetadata requestMetadata) {
|
||||||
|
return getGenericServicesMap(serviceName).get(requestMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodMetadata getMethodMetadata(String serviceName, RequestMetadata requestMetadata) {
|
||||||
|
return getMethodMetadataMap(serviceName).get(requestMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReferenceBean<GenericService> adaptReferenceBean(ServiceRestMetadata serviceRestMetadata) {
|
||||||
|
String dubboServiceName = serviceRestMetadata.getName();
|
||||||
|
String[] segments = getServiceSegments(dubboServiceName);
|
||||||
|
String interfaceName = getServiceInterface(segments);
|
||||||
|
String version = getServiceVersion(segments);
|
||||||
|
String group = getServiceGroup(segments);
|
||||||
|
|
||||||
|
ReferenceBean<GenericService> referenceBean = new ReferenceBean<GenericService>();
|
||||||
|
referenceBean.setGeneric(true);
|
||||||
|
referenceBean.setInterface(interfaceName);
|
||||||
|
referenceBean.setVersion(version);
|
||||||
|
referenceBean.setGroup(group);
|
||||||
|
referenceBean.setProtocol(targetProtocol);
|
||||||
|
referenceBean.setCluster(targetCluster);
|
||||||
|
|
||||||
|
return referenceBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<RequestMetadata, GenericService> getGenericServicesMap(String serviceName) {
|
||||||
|
return genericServicesRepository.getOrDefault(serviceName, Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<RequestMetadata, MethodMetadata> getMethodMetadataMap(String serviceName) {
|
||||||
|
return methodMetadataRepository.getOrDefault(serviceName, Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,73 +14,60 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.rest.feign;
|
package org.springframework.cloud.alibaba.dubbo.metadata.resolver;
|
||||||
|
|
||||||
import com.alibaba.dubbo.common.URL;
|
import com.alibaba.dubbo.common.URL;
|
||||||
import com.alibaba.dubbo.config.spring.ServiceBean;
|
import com.alibaba.dubbo.config.spring.ServiceBean;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import feign.Contract;
|
import feign.Contract;
|
||||||
|
import feign.Feign;
|
||||||
import feign.MethodMetadata;
|
import feign.MethodMetadata;
|
||||||
import feign.Request;
|
import feign.Util;
|
||||||
import feign.RequestTemplate;
|
|
||||||
import feign.jaxrs2.JAXRS2Contract;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry;
|
import org.springframework.cloud.alibaba.dubbo.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 org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The REST metadata resolver for Feign
|
* The metadata resolver for {@link Feign}
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton {
|
public class FeignMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton, MetadataResolver {
|
||||||
|
|
||||||
private static final String METHOD_PROPERTY_NAME = "method";
|
|
||||||
private static final String URL_PROPERTY_NAME = "url";
|
|
||||||
private static final String HEADERS_PROPERTY_NAME = "headers";
|
|
||||||
|
|
||||||
private static final String[] CONTRACT_CLASS_NAMES = {
|
private static final String[] CONTRACT_CLASS_NAMES = {
|
||||||
"feign.jaxrs2.JAXRS2Contract",
|
"feign.jaxrs2.JAXRS2Contract",
|
||||||
"org.springframework.cloud.openfeign.support.SpringMvcContract",
|
"org.springframework.cloud.openfeign.support.SpringMvcContract",
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final String currentApplicationName;
|
||||||
|
|
||||||
private final ObjectProvider<Contract> contract;
|
private final ObjectProvider<Contract> contract;
|
||||||
|
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Feign Contracts
|
* Feign Contracts
|
||||||
*/
|
*/
|
||||||
private Collection<Contract> contracts;
|
private Collection<Contract> contracts;
|
||||||
|
|
||||||
private ClassLoader classLoader;
|
public FeignMetadataResolver(String currentApplicationName, ObjectProvider<Contract> contract) {
|
||||||
|
this.currentApplicationName = currentApplicationName;
|
||||||
@Value("${spring.application.name}")
|
|
||||||
private String currentApplicationName;
|
|
||||||
|
|
||||||
public FeignRestMetadataResolver(ObjectProvider<ObjectMapper> objectMapper, ObjectProvider<Contract> contract) {
|
|
||||||
this.objectMapper = objectMapper.getIfAvailable();
|
|
||||||
this.contract = contract;
|
this.contract = contract;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,17 +100,16 @@ public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartIni
|
|||||||
return ClassUtils.isPresent(className, classLoader);
|
return ClassUtils.isPresent(className, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Set<ServiceRestMetadata> resolveServiceRestMetadata(ServiceBean serviceBean) {
|
public Set<ServiceRestMetadata> resolveServiceRestMetadata(ServiceBean serviceBean) {
|
||||||
|
|
||||||
Object bean = serviceBean.getRef();
|
Object bean = serviceBean.getRef();
|
||||||
|
|
||||||
Class<?> beanType = bean.getClass();
|
Class<?> beanType = bean.getClass();
|
||||||
|
|
||||||
Class<?> interfaceClass = serviceBean.getInterfaceClass();
|
|
||||||
|
|
||||||
Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||||
|
|
||||||
Set<MethodRestMetadata> methodRestMetadata = resolveMethodRestMetadata(beanType, interfaceClass);
|
Set<RestMethodMetadata> methodRestMetadata = resolveMethodRestMetadata(beanType);
|
||||||
|
|
||||||
List<URL> urls = serviceBean.getExportedUrls();
|
List<URL> urls = serviceBean.getExportedUrls();
|
||||||
|
|
||||||
@ -139,65 +125,61 @@ public class FeignRestMetadataResolver implements BeanClassLoaderAware, SmartIni
|
|||||||
return serviceRestMetadata;
|
return serviceRestMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<MethodRestMetadata> resolveMethodRestMetadata(Class<?> targetClass) {
|
@Override
|
||||||
return resolveMethodRestMetadata(targetClass, targetClass);
|
public Set<RestMethodMetadata> resolveMethodRestMetadata(Class<?> targetType) {
|
||||||
}
|
List<Method> feignContractMethods = selectFeignContractMethods(targetType);
|
||||||
|
|
||||||
protected Set<MethodRestMetadata> resolveMethodRestMetadata(Class<?> targetClass, Class revisedClass) {
|
|
||||||
return contracts.stream()
|
return contracts.stream()
|
||||||
.map(contract -> contract.parseAndValidatateMetadata(targetClass))
|
.map(contract -> contract.parseAndValidatateMetadata(targetType))
|
||||||
.flatMap(v -> v.stream())
|
.flatMap(v -> v.stream())
|
||||||
.map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetClass, revisedClass))
|
.map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetType, feignContractMethods))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toJson(Object object) {
|
/**
|
||||||
String jsonContent = null;
|
* Select feign contract methods
|
||||||
try {
|
* <p>
|
||||||
jsonContent = objectMapper.writeValueAsString(object);
|
* extract some code from {@link Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class)}
|
||||||
} catch (JsonProcessingException e) {
|
*
|
||||||
throw new IllegalArgumentException(e);
|
* @param targetType
|
||||||
|
* @return non-null
|
||||||
|
*/
|
||||||
|
private List<Method> selectFeignContractMethods(Class<?> targetType) {
|
||||||
|
List<Method> methods = new LinkedList<>();
|
||||||
|
for (Method method : targetType.getMethods()) {
|
||||||
|
if (method.getDeclaringClass() == Object.class ||
|
||||||
|
(method.getModifiers() & Modifier.STATIC) != 0 ||
|
||||||
|
Util.isDefault(method)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return jsonContent;
|
methods.add(method);
|
||||||
|
}
|
||||||
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String regenerateConfigKey(String configKey, Class<?> beanType, Class<?> interfaceClass) {
|
protected RestMethodMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class<?> targetType,
|
||||||
if (beanType.equals(interfaceClass)) {
|
List<Method> feignContractMethods) {
|
||||||
return configKey;
|
|
||||||
}
|
|
||||||
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 configKey = methodMetadata.configKey();
|
||||||
String newConfigKey = regenerateConfigKey(configKey, beanType, interfaceClass);
|
Method feignContractMethod = getMatchedFeignContractMethod(targetType, feignContractMethods, configKey);
|
||||||
|
|
||||||
MethodRestMetadata methodRestMetadata = new MethodRestMetadata();
|
RestMethodMetadata metadata = new RestMethodMetadata();
|
||||||
methodRestMetadata.setConfigKey(newConfigKey);
|
|
||||||
methodRestMetadata.setMethod(request.method());
|
|
||||||
methodRestMetadata.setUrl(request.url());
|
|
||||||
methodRestMetadata.setHeaders(request.headers());
|
|
||||||
methodRestMetadata.setIndexToName(methodMetadata.indexToName());
|
|
||||||
|
|
||||||
return methodRestMetadata;
|
metadata.setRequest(new RequestMetadata(methodMetadata.template()));
|
||||||
|
metadata.setMethod(new org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata(feignContractMethod));
|
||||||
|
metadata.setIndexToName(methodMetadata.indexToName());
|
||||||
|
|
||||||
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request resolveRequest(String json) {
|
private Method getMatchedFeignContractMethod(Class<?> targetType, List<Method> methods, String expectedConfigKey) {
|
||||||
Request request = null;
|
Method matchedMethod = null;
|
||||||
try {
|
for (Method method : methods) {
|
||||||
Map<String, Object> data = objectMapper.readValue(json, Map.class);
|
String configKey = Feign.configKey(targetType, method);
|
||||||
String method = (String) data.get(METHOD_PROPERTY_NAME);
|
if (expectedConfigKey.equals(configKey)) {
|
||||||
String url = (String) data.get(URL_PROPERTY_NAME);
|
matchedMethod = method;
|
||||||
Map<String, Collection<String>> headers = (Map) data.get(HEADERS_PROPERTY_NAME);
|
break;
|
||||||
request = Request.create(method, url, headers, null, null);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
}
|
||||||
return request;
|
}
|
||||||
|
return matchedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.metadata.resolver;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.config.spring.ServiceBean;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The REST metadata resolver
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public interface MetadataResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the {@link ServiceRestMetadata} {@link Set set} from {@link ServiceBean}
|
||||||
|
*
|
||||||
|
* @param serviceBean {@link ServiceBean}
|
||||||
|
* @return non-null {@link Set}
|
||||||
|
*/
|
||||||
|
Set<ServiceRestMetadata> resolveServiceRestMetadata(ServiceBean serviceBean);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve {@link RestMethodMetadata} {@link Set set} from {@link Class target type}
|
||||||
|
*
|
||||||
|
* @param targetType {@link Class target type}
|
||||||
|
* @return non-null {@link Set}
|
||||||
|
*/
|
||||||
|
Set<RestMethodMetadata> resolveMethodRestMetadata(Class<?> targetType);
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.metadata.service;
|
||||||
|
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config Service for Metadata
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public interface MetadataConfigService {
|
||||||
|
|
||||||
|
void publishServiceRestMetadata(String serviceName, Set<ServiceRestMetadata> serviceRestMetadata);
|
||||||
|
|
||||||
|
Set<ServiceRestMetadata> getServiceRestMetadata(String serviceName);
|
||||||
|
}
|
@ -14,23 +14,33 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.rest.feign;
|
package org.springframework.cloud.alibaba.dubbo.metadata.service;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.config.ConfigService;
|
import com.alibaba.nacos.api.config.ConfigService;
|
||||||
import com.alibaba.nacos.api.exception.NacosException;
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
|
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
|
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rest Metadata Config Service
|
* Nacos {@link MetadataConfigService}
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class RestMetadataConfigService {
|
public class NacosMetadataConfigService implements MetadataConfigService {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private NacosConfigProperties nacosConfigProperties;
|
private NacosConfigProperties nacosConfigProperties;
|
||||||
@ -40,24 +50,48 @@ public class RestMetadataConfigService {
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
this.configService = nacosConfigProperties.configServiceInstance();
|
this.configService = nacosConfigProperties.configServiceInstance();
|
||||||
|
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data Id of service rest metadata
|
* Get the data Id of service rest metadata
|
||||||
* TODO JavaDoc
|
|
||||||
*/
|
*/
|
||||||
private static String getServiceRestMetadataDataId(String serviceName) {
|
private static String getServiceRestMetadataDataId(String serviceName) {
|
||||||
return "metadata:rest:" + serviceName + ".json";
|
return "metadata:rest:" + serviceName + ".json";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publishServiceRestMetadata(String serviceName, String restMetadataJSON)
|
@Override
|
||||||
throws NacosException {
|
public void publishServiceRestMetadata(String serviceName, Set<ServiceRestMetadata> serviceRestMetadata) {
|
||||||
String dataId = getServiceRestMetadataDataId(serviceName);
|
String dataId = getServiceRestMetadataDataId(serviceName);
|
||||||
configService.publishConfig(dataId, DEFAULT_GROUP, restMetadataJSON);
|
String json = writeValueAsString(serviceRestMetadata);
|
||||||
|
try {
|
||||||
|
configService.publishConfig(dataId, DEFAULT_GROUP, json);
|
||||||
|
} catch (NacosException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServiceRestMetadata(String serviceName) throws NacosException {
|
@Override
|
||||||
|
public Set<ServiceRestMetadata> getServiceRestMetadata(String serviceName) {
|
||||||
|
Set<ServiceRestMetadata> metadata = Collections.emptySet();
|
||||||
String dataId = getServiceRestMetadataDataId(serviceName);
|
String dataId = getServiceRestMetadataDataId(serviceName);
|
||||||
return configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3);
|
try {
|
||||||
|
String json = configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3);
|
||||||
|
metadata = objectMapper.readValue(json,
|
||||||
|
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String writeValueAsString(Object object) {
|
||||||
|
String content = null;
|
||||||
|
try {
|
||||||
|
content = objectMapper.writeValueAsString(object);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,13 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.openfeign;
|
package org.springframework.cloud.alibaba.dubbo.openfeign;
|
||||||
|
|
||||||
import feign.*;
|
import feign.Contract;
|
||||||
import feign.codec.Decoder;
|
import feign.Feign;
|
||||||
import feign.codec.Encoder;
|
|
||||||
import feign.codec.ErrorDecoder;
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration;
|
import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
|
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -41,6 +41,12 @@ import java.util.List;
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class DubboFeignClientsConfiguration {
|
public class DubboFeignClientsConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Contract contract;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DubboServiceMetadataRepository dubboServiceRepository;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public BeanPostProcessor beanPostProcessor() {
|
public BeanPostProcessor beanPostProcessor() {
|
||||||
return new BeanPostProcessor() {
|
return new BeanPostProcessor() {
|
||||||
@ -48,132 +54,12 @@ public class DubboFeignClientsConfiguration {
|
|||||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
if (bean instanceof Feign.Builder) {
|
if (bean instanceof Feign.Builder) {
|
||||||
Feign.Builder builder = (Feign.Builder) bean;
|
Feign.Builder builder = (Feign.Builder) bean;
|
||||||
BuilderWrapper wrapper = new BuilderWrapper(builder);
|
builder.invocationHandlerFactory(new DubboInvocationHandlerFactory(contract, dubboServiceRepository));
|
||||||
return wrapper;
|
|
||||||
}
|
}
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BuilderWrapper extends Feign.Builder {
|
|
||||||
|
|
||||||
private final Feign.Builder delegate;
|
|
||||||
|
|
||||||
private BuilderWrapper(Feign.Builder delegate) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder logLevel(Logger.Level logLevel) {
|
|
||||||
return delegate.logLevel(logLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder contract(Contract contract) {
|
|
||||||
delegate.contract(contract);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder client(Client client) {
|
|
||||||
delegate.client(client);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder retryer(Retryer retryer) {
|
|
||||||
delegate.retryer(retryer);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder logger(Logger logger) {
|
|
||||||
delegate.logger(logger);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder encoder(Encoder encoder) {
|
|
||||||
delegate.encoder(encoder);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder decoder(Decoder decoder) {
|
|
||||||
delegate.decoder(decoder);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder queryMapEncoder(QueryMapEncoder queryMapEncoder) {
|
|
||||||
delegate.queryMapEncoder(queryMapEncoder);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
|
|
||||||
delegate.mapAndDecode(mapper, decoder);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder decode404() {
|
|
||||||
delegate.decode404();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder errorDecoder(ErrorDecoder errorDecoder) {
|
|
||||||
delegate.errorDecoder(errorDecoder);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder options(Request.Options options) {
|
|
||||||
delegate.options(options);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder requestInterceptor(RequestInterceptor requestInterceptor) {
|
|
||||||
delegate.requestInterceptor(requestInterceptor);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder requestInterceptors(Iterable<RequestInterceptor> requestInterceptors) {
|
|
||||||
delegate.requestInterceptors(requestInterceptors);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
|
|
||||||
delegate.invocationHandlerFactory(invocationHandlerFactory);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign.Builder doNotCloseAfterDecode() {
|
|
||||||
delegate.doNotCloseAfterDecode();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T target(Class<T> apiType, String url) {
|
|
||||||
return delegate.target(apiType, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T target(Target<T> target) {
|
|
||||||
return delegate.target(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Feign build() {
|
|
||||||
return delegate.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.openfeign;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.rpc.service.GenericService;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo {@link GenericService} for {@link InvocationHandler}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class DubboInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
|
private final Map<Method, GenericService> genericServicesMap;
|
||||||
|
|
||||||
|
private final Map<Method, MethodMetadata> methodMetadata;
|
||||||
|
|
||||||
|
private final InvocationHandler defaultInvocationHandler;
|
||||||
|
|
||||||
|
public DubboInvocationHandler(Map<Method, GenericService> genericServicesMap,
|
||||||
|
Map<Method, MethodMetadata> methodMetadata,
|
||||||
|
InvocationHandler defaultInvocationHandler) {
|
||||||
|
this.genericServicesMap = genericServicesMap;
|
||||||
|
this.methodMetadata = methodMetadata;
|
||||||
|
this.defaultInvocationHandler = defaultInvocationHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
|
||||||
|
GenericService genericService = genericServicesMap.get(method);
|
||||||
|
|
||||||
|
MethodMetadata methodMetadata = this.methodMetadata.get(method);
|
||||||
|
|
||||||
|
if (genericService == null || methodMetadata == null) {
|
||||||
|
return defaultInvocationHandler.invoke(proxy, method, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
String methodName = methodMetadata.getName();
|
||||||
|
|
||||||
|
String[] parameterTypes = methodMetadata
|
||||||
|
.getParams()
|
||||||
|
.stream()
|
||||||
|
.map(MethodParameterMetadata::getType)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
|
||||||
|
return genericService.$invoke(methodName, parameterTypes, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.cloud.alibaba.dubbo.openfeign;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.rpc.service.GenericService;
|
||||||
|
import feign.Contract;
|
||||||
|
import feign.InvocationHandlerFactory;
|
||||||
|
import feign.MethodMetadata;
|
||||||
|
import feign.Target;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static feign.Feign.configKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo {@link InvocationHandlerFactory}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class DubboInvocationHandlerFactory implements InvocationHandlerFactory {
|
||||||
|
|
||||||
|
private final static InvocationHandlerFactory DEFAULT_INVOCATION_HANDLER_FACTORY =
|
||||||
|
new InvocationHandlerFactory.Default();
|
||||||
|
|
||||||
|
private final Contract contract;
|
||||||
|
|
||||||
|
private final DubboServiceMetadataRepository dubboServiceRepository;
|
||||||
|
|
||||||
|
public DubboInvocationHandlerFactory(Contract contract, DubboServiceMetadataRepository dubboServiceRepository) {
|
||||||
|
this.contract = contract;
|
||||||
|
this.dubboServiceRepository = dubboServiceRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
|
||||||
|
// The target class annotated @FeignClient
|
||||||
|
Class<?> targetType = target.type();
|
||||||
|
// Resolve metadata from current @FeignClient type
|
||||||
|
Map<Method, RequestMetadata> methodRequestMetadataMap = resolveMethodRequestMetadataMap(targetType, dispatch.keySet());
|
||||||
|
// @FeignClient specifies the service name
|
||||||
|
String serviceName = target.name();
|
||||||
|
// Update specified metadata
|
||||||
|
dubboServiceRepository.updateMetadata(serviceName);
|
||||||
|
|
||||||
|
Map<Method, GenericService> genericServicesMap = new HashMap<>();
|
||||||
|
|
||||||
|
Map<Method, org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata> methodMetadataMap = new HashMap<>();
|
||||||
|
|
||||||
|
methodRequestMetadataMap.forEach((method, requestMetadata) -> {
|
||||||
|
GenericService genericService = dubboServiceRepository.getGenericService(serviceName, requestMetadata);
|
||||||
|
org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata =
|
||||||
|
dubboServiceRepository.getMethodMetadata(serviceName, requestMetadata);
|
||||||
|
genericServicesMap.put(method, genericService);
|
||||||
|
methodMetadataMap.put(method, methodMetadata);
|
||||||
|
});
|
||||||
|
|
||||||
|
InvocationHandler defaultInvocationHandler = DEFAULT_INVOCATION_HANDLER_FACTORY.create(target, dispatch);
|
||||||
|
|
||||||
|
DubboInvocationHandler invocationHandler = new DubboInvocationHandler(genericServicesMap, methodMetadataMap,
|
||||||
|
defaultInvocationHandler);
|
||||||
|
|
||||||
|
return invocationHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Method, RequestMetadata> resolveMethodRequestMetadataMap(Class<?> targetType, Set<Method> methods) {
|
||||||
|
Map<String, RequestMetadata> requestMetadataMap = resolveRequestMetadataMap(targetType);
|
||||||
|
return methods.stream().collect(Collectors.toMap(method -> method, method ->
|
||||||
|
requestMetadataMap.get(configKey(targetType, method))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, RequestMetadata> resolveRequestMetadataMap(Class<?> targetType) {
|
||||||
|
return contract.parseAndValidatateMetadata(targetType)
|
||||||
|
.stream().collect(Collectors.toMap(MethodMetadata::configKey, this::requestMetadata));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestMetadata requestMetadata(MethodMetadata methodMetadata) {
|
||||||
|
return new RequestMetadata(methodMetadata.template());
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,6 @@ import com.alibaba.dubbo.common.utils.UrlUtils;
|
|||||||
import com.alibaba.dubbo.registry.NotifyListener;
|
import com.alibaba.dubbo.registry.NotifyListener;
|
||||||
import com.alibaba.dubbo.registry.RegistryFactory;
|
import com.alibaba.dubbo.registry.RegistryFactory;
|
||||||
import com.alibaba.dubbo.registry.support.FailbackRegistry;
|
import com.alibaba.dubbo.registry.support.FailbackRegistry;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||||
@ -48,6 +47,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
|
import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
|
||||||
import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
|
import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
|
||||||
|
import static com.alibaba.dubbo.common.Constants.PROTOCOL_KEY;
|
||||||
import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
|
import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
|
||||||
import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY;
|
import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY;
|
||||||
|
|
||||||
@ -70,11 +70,13 @@ public class SpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
private static final int CATEGORY_INDEX = 0;
|
private static final int CATEGORY_INDEX = 0;
|
||||||
|
|
||||||
private static final int SERVICE_INTERFACE_INDEX = 1;
|
private static final int PROTOCOL_INDEX = CATEGORY_INDEX + 1;
|
||||||
|
|
||||||
private static final int SERVICE_VERSION_INDEX = 2;
|
private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1;
|
||||||
|
|
||||||
private static final int SERVICE_GROUP_INDEX = 3;
|
private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
|
||||||
|
|
||||||
|
private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1;
|
||||||
|
|
||||||
private static final String WILDCARD = "*";
|
private static final String WILDCARD = "*";
|
||||||
|
|
||||||
@ -167,6 +169,7 @@ public class SpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
private static String getServiceName(URL url, String category) {
|
private static String getServiceName(URL url, String category) {
|
||||||
StringBuilder serviceNameBuilder = new StringBuilder(category);
|
StringBuilder serviceNameBuilder = new StringBuilder(category);
|
||||||
|
appendIfPresent(serviceNameBuilder, url.getParameter(PROTOCOL_KEY, url.getProtocol()));
|
||||||
appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
|
appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
|
||||||
appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
|
appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
|
||||||
appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
|
appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
|
||||||
@ -175,6 +178,10 @@ public class SpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
private static void appendIfPresent(StringBuilder target, URL url, String parameterName) {
|
private static void appendIfPresent(StringBuilder target, URL url, String parameterName) {
|
||||||
String parameterValue = url.getParameter(parameterName);
|
String parameterValue = url.getParameter(parameterName);
|
||||||
|
appendIfPresent(target, parameterValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendIfPresent(StringBuilder target, String parameterValue) {
|
||||||
if (StringUtils.hasText(parameterValue)) {
|
if (StringUtils.hasText(parameterValue)) {
|
||||||
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
|
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
|
||||||
}
|
}
|
||||||
@ -196,32 +203,38 @@ public class SpringCloudRegistry extends FailbackRegistry {
|
|||||||
// split service name to segments
|
// split service name to segments
|
||||||
// (required) segments[0] = category
|
// (required) segments[0] = category
|
||||||
// (required) segments[1] = serviceInterface
|
// (required) segments[1] = serviceInterface
|
||||||
// (required) segments[2] = version
|
// (required) segments[2] = protocol
|
||||||
// (optional) segments[3] = group
|
// (required) segments[3] = version
|
||||||
String[] segments = StringUtils.split(serviceName, SERVICE_NAME_SEPARATOR);
|
// (optional) segments[4] = group
|
||||||
|
String[] segments = getServiceSegments(serviceName);
|
||||||
int length = segments.length;
|
int length = segments.length;
|
||||||
if (length < 3) { // must present 3 segments or more
|
if (length < 4) { // must present 4 segments or more
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String category = segments[CATEGORY_INDEX];
|
String category = getCategory(segments);
|
||||||
if (Arrays.binarySearch(categories, category) > -1) { // no match category
|
if (Arrays.binarySearch(categories, category) > -1) { // no match category
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String serviceInterface = segments[SERVICE_INTERFACE_INDEX];
|
String protocol = getProtocol(segments);
|
||||||
|
if (StringUtils.hasText(protocol)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String serviceInterface = getServiceInterface(segments);
|
||||||
if (!WILDCARD.equals(targetServiceInterface) &&
|
if (!WILDCARD.equals(targetServiceInterface) &&
|
||||||
!Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface
|
!Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String version = segments[SERVICE_VERSION_INDEX];
|
String version = getServiceVersion(segments);
|
||||||
if (!WILDCARD.equals(targetVersion) &&
|
if (!WILDCARD.equals(targetVersion) &&
|
||||||
!Objects.equals(targetVersion, version)) { // no match service version
|
!Objects.equals(targetVersion, version)) { // no match service version
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String group = length > 3 ? segments[SERVICE_GROUP_INDEX] : null;
|
String group = getServiceGroup(segments);
|
||||||
if (group != null && !WILDCARD.equals(targetGroup)
|
if (group != null && !WILDCARD.equals(targetGroup)
|
||||||
&& !Objects.equals(targetGroup, group)) { // no match service group
|
&& !Objects.equals(targetGroup, group)) { // no match service group
|
||||||
return false;
|
return false;
|
||||||
@ -232,6 +245,30 @@ public class SpringCloudRegistry extends FailbackRegistry {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String[] getServiceSegments(String serviceName) {
|
||||||
|
return StringUtils.delimitedListToStringArray(serviceName, SERVICE_NAME_SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCategory(String[] segments) {
|
||||||
|
return segments[CATEGORY_INDEX];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getProtocol(String[] segments) {
|
||||||
|
return segments[PROTOCOL_INDEX];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getServiceInterface(String[] segments) {
|
||||||
|
return segments[SERVICE_INTERFACE_INDEX];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getServiceVersion(String[] segments) {
|
||||||
|
return segments[SERVICE_VERSION_INDEX];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getServiceGroup(String[] segments) {
|
||||||
|
return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the categories from {@link URL}
|
* Get the categories from {@link URL}
|
||||||
*
|
*
|
||||||
@ -333,7 +370,8 @@ public class SpringCloudRegistry extends FailbackRegistry {
|
|||||||
@Override
|
@Override
|
||||||
public boolean accept(ServiceInstance data) {
|
public boolean accept(ServiceInstance data) {
|
||||||
// TODO check the details of status
|
// TODO check the details of status
|
||||||
return serviceRegistry.getStatus(new DubboRegistration(data)) != null;
|
// return serviceRegistry.getStatus(new DubboRegistration(data)) != null;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\
|
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\
|
||||||
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
|
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
|
||||||
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
|
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
|
||||||
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\
|
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration
|
||||||
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestDiscoveryAutoConfiguration
|
|
||||||
|
@ -16,35 +16,27 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.bootstrap;
|
package org.springframework.cloud.alibaba.dubbo.bootstrap;
|
||||||
|
|
||||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
|
||||||
import com.alibaba.dubbo.config.RegistryConfig;
|
|
||||||
import com.alibaba.dubbo.config.annotation.Reference;
|
import com.alibaba.dubbo.config.annotation.Reference;
|
||||||
import com.alibaba.dubbo.config.spring.ReferenceBean;
|
|
||||||
import com.alibaba.dubbo.config.spring.ServiceBean;
|
|
||||||
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
import org.springframework.cloud.alibaba.dubbo.service.EchoService;
|
import org.springframework.cloud.alibaba.dubbo.service.EchoService;
|
||||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo Spring Cloud Bootstrap
|
* Dubbo Spring Cloud Bootstrap
|
||||||
*/
|
*/
|
||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
@EnableScheduling
|
|
||||||
@RestController
|
@RestController
|
||||||
public class DubboSpringCloudBootstrap {
|
public class DubboSpringCloudBootstrap {
|
||||||
|
|
||||||
@ -67,38 +59,16 @@ public class DubboSpringCloudBootstrap {
|
|||||||
String echo(@RequestParam("message") String message);
|
String echo(@RequestParam("message") String message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Bean
|
@Bean
|
||||||
// public ApplicationRunner applicationRunner() {
|
public ApplicationRunner applicationRunner() {
|
||||||
// return arguments -> {
|
return arguments -> {
|
||||||
// // Dubbo Service call
|
// Dubbo Service call
|
||||||
// System.out.println(echoService.echo("mercyblitz"));
|
System.out.println(echoService.echo("mercyblitz"));
|
||||||
// // Spring Cloud Open Feign REST Call
|
// Spring Cloud Open Feign REST Call
|
||||||
// System.out.println(feignEchoService.echo("mercyblitz"));
|
System.out.println(feignEchoService.echo("mercyblitz"));
|
||||||
// };
|
};
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ApplicationConfig applicationConfig;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private List<RegistryConfig> registries;
|
|
||||||
|
|
||||||
@EventListener(ServiceBeanExportedEvent.class)
|
|
||||||
public void onServiceBeanExportedEvent(ServiceBeanExportedEvent event) {
|
|
||||||
ServiceBean serviceBean = event.getServiceBean();
|
|
||||||
ReferenceBean referenceBean = new ReferenceBean();
|
|
||||||
referenceBean.setApplication(applicationConfig);
|
|
||||||
referenceBean.setRegistries(registries);
|
|
||||||
referenceBean.setInterface(serviceBean.getInterfaceClass());
|
|
||||||
referenceBean.setInterface(serviceBean.getInterface());
|
|
||||||
referenceBean.setVersion(serviceBean.getVersion());
|
|
||||||
referenceBean.setGroup(serviceBean.getGroup());
|
|
||||||
Object object = referenceBean.get();
|
|
||||||
System.out.println(object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
|
new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
|
||||||
.run(args);
|
.run(args);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user