1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00
This commit is contained in:
mercyblitz 2019-02-20 01:31:22 +08:00
parent d05c437d89
commit c0430abcae
13 changed files with 393 additions and 109 deletions

View File

@ -27,15 +27,19 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported; import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported;
import org.springframework.cloud.alibaba.dubbo.client.loadbalancer.DubboAdapterLoadBalancerInterceptor; import org.springframework.cloud.alibaba.dubbo.client.loadbalancer.DubboAdapterLoadBalancerInterceptor;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration; import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer; import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.MethodMetadata;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.ArrayList; import java.util.ArrayList;
@ -66,6 +70,12 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClass
@Autowired @Autowired
private ConfigurableListableBeanFactory beanFactory; private ConfigurableListableBeanFactory beanFactory;
@Autowired
private DubboGenericServiceFactory dubboGenericServiceFactory;
@Autowired
private Environment environment;
@LoadBalanced @LoadBalanced
@Autowired(required = false) @Autowired(required = false)
private Map<String, RestTemplate> restTemplates = Collections.emptyMap(); private Map<String, RestTemplate> restTemplates = Collections.emptyMap();
@ -82,37 +92,43 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClass
public void adaptRestTemplates() { public void adaptRestTemplates() {
for (Map.Entry<String, RestTemplate> entry : restTemplates.entrySet()) { for (Map.Entry<String, RestTemplate> entry : restTemplates.entrySet()) {
String beanName = entry.getKey(); String beanName = entry.getKey();
if (isDubboTranslatedAnnotated(beanName)) { Map<String, Object> dubboTranslatedAttributes = getDubboTranslatedAttributes(beanName);
adaptRestTemplate(entry.getValue()); if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) {
adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes);
} }
} }
} }
/** /**
* Judge {@link RestTemplate} bean being annotated {@link DubboTransported @DubboTransported} or not * Gets the annotation attributes {@link RestTemplate} bean being annotated
* {@link DubboTransported @DubboTransported}
* *
* @param beanName the bean name of {@link LoadBalanced @LoadBalanced} {@link RestTemplate} * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} {@link RestTemplate}
* @return * @return non-null {@link Map}
*/ */
private boolean isDubboTranslatedAnnotated(String beanName) { private Map<String, Object> getDubboTranslatedAttributes(String beanName) {
boolean annotated = false; Map<String, Object> attributes = Collections.emptyMap();
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedBeanDefinition) { if (beanDefinition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata(); MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
annotated = factoryMethodMetadata != null && attributes = factoryMethodMetadata != null ?
!factoryMethodMetadata.getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME).isEmpty(); factoryMethodMetadata.getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME) : Collections.emptyMap();
} }
return annotated; return attributes;
} }
/** /**
* Adapt the instance of {@link DubboAdapterLoadBalancerInterceptor} to the {@link LoadBalancerInterceptor} Bean. * Adapt the instance of {@link DubboAdapterLoadBalancerInterceptor} to the {@link LoadBalancerInterceptor} Bean.
* *
* @param restTemplate {@link LoadBalanced @LoadBalanced} {@link RestTemplate} Bean * @param restTemplate {@link LoadBalanced @LoadBalanced} {@link RestTemplate} Bean
* @param dubboTranslatedAttributes the annotation dubboTranslatedAttributes {@link RestTemplate} bean being annotated
* {@link DubboTransported @DubboTransported}
*/ */
private void adaptRestTemplate(RestTemplate restTemplate) { private void adaptRestTemplate(RestTemplate restTemplate, Map<String, Object> dubboTranslatedAttributes) {
DubboTransportedMetadata dubboTransportedMetadata = buildDubboTransportedMetadata(dubboTranslatedAttributes);
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(restTemplate.getInterceptors()); List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(restTemplate.getInterceptors());
@ -120,12 +136,23 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClass
if (index > -1) { if (index > -1) {
interceptors.set(index, new DubboAdapterLoadBalancerInterceptor(repository, loadBalancerInterceptor, interceptors.set(index, new DubboAdapterLoadBalancerInterceptor(repository, loadBalancerInterceptor,
restTemplate.getMessageConverters(),classLoader)); restTemplate.getMessageConverters(), classLoader,
dubboTransportedMetadata, dubboGenericServiceFactory));
} }
restTemplate.setInterceptors(interceptors); restTemplate.setInterceptors(interceptors);
} }
private DubboTransportedMetadata buildDubboTransportedMetadata(Map<String, Object> dubboTranslatedAttributes) {
DubboTransportedMetadata dubboTransportedMetadata = new DubboTransportedMetadata();
String protocol = (String) dubboTranslatedAttributes.get("protocol");
String cluster = (String) dubboTranslatedAttributes.get("cluster");
// resolve placeholders
dubboTransportedMetadata.setProtocol(environment.resolvePlaceholders(protocol));
dubboTransportedMetadata.setCluster(environment.resolvePlaceholders(cluster));
return dubboTransportedMetadata;
}
@Override @Override
public void setBeanClassLoader(ClassLoader classLoader) { public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;

View File

@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory;
import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor; import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor;
import org.springframework.cloud.openfeign.FeignAutoConfiguration; import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -54,8 +55,9 @@ public class DubboOpenFeignAutoConfiguration {
@Bean @Bean
public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment, public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment,
DubboServiceMetadataRepository dubboServiceMetadataRepository) { DubboServiceMetadataRepository dubboServiceMetadataRepository,
return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository); DubboGenericServiceFactory dubboGenericServiceFactory) {
return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository,dubboGenericServiceFactory);
} }
} }

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Spring Boot Auto-Configuration class for Dubbo Service
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Configuration
public class DubboServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DubboGenericServiceFactory dubboGenericServiceFactory() {
return new DubboGenericServiceFactory();
}
}

View File

@ -16,15 +16,17 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.client.loadbalancer; package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.rpc.service.GenericException; import com.alibaba.dubbo.rpc.service.GenericException;
import com.alibaba.dubbo.rpc.service.GenericService; import com.alibaba.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.ParameterResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.ParameterResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestExecution;
@ -52,18 +54,23 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt
private final LoadBalancerInterceptor loadBalancerInterceptor; private final LoadBalancerInterceptor loadBalancerInterceptor;
private final List<HttpMessageConverter<?>> messageConverters;
private final DubboClientHttpResponseFactory clientHttpResponseFactory; private final DubboClientHttpResponseFactory clientHttpResponseFactory;
private final DubboTransportedMetadata dubboTransportedMetadata;
private final DubboGenericServiceFactory dubboGenericServiceFactory;
public DubboAdapterLoadBalancerInterceptor(DubboServiceMetadataRepository dubboServiceMetadataRepository, public DubboAdapterLoadBalancerInterceptor(DubboServiceMetadataRepository dubboServiceMetadataRepository,
LoadBalancerInterceptor loadBalancerInterceptor, LoadBalancerInterceptor loadBalancerInterceptor,
List<HttpMessageConverter<?>> messageConverters, List<HttpMessageConverter<?>> messageConverters,
ClassLoader classLoader) { ClassLoader classLoader,
DubboTransportedMetadata dubboTransportedMetadata,
DubboGenericServiceFactory dubboGenericServiceFactory) {
this.repository = dubboServiceMetadataRepository; this.repository = dubboServiceMetadataRepository;
this.loadBalancerInterceptor = loadBalancerInterceptor; this.loadBalancerInterceptor = loadBalancerInterceptor;
this.messageConverters = messageConverters; this.dubboTransportedMetadata = dubboTransportedMetadata;
this.clientHttpResponseFactory = new DubboClientHttpResponseFactory(messageConverters, classLoader); this.clientHttpResponseFactory = new DubboClientHttpResponseFactory(messageConverters, classLoader);
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
} }
@Override @Override
@ -79,19 +86,21 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt
RequestMetadata clientMetadata = buildRequestMetadata(request, uriComponents); RequestMetadata clientMetadata = buildRequestMetadata(request, uriComponents);
RestMethodMetadata restMethodMetadata = repository.getRestMethodMetadata(serviceName, clientMetadata); DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, clientMetadata);
ReferenceBean<GenericService> referenceBean = repository.getReferenceBean(serviceName, clientMetadata); if (dubboServiceMetadata == null) { // if DubboServiceMetadata is not found
if (referenceBean == null || restMethodMetadata == null) {
return loadBalancerInterceptor.intercept(request, body, execution); return loadBalancerInterceptor.intercept(request, body, execution);
} }
RestMethodMetadata restMethodMetadata = dubboServiceMetadata.getRestMethodMetadata();
GenericService genericService = dubboGenericServiceFactory.create(dubboServiceMetadata, dubboTransportedMetadata);
Object result = null; Object result = null;
GenericException exception = null; GenericException exception = null;
try { try {
result = invokeService(restMethodMetadata, referenceBean, clientMetadata); result = invokeService(restMethodMetadata, genericService, clientMetadata);
} catch (GenericException e) { } catch (GenericException e) {
exception = e; exception = e;
} }
@ -99,7 +108,7 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt
return clientHttpResponseFactory.build(result, exception, clientMetadata, restMethodMetadata); return clientHttpResponseFactory.build(result, exception, clientMetadata, restMethodMetadata);
} }
private Object invokeService(RestMethodMetadata restMethodMetadata, ReferenceBean<GenericService> referenceBean, private Object invokeService(RestMethodMetadata restMethodMetadata, GenericService genericService,
RequestMetadata clientMetadata) throws GenericException { RequestMetadata clientMetadata) throws GenericException {
MethodMetadata methodMetadata = restMethodMetadata.getMethod(); MethodMetadata methodMetadata = restMethodMetadata.getMethod();
@ -110,8 +119,6 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt
Object[] parameters = parameterResolver.resolveParameters(restMethodMetadata, clientMetadata); Object[] parameters = parameterResolver.resolveParameters(restMethodMetadata, clientMetadata);
GenericService genericService = referenceBean.get();
Object result = genericService.$invoke(methodName, parameterTypes, parameters); Object result = genericService.$invoke(methodName, parameterTypes, parameters);
return result; return result;

View File

@ -0,0 +1,58 @@
/*
* 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.Objects;
/**
* Dubbo Service Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class DubboServiceMetadata {
private final ServiceRestMetadata serviceRestMetadata;
private final RestMethodMetadata restMethodMetadata;
public DubboServiceMetadata(ServiceRestMetadata serviceRestMetadata, RestMethodMetadata restMethodMetadata) {
this.serviceRestMetadata = serviceRestMetadata;
this.restMethodMetadata = restMethodMetadata;
}
public ServiceRestMetadata getServiceRestMetadata() {
return serviceRestMetadata;
}
public RestMethodMetadata getRestMethodMetadata() {
return restMethodMetadata;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DubboServiceMetadata)) return false;
DubboServiceMetadata that = (DubboServiceMetadata) o;
return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) &&
Objects.equals(restMethodMetadata, that.restMethodMetadata);
}
@Override
public int hashCode() {
return Objects.hash(serviceRestMetadata, restMethodMetadata);
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.metadata;
import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported;
import java.util.Objects;
/**
* {@link DubboTransported @DubboTransported} Metadata
*/
public class DubboTransportedMetadata {
private String protocol;
private String cluster;
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getCluster() {
return cluster;
}
public void setCluster(String cluster) {
this.cluster = cluster;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DubboTransportedMetadata)) return false;
DubboTransportedMetadata that = (DubboTransportedMetadata) o;
return Objects.equals(protocol, that.protocol) &&
Objects.equals(cluster, that.cluster);
}
@Override
public int hashCode() {
return Objects.hash(protocol, cluster);
}
}

View File

@ -19,55 +19,88 @@ package org.springframework.cloud.alibaba.dubbo.metadata;
import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported; import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
/** /**
* {@link MethodMetadata} annotated {@link DubboTransported @DubboTransported} * {@link MethodMetadata} annotated {@link DubboTransported @DubboTransported}
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
public class DubboTransportedMethodMetadata extends MethodMetadata { public class DubboTransportedMethodMetadata {
private String protocol; private final DubboTransportedMetadata dubboTransportedMetadata;
private String cluster; private final MethodMetadata methodMetadata;
public DubboTransportedMethodMetadata(Method method) { public DubboTransportedMethodMetadata(Method method) {
super(method); this.methodMetadata = new MethodMetadata(method);
this.dubboTransportedMetadata = new DubboTransportedMetadata();
} }
public String getProtocol() { public String getProtocol() {
return protocol; return dubboTransportedMetadata.getProtocol();
} }
public void setProtocol(String protocol) { public void setProtocol(String protocol) {
this.protocol = protocol; dubboTransportedMetadata.setProtocol(protocol);
} }
public String getCluster() { public String getCluster() {
return cluster; return dubboTransportedMetadata.getCluster();
} }
public void setCluster(String cluster) { public void setCluster(String cluster) {
this.cluster = cluster; dubboTransportedMetadata.setCluster(cluster);
}
public String getName() {
return methodMetadata.getName();
}
public void setName(String name) {
methodMetadata.setName(name);
}
public String getReturnType() {
return methodMetadata.getReturnType();
}
public void setReturnType(String returnType) {
methodMetadata.setReturnType(returnType);
}
public List<MethodParameterMetadata> getParams() {
return methodMetadata.getParams();
}
public void setParams(List<MethodParameterMetadata> params) {
methodMetadata.setParams(params);
}
public Method getMethod() {
return methodMetadata.getMethod();
}
public DubboTransportedMetadata getDubboTransportedMetadata() {
return dubboTransportedMetadata;
}
public MethodMetadata getMethodMetadata() {
return methodMetadata;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof DubboTransportedMethodMetadata)) return false; if (!(o instanceof DubboTransportedMethodMetadata)) return false;
if (!super.equals(o)) return false;
DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o; DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o;
return Objects.equals(dubboTransportedMetadata, that.dubboTransportedMetadata) &&
if (protocol != null ? !protocol.equals(that.protocol) : that.protocol != null) return false; Objects.equals(methodMetadata, that.methodMetadata);
return cluster != null ? cluster.equals(that.cluster) : that.cluster == null;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = super.hashCode(); return Objects.hash(dubboTransportedMetadata, methodMetadata);
result = 31 * result + (protocol != null ? protocol.hashCode() : 0);
result = 31 * result + (cluster != null ? cluster.hashCode() : 0);
return result;
} }
} }

View File

@ -20,13 +20,14 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
* Method Request Metadata * Method Request Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class RestMethodMetadata { public class RestMethodMetadata {

View File

@ -16,15 +16,12 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.metadata.repository; package org.springframework.cloud.alibaba.dubbo.metadata.repository;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.dubbo.http.matcher.RequestMetadataMatcher; import org.springframework.cloud.alibaba.dubbo.http.matcher.RequestMetadataMatcher;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
@ -35,10 +32,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.springframework.cloud.alibaba.dubbo.http.DefaultHttpRequest.builder; import static org.springframework.cloud.alibaba.dubbo.http.DefaultHttpRequest.builder;
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;
import static org.springframework.util.CollectionUtils.isEmpty; import static org.springframework.util.CollectionUtils.isEmpty;
/** /**
@ -53,15 +46,9 @@ public class DubboServiceMetadataRepository {
/** /**
* Key is application name * Key is application name
* Value is Map<RequestMetadata, ReferenceBean<GenericService>> * Value is Map<RequestMetadata, DubboServiceMetadata>
*/ */
private Map<String, Map<RequestMetadataMatcher, ReferenceBean<GenericService>>> referenceBeansRepository = newHashMap(); private Map<String, Map<RequestMetadataMatcher, DubboServiceMetadata>> repository = newHashMap();
/**
* Key is application name
* Value is Map<RequestMetadata, RestMethodMetadata>
*/
private Map<String, Map<RequestMetadataMatcher, RestMethodMetadata>> restMethodMetadataRepository = newHashMap();
@Autowired @Autowired
private MetadataConfigService metadataConfigService; private MetadataConfigService metadataConfigService;
@ -73,7 +60,7 @@ public class DubboServiceMetadataRepository {
*/ */
public void initialize(String serviceName) { public void initialize(String serviceName) {
if (referenceBeansRepository.containsKey(serviceName)) { if (repository.containsKey(serviceName)) {
return; return;
} }
@ -87,29 +74,28 @@ public class DubboServiceMetadataRepository {
return; return;
} }
Map<RequestMetadataMatcher, ReferenceBean<GenericService>> genericServicesMap = getReferenceBeansMap(serviceName); Map<RequestMetadataMatcher, DubboServiceMetadata> metadataMap = getMetadataMap(serviceName);
Map<RequestMetadataMatcher, RestMethodMetadata> restMethodMetadataMap = getRestMethodMetadataMap(serviceName);
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
ReferenceBean<GenericService> referenceBean = adaptReferenceBean(serviceRestMetadata);
serviceRestMetadata.getMeta().forEach(restMethodMetadata -> { serviceRestMetadata.getMeta().forEach(restMethodMetadata -> {
RequestMetadata requestMetadata = restMethodMetadata.getRequest(); RequestMetadata requestMetadata = restMethodMetadata.getRequest();
RequestMetadataMatcher matcher = new RequestMetadataMatcher(requestMetadata); RequestMetadataMatcher matcher = new RequestMetadataMatcher(requestMetadata);
genericServicesMap.put(matcher, referenceBean); DubboServiceMetadata metadata = new DubboServiceMetadata(serviceRestMetadata, restMethodMetadata);
restMethodMetadataMap.put(matcher, restMethodMetadata); metadataMap.put(matcher, metadata);
}); });
} }
} }
public ReferenceBean<GenericService> getReferenceBean(String serviceName, RequestMetadata requestMetadata) { /**
return match(referenceBeansRepository, serviceName, requestMetadata); * Get a {@link DubboServiceMetadata} by the specified service name if {@link RequestMetadata} matched
} *
* @param serviceName service name
public RestMethodMetadata getRestMethodMetadata(String serviceName, RequestMetadata requestMetadata) { * @param requestMetadata {@link RequestMetadata} to be matched
return match(restMethodMetadataRepository, serviceName, requestMetadata); * @return {@link DubboServiceMetadata} if matched, or <code>null</code>
*/
public DubboServiceMetadata get(String serviceName, RequestMetadata requestMetadata) {
return match(repository, serviceName, requestMetadata);
} }
private static <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository, String serviceName, private static <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository, String serviceName,
@ -140,28 +126,8 @@ public class DubboServiceMetadataRepository {
return object; return object;
} }
private ReferenceBean<GenericService> adaptReferenceBean(ServiceRestMetadata serviceRestMetadata) { private Map<RequestMetadataMatcher, DubboServiceMetadata> getMetadataMap(String serviceName) {
String dubboServiceName = serviceRestMetadata.getName(); return getMap(repository, serviceName);
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);
return referenceBean;
}
private Map<RequestMetadataMatcher, ReferenceBean<GenericService>> getReferenceBeansMap(String serviceName) {
return getMap(referenceBeansRepository, serviceName);
}
private Map<RequestMetadataMatcher, RestMethodMetadata> getRestMethodMetadataMap(String serviceName) {
return getMap(restMethodMetadataRepository, serviceName);
} }
private static <K, V> Map<K, V> getMap(Map<String, Map<K, V>> repository, String key) { private static <K, V> Map<K, V> getMap(Map<String, Map<K, V>> repository, String key) {

View File

@ -0,0 +1,79 @@
/*
* 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 com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
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 {@link GenericService} Factory
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class DubboGenericServiceFactory {
private final ConcurrentMap<Integer, GenericService> cache = new ConcurrentHashMap<>();
public GenericService create(DubboServiceMetadata dubboServiceMetadata,
DubboTransportedMetadata dubboTransportedMetadata) {
Integer key = Objects.hash(dubboServiceMetadata, dubboTransportedMetadata);
GenericService genericService = cache.get(key);
if (genericService == null) {
genericService = build(dubboServiceMetadata.getServiceRestMetadata(), dubboTransportedMetadata);
cache.putIfAbsent(key, genericService);
}
return genericService;
}
private GenericService build(ServiceRestMetadata serviceRestMetadata,
DubboTransportedMetadata dubboTransportedMetadata) {
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(dubboTransportedMetadata.getProtocol());
referenceBean.setCluster(dubboTransportedMetadata.getCluster());
return referenceBean.get();
}
}

View File

@ -20,6 +20,7 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import static java.lang.reflect.Proxy.newProxyInstance; import static java.lang.reflect.Proxy.newProxyInstance;
@ -39,12 +40,16 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo
private final DubboServiceMetadataRepository dubboServiceMetadataRepository; private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
private final DubboGenericServiceFactory dubboGenericServiceFactory;
private ClassLoader classLoader; private ClassLoader classLoader;
public TargeterBeanPostProcessor(Environment environment, public TargeterBeanPostProcessor(Environment environment,
DubboServiceMetadataRepository dubboServiceMetadataRepository) { DubboServiceMetadataRepository dubboServiceMetadataRepository,
DubboGenericServiceFactory dubboGenericServiceFactory) {
this.environment = environment; this.environment = environment;
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
} }
@Override @Override
@ -58,7 +63,8 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo
Class<?> targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader); Class<?> targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader);
if (targetClass.isAssignableFrom(beanClass)) { if (targetClass.isAssignableFrom(beanClass)) {
return newProxyInstance(classLoader, new Class[]{targetClass}, return newProxyInstance(classLoader, new Class[]{targetClass},
new TargeterInvocationHandler(bean, environment, dubboServiceMetadataRepository)); new TargeterInvocationHandler(bean, environment, dubboServiceMetadataRepository,
dubboGenericServiceFactory));
} }
return bean; return bean;
} }

View File

@ -17,16 +17,18 @@
package org.springframework.cloud.alibaba.dubbo.openfeign; package org.springframework.cloud.alibaba.dubbo.openfeign;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.rpc.service.GenericService; import com.alibaba.dubbo.rpc.service.GenericService;
import feign.Contract; import feign.Contract;
import feign.Target; import feign.Target;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboTransportedMethodMetadataResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboTransportedMethodMetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory;
import org.springframework.cloud.openfeign.FeignContext; import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@ -51,11 +53,14 @@ class TargeterInvocationHandler implements InvocationHandler {
private final DubboServiceMetadataRepository repository; private final DubboServiceMetadataRepository repository;
TargeterInvocationHandler(Object bean, Environment environment, private final DubboGenericServiceFactory dubboGenericServiceFactory;
DubboServiceMetadataRepository repository) {
TargeterInvocationHandler(Object bean, Environment environment, DubboServiceMetadataRepository repository,
DubboGenericServiceFactory dubboGenericServiceFactory) {
this.bean = bean; this.bean = bean;
this.environment = environment; this.environment = environment;
this.repository = repository; this.repository = repository;
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
} }
@Override @Override
@ -115,12 +120,12 @@ class TargeterInvocationHandler implements InvocationHandler {
Map<Method, GenericService> genericServicesMap = new HashMap<>(); Map<Method, GenericService> genericServicesMap = new HashMap<>();
methodRequestMetadataMap.forEach((dubboTransportedMethodMetadata, requestMetadata) -> { methodRequestMetadataMap.forEach((dubboTransportedMethodMetadata, requestMetadata) -> {
ReferenceBean<GenericService> referenceBean = repository.getReferenceBean(serviceName, requestMetadata); DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, requestMetadata);
RestMethodMetadata restMethodMetadata = repository.getRestMethodMetadata(serviceName, requestMetadata); RestMethodMetadata restMethodMetadata = dubboServiceMetadata.getRestMethodMetadata();
org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata = restMethodMetadata.getMethod(); org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata = restMethodMetadata.getMethod();
referenceBean.setProtocol(dubboTransportedMethodMetadata.getProtocol()); DubboTransportedMetadata dubboTransportedMetadata = dubboTransportedMethodMetadata.getDubboTransportedMetadata();
referenceBean.setCluster(dubboTransportedMethodMetadata.getCluster()); GenericService genericService = dubboGenericServiceFactory.create(dubboServiceMetadata, dubboTransportedMetadata);
genericServicesMap.put(dubboTransportedMethodMetadata.getMethod(), referenceBean.get()); genericServicesMap.put(dubboTransportedMethodMetadata.getMethod(), genericService);
methodMetadataMap.put(dubboTransportedMethodMetadata.getMethod(), methodMetadata); methodMetadataMap.put(dubboTransportedMethodMetadata.getMethod(), methodMetadata);
}); });

View File

@ -2,7 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\ 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.DubboRestMetadataRegistrationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\ org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer