From 2f5ac6b7ad63713c46e11ee695caf592562e362c Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 20 Feb 2019 16:14:10 +0800 Subject: [PATCH] Polish spring-cloud-incubator/spring-cloud-alibaba#348 : Add The resolvers of Dubbo Generic Method parameters. --- ...BalancedRestTemplateAutoConfiguration.java | 10 +- .../DubboMetadataAutoConfiguration.java | 4 +- .../DubboOpenFeignAutoConfiguration.java | 15 ++- ...MetadataRegistrationAutoConfiguration.java | 2 +- .../DubboServiceAutoConfiguration.java | 14 ++- .../DubboAdapterLoadBalancerInterceptor.java | 42 +++---- .../DubboClientHttpResponseFactory.java | 2 +- .../dubbo/http/ByteArrayHttpInputMessage.java | 55 +++++++++ .../dubbo/http/DefaultServerHttpRequest.java | 100 ++++++++++++++++ .../util}/HttpMessageConverterResolver.java | 40 ++++++- .../dubbo/metadata/RestMethodMetadata.java | 15 ++- .../DubboServiceMetadataRepository.java | 2 +- .../DubboServiceBeanMetadataResolver.java | 5 +- .../metadata/resolver/ParameterResolver.java | 102 ---------------- .../openfeign/DubboInvocationHandler.java | 34 +++--- .../openfeign/TargeterBeanPostProcessor.java | 11 +- .../openfeign/TargeterInvocationHandler.java | 21 ++-- .../dubbo/registry/SpringCloudRegistry.java | 29 ++--- .../DubboGenericServiceExecutionContext.java | 51 ++++++++ ...GenericServiceExecutionContextFactory.java | 112 ++++++++++++++++++ .../service/DubboGenericServiceFactory.java | 45 +++++-- .../service/MetadataConfigService.java | 2 +- .../service/NacosMetadataConfigService.java | 3 +- ...tDubboGenericServiceParameterResolver.java | 81 +++++++++++++ .../DubboGenericServiceParameterResolver.java | 50 ++++++++ .../RequestBodyServerParameterResolver.java | 102 ++++++++++++++++ .../RequestParamServiceParameterResolver.java | 87 ++++++++++++++ .../bootstrap/DubboSpringCloudBootstrap.java | 15 ++- 28 files changed, 835 insertions(+), 216 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultServerHttpRequest.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{metadata/resolver => http/util}/HttpMessageConverterResolver.java (86%) delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/ParameterResolver.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContext.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContextFactory.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{metadata => }/service/DubboGenericServiceFactory.java (64%) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{metadata => }/service/MetadataConfigService.java (94%) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/{metadata => }/service/NacosMetadataConfigService.java (98%) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/DubboGenericServiceParameterResolver.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestBodyServerParameterResolver.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestParamServiceParameterResolver.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java index f32bea75..4245a5f8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java @@ -29,7 +29,8 @@ import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported; 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.service.DubboGenericServiceFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; @@ -71,7 +72,10 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClass private ConfigurableListableBeanFactory beanFactory; @Autowired - private DubboGenericServiceFactory dubboGenericServiceFactory; + private DubboGenericServiceFactory serviceFactory; + + @Autowired + private DubboGenericServiceExecutionContextFactory contextFactory; @Autowired private Environment environment; @@ -137,7 +141,7 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClass if (index > -1) { interceptors.set(index, new DubboAdapterLoadBalancerInterceptor(repository, loadBalancerInterceptor, restTemplate.getMessageConverters(), classLoader, - dubboTransportedMetadata, dubboGenericServiceFactory)); + dubboTransportedMetadata, serviceFactory, contextFactory)); } restTemplate.setInterceptors(interceptors); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index cd4422c7..2d04d468 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -18,8 +18,8 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; -import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.metadata.service.NacosMetadataConfigService; +import org.springframework.cloud.alibaba.dubbo.service.MetadataConfigService; +import org.springframework.cloud.alibaba.dubbo.service.NacosMetadataConfigService; import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java index ab4c7825..55d2f0a9 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java @@ -19,15 +19,15 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import feign.Contract; import feign.Feign; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 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.MetadataResolver; -import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.openfeign.FeignAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -44,20 +44,19 @@ import org.springframework.core.env.Environment; @Configuration public class DubboOpenFeignAutoConfiguration { - @Value("${spring.application.name}") - private String currentApplicationName; - @Bean @ConditionalOnMissingBean public MetadataResolver metadataJsonResolver(ObjectProvider contract) { - return new DubboServiceBeanMetadataResolver(currentApplicationName, contract); + return new DubboServiceBeanMetadataResolver(contract); } @Bean public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment, DubboServiceMetadataRepository dubboServiceMetadataRepository, - DubboGenericServiceFactory dubboGenericServiceFactory) { - return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository,dubboGenericServiceFactory); + DubboGenericServiceFactory dubboGenericServiceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { + return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository, + dubboGenericServiceFactory, contextFactory); } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java index e75c1f73..8eed7a65 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java @@ -27,7 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; -import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService; +import org.springframework.cloud.alibaba.dubbo.service.MetadataConfigService; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java index 551cd65e..f1fd1e42 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java @@ -17,9 +17,13 @@ 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.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; +import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestBodyServerParameterResolver; +import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestParamServiceParameterResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; /** * Spring Boot Auto-Configuration class for Dubbo Service @@ -35,4 +39,12 @@ public class DubboServiceAutoConfiguration { return new DubboGenericServiceFactory(); } + @Configuration + @Import(value = { + DubboGenericServiceExecutionContextFactory.class, + RequestParamServiceParameterResolver.class, + RequestBodyServerParameterResolver.class, + }) + static class ParameterResolversConfiguration { + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboAdapterLoadBalancerInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboAdapterLoadBalancerInterceptor.java index d40892bc..7e709d1f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboAdapterLoadBalancerInterceptor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboAdapterLoadBalancerInterceptor.java @@ -19,14 +19,15 @@ package org.springframework.cloud.alibaba.dubbo.client.loadbalancer; import com.alibaba.dubbo.rpc.service.GenericException; import com.alibaba.dubbo.rpc.service.GenericService; +import org.springframework.cloud.alibaba.dubbo.http.DefaultServerHttpRequest; 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.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; 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.service.DubboGenericServiceFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; @@ -48,8 +49,6 @@ import java.util.List; */ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInterceptor { - private final ParameterResolver parameterResolver = new ParameterResolver(); - private final DubboServiceMetadataRepository repository; private final LoadBalancerInterceptor loadBalancerInterceptor; @@ -58,19 +57,23 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt private final DubboTransportedMetadata dubboTransportedMetadata; - private final DubboGenericServiceFactory dubboGenericServiceFactory; + private final DubboGenericServiceFactory serviceFactory; + + private final DubboGenericServiceExecutionContextFactory contextFactory; public DubboAdapterLoadBalancerInterceptor(DubboServiceMetadataRepository dubboServiceMetadataRepository, LoadBalancerInterceptor loadBalancerInterceptor, List> messageConverters, ClassLoader classLoader, DubboTransportedMetadata dubboTransportedMetadata, - DubboGenericServiceFactory dubboGenericServiceFactory) { + DubboGenericServiceFactory serviceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { this.repository = dubboServiceMetadataRepository; this.loadBalancerInterceptor = loadBalancerInterceptor; this.dubboTransportedMetadata = dubboTransportedMetadata; this.clientHttpResponseFactory = new DubboClientHttpResponseFactory(messageConverters, classLoader); - this.dubboGenericServiceFactory = dubboGenericServiceFactory; + this.serviceFactory = serviceFactory; + this.contextFactory = contextFactory; } @Override @@ -94,13 +97,16 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt RestMethodMetadata restMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); - GenericService genericService = dubboGenericServiceFactory.create(dubboServiceMetadata, dubboTransportedMetadata); + GenericService genericService = serviceFactory.create(dubboServiceMetadata, dubboTransportedMetadata); + + DubboGenericServiceExecutionContext context = contextFactory.create(restMethodMetadata, + new DefaultServerHttpRequest(request, body)); Object result = null; GenericException exception = null; try { - result = invokeService(restMethodMetadata, genericService, clientMetadata); + result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters()); } catch (GenericException e) { exception = e; } @@ -108,22 +114,6 @@ public class DubboAdapterLoadBalancerInterceptor implements ClientHttpRequestInt return clientHttpResponseFactory.build(result, exception, clientMetadata, restMethodMetadata); } - private Object invokeService(RestMethodMetadata restMethodMetadata, GenericService genericService, - RequestMetadata clientMetadata) throws GenericException { - - MethodMetadata methodMetadata = restMethodMetadata.getMethod(); - - String methodName = methodMetadata.getName(); - - String[] parameterTypes = parameterResolver.resolveParameterTypes(methodMetadata); - - Object[] parameters = parameterResolver.resolveParameters(restMethodMetadata, clientMetadata); - - Object result = genericService.$invoke(methodName, parameterTypes, parameters); - - return result; - } - public static RequestMetadata buildRequestMetadata(HttpRequest request, UriComponents uriComponents) { RequestMetadata requestMetadata = new RequestMetadata(); requestMetadata.setPath(uriComponents.getPath()); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java index f652273e..387cf6b1 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java @@ -19,9 +19,9 @@ package org.springframework.cloud.alibaba.dubbo.client.loadbalancer; import com.alibaba.dubbo.rpc.service.GenericException; import org.springframework.cloud.alibaba.dubbo.http.converter.HttpMessageConverterHolder; +import org.springframework.cloud.alibaba.dubbo.http.util.HttpMessageConverterResolver; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.resolver.HttpMessageConverterResolver; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.HttpMessageConverter; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java new file mode 100644 index 00000000..2451a715 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java @@ -0,0 +1,55 @@ +/* + * 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.http; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Byte array {@link HttpInputMessage} implementation + * + * @author Mercy + */ +public class ByteArrayHttpInputMessage implements HttpInputMessage { + + private final HttpHeaders httpHeaders; + + private final InputStream inputStream; + + public ByteArrayHttpInputMessage(byte[] body) { + this(new HttpHeaders(), body); + } + + public ByteArrayHttpInputMessage(HttpHeaders httpHeaders, byte[] body) { + this.httpHeaders = httpHeaders; + this.inputStream = new ByteArrayInputStream(body); + } + + @Override + public InputStream getBody() throws IOException { + return inputStream; + } + + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultServerHttpRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultServerHttpRequest.java new file mode 100644 index 00000000..4adc8131 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultServerHttpRequest.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.http; + + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.http.server.ServerHttpAsyncRequestControl; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.security.Principal; + +/** + * Default {@link ServerHttpRequest} implementation + * + * @author Mercy + */ +public class DefaultServerHttpRequest implements ServerHttpRequest { + + private final HttpMethod httpMethod; + + private final URI uri; + + private final HttpHeaders httpHeaders; + + private final HttpInputMessage httpInputMessage; + + public DefaultServerHttpRequest(HttpRequest httpRequest, byte[] body) { + this.httpMethod = httpRequest.getMethod(); + this.uri = httpRequest.getURI(); + this.httpHeaders = httpRequest.getHeaders(); + this.httpInputMessage = new ByteArrayHttpInputMessage(body); + } + + @Override + public InputStream getBody() throws IOException { + return httpInputMessage.getBody(); + } + + @Override + public HttpMethod getMethod() { + return httpMethod; + } + + // Override method since Spring Framework 5.0 + public String getMethodValue() { + return httpMethod.name(); + } + + @Override + public URI getURI() { + return uri; + } + + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } + + @Override + public Principal getPrincipal() { + throw new UnsupportedOperationException(); + } + + @Override + public InetSocketAddress getLocalAddress() { + throw new UnsupportedOperationException(); + } + + @Override + public InetSocketAddress getRemoteAddress() { + throw new UnsupportedOperationException(); + } + + @Override + public ServerHttpAsyncRequestControl getAsyncRequestControl(ServerHttpResponse response) { + throw new UnsupportedOperationException(); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/HttpMessageConverterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/util/HttpMessageConverterResolver.java similarity index 86% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/HttpMessageConverterResolver.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/util/HttpMessageConverterResolver.java index cbde9e46..4e549654 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/HttpMessageConverterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/util/HttpMessageConverterResolver.java @@ -14,12 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.metadata.resolver; +package org.springframework.cloud.alibaba.dubbo.http.util; import org.springframework.cloud.alibaba.dubbo.http.converter.HttpMessageConverterHolder; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.core.MethodParameter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServletServerHttpRequest; @@ -33,6 +35,8 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import static java.util.Collections.unmodifiableList; + /** * {@link HttpMessageConverter} Resolver * @@ -54,6 +58,28 @@ public class HttpMessageConverterResolver { this.classLoader = classLoader; } + public HttpMessageConverterHolder resolve(HttpRequest request, Class parameterType) { + + HttpMessageConverterHolder httpMessageConverterHolder = null; + + HttpHeaders httpHeaders = request.getHeaders(); + + MediaType contentType = httpHeaders.getContentType(); + + if (contentType == null) { + contentType = MediaType.APPLICATION_OCTET_STREAM; + } + + for (HttpMessageConverter converter : this.messageConverters) { + if (converter.canRead(parameterType, contentType)) { + httpMessageConverterHolder = new HttpMessageConverterHolder(contentType, converter); + break; + } + } + + return httpMessageConverterHolder; + } + /** * Resolve the most match {@link HttpMessageConverter} from {@link RequestMetadata} * @@ -61,7 +87,8 @@ public class HttpMessageConverterResolver { * @param restMethodMetadata {@link RestMethodMetadata} * @return */ - public HttpMessageConverterHolder resolve(RequestMetadata requestMetadata, RestMethodMetadata restMethodMetadata) { + public HttpMessageConverterHolder resolve(RequestMetadata requestMetadata, RestMethodMetadata + restMethodMetadata) { HttpMessageConverterHolder httpMessageConverterHolder = null; @@ -114,6 +141,10 @@ public class HttpMessageConverterResolver { return httpMessageConverterHolder; } + public List getAllSupportedMediaTypes() { + return unmodifiableList(allSupportedMediaTypes); + } + private Class resolveReturnValueClass(RestMethodMetadata restMethodMetadata) { String returnClassName = restMethodMetadata.getMethod().getReturnType(); return ClassUtils.resolveClassName(returnClassName, classLoader); @@ -139,7 +170,8 @@ public class HttpMessageConverterResolver { * @param returnValueClass the class of return value * @return non-null {@link List} */ - private List getProducibleMediaTypes(RestMethodMetadata restMethodMetadata, Class returnValueClass) { + private List getProducibleMediaTypes(RestMethodMetadata restMethodMetadata, Class + returnValueClass) { RequestMetadata serverRequestMetadata = restMethodMetadata.getRequest(); List mediaTypes = serverRequestMetadata.getProduceMediaTypes(); if (!CollectionUtils.isEmpty(mediaTypes)) { // Empty @@ -172,7 +204,7 @@ public class HttpMessageConverterResolver { } List result = new ArrayList(allSupportedMediaTypes); MediaType.sortBySpecificity(result); - return Collections.unmodifiableList(result); + return unmodifiableList(result); } /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java index 46675b47..ba01e527 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java @@ -18,7 +18,9 @@ package org.springframework.cloud.alibaba.dubbo.metadata; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.core.ResolvableType; +import java.lang.reflect.Type; import java.util.Collection; import java.util.List; import java.util.Map; @@ -76,8 +78,8 @@ public class RestMethodMetadata { this.headerMapIndex = methodMetadata.headerMapIndex(); this.queryMapEncoded = methodMetadata.queryMapEncoded(); this.queryMapEncoded = methodMetadata.queryMapEncoded(); - this.returnType = methodMetadata.returnType() == null ? null : methodMetadata.returnType().toString(); - this.bodyType = methodMetadata.bodyType() == null ? null : methodMetadata.bodyType().toString(); + this.returnType = getClassName(methodMetadata.returnType()); + this.bodyType = getClassName(methodMetadata.bodyType()); this.indexToName = methodMetadata.indexToName(); this.formParams = methodMetadata.formParams(); this.indexToEncoded = methodMetadata.indexToEncoded(); @@ -203,4 +205,13 @@ public class RestMethodMetadata { return Objects.hash(method, request, urlIndex, bodyIndex, headerMapIndex, queryMapIndex, queryMapEncoded, returnType, bodyType, indexToName, formParams, indexToEncoded); } + + private String getClassName(Type type) { + if (type == null) { + return null; + } + ResolvableType resolvableType = ResolvableType.forType(type); + return resolvableType.resolve().getName(); + } + } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java index cb578bd2..4e30381c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java @@ -23,7 +23,7 @@ import org.springframework.cloud.alibaba.dubbo.http.matcher.RequestMetadataMatch import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; 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.cloud.alibaba.dubbo.service.MetadataConfigService; import org.springframework.http.HttpRequest; import org.springframework.stereotype.Repository; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java index da42e187..33c44716 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java @@ -56,8 +56,6 @@ public class DubboServiceBeanMetadataResolver implements BeanClassLoaderAware, S "org.springframework.cloud.openfeign.support.SpringMvcContract", }; - private final String currentApplicationName; - private final ObjectProvider contract; private ClassLoader classLoader; @@ -67,8 +65,7 @@ public class DubboServiceBeanMetadataResolver implements BeanClassLoaderAware, S */ private Collection contracts; - public DubboServiceBeanMetadataResolver(String currentApplicationName, ObjectProvider contract) { - this.currentApplicationName = currentApplicationName; + public DubboServiceBeanMetadataResolver(ObjectProvider contract) { this.contract = contract; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/ParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/ParameterResolver.java deleted file mode 100644 index 3c627207..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/ParameterResolver.java +++ /dev/null @@ -1,102 +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.metadata.resolver; - -import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; -import org.springframework.util.CollectionUtils; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Parameter Resolver - * - * @author Mercy - */ -public class ParameterResolver { - - public Object[] resolveParameters(RestMethodMetadata restMethodMetadata, RequestMetadata clientMetadata) { - - MethodMetadata methodMetadata = restMethodMetadata.getMethod(); - - RequestMetadata requestMetadata = restMethodMetadata.getRequest(); - - Map> indexToName = restMethodMetadata.getIndexToName(); - - List params = methodMetadata.getParams(); - - Object[] parameters = new Object[params.size()]; - - for (MethodParameterMetadata parameterMetadata : params) { - - int index = parameterMetadata.getIndex(); - - String name = getName(indexToName, index); - - parameters[index] = getValue(requestMetadata, clientMetadata, name); - - } - - return parameters; - } - - private String getValue(RequestMetadata serverMetadata, RequestMetadata clientMetadata, String name) { - String value = null; - Set paramNames = serverMetadata.getParamNames(); - Set headerNames = serverMetadata.getHeaderNames(); - if (paramNames.contains(name)) { - value = clientMetadata.getParameter(name); - } else if (headerNames.contains(name)) { - value = clientMetadata.getHeader(name); - } - return value; - - } - - private String getName(Map> indexToName, int index) { - Collection names = indexToName.get(index); - String name = null; - if (!CollectionUtils.isEmpty(names)) { - Iterator iterator = names.iterator(); - while (iterator.hasNext()) { - name = iterator.next(); // choose the last one if more than one - } - } - return name; - } - - public String[] resolveParameterTypes(MethodMetadata methodMetadata) { - - List params = methodMetadata.getParams(); - - String[] parameterTypes = new String[params.size()]; - - for (MethodParameterMetadata parameterMetadata : params) { - int index = parameterMetadata.getIndex(); - String parameterType = parameterMetadata.getType(); - parameterTypes[index] = parameterType; - } - - return parameterTypes; - } -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java index 622ae340..1c1b8eb5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java @@ -17,8 +17,10 @@ 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 org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -33,16 +35,20 @@ public class DubboInvocationHandler implements InvocationHandler { private final Map genericServicesMap; - private final Map methodMetadata; + private final Map restMethodMetadataMap; private final InvocationHandler defaultInvocationHandler; + private final DubboGenericServiceExecutionContextFactory contextFactory; + public DubboInvocationHandler(Map genericServicesMap, - Map methodMetadata, - InvocationHandler defaultInvocationHandler) { + Map restMethodMetadataMap, + InvocationHandler defaultInvocationHandler, + DubboGenericServiceExecutionContextFactory contextFactory) { this.genericServicesMap = genericServicesMap; - this.methodMetadata = methodMetadata; + this.restMethodMetadataMap = restMethodMetadataMap; this.defaultInvocationHandler = defaultInvocationHandler; + this.contextFactory = contextFactory; } @Override @@ -50,20 +56,18 @@ public class DubboInvocationHandler implements InvocationHandler { GenericService genericService = genericServicesMap.get(method); - MethodMetadata methodMetadata = this.methodMetadata.get(method); + RestMethodMetadata restMethodMetadata = restMethodMetadataMap.get(method); - if (genericService == null || methodMetadata == null) { + if (genericService == null || restMethodMetadata == null) { return defaultInvocationHandler.invoke(proxy, method, args); } - String methodName = methodMetadata.getName(); + DubboGenericServiceExecutionContext context = contextFactory.create(restMethodMetadata, args); - String[] parameterTypes = methodMetadata - .getParams() - .stream() - .map(MethodParameterMetadata::getType) - .toArray(String[]::new); + String methodName = context.getMethodName(); + String[] parameterTypes = context.getParameterTypes(); + Object[] parameters = context.getParameters(); - return genericService.$invoke(methodName, parameterTypes, args); + return genericService.$invoke(methodName, parameterTypes, parameters); } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterBeanPostProcessor.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterBeanPostProcessor.java index 7bb51221..d055709e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterBeanPostProcessor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterBeanPostProcessor.java @@ -20,7 +20,8 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; -import org.springframework.cloud.alibaba.dubbo.metadata.service.DubboGenericServiceFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.core.env.Environment; import static java.lang.reflect.Proxy.newProxyInstance; @@ -42,14 +43,18 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo private final DubboGenericServiceFactory dubboGenericServiceFactory; + private final DubboGenericServiceExecutionContextFactory contextFactory; + private ClassLoader classLoader; public TargeterBeanPostProcessor(Environment environment, DubboServiceMetadataRepository dubboServiceMetadataRepository, - DubboGenericServiceFactory dubboGenericServiceFactory) { + DubboGenericServiceFactory dubboGenericServiceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { this.environment = environment; this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; this.dubboGenericServiceFactory = dubboGenericServiceFactory; + this.contextFactory = contextFactory; } @Override @@ -64,7 +69,7 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo if (targetClass.isAssignableFrom(beanClass)) { return newProxyInstance(classLoader, new Class[]{targetClass}, new TargeterInvocationHandler(bean, environment, dubboServiceMetadataRepository, - dubboGenericServiceFactory)); + dubboGenericServiceFactory,contextFactory)); } return bean; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java index 346837aa..1b1863e7 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java @@ -28,7 +28,8 @@ import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; 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.service.DubboGenericServiceFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.openfeign.FeignContext; import org.springframework.core.env.Environment; @@ -55,12 +56,16 @@ class TargeterInvocationHandler implements InvocationHandler { private final DubboGenericServiceFactory dubboGenericServiceFactory; + private final DubboGenericServiceExecutionContextFactory contextFactory; + TargeterInvocationHandler(Object bean, Environment environment, DubboServiceMetadataRepository repository, - DubboGenericServiceFactory dubboGenericServiceFactory) { + DubboGenericServiceFactory dubboGenericServiceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { this.bean = bean; this.environment = environment; this.repository = repository; this.dubboGenericServiceFactory = dubboGenericServiceFactory; + this.contextFactory = contextFactory; } @Override @@ -115,24 +120,24 @@ class TargeterInvocationHandler implements InvocationHandler { // Update Metadata repository.initialize(serviceName); - Map methodMetadataMap = new HashMap<>(); + Map restMethodMetadataMap = new HashMap<>(); Map genericServicesMap = new HashMap<>(); methodRequestMetadataMap.forEach((dubboTransportedMethodMetadata, requestMetadata) -> { DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, requestMetadata); RestMethodMetadata restMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); - org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata = restMethodMetadata.getMethod(); DubboTransportedMetadata dubboTransportedMetadata = dubboTransportedMethodMetadata.getDubboTransportedMetadata(); GenericService genericService = dubboGenericServiceFactory.create(dubboServiceMetadata, dubboTransportedMetadata); - genericServicesMap.put(dubboTransportedMethodMetadata.getMethod(), genericService); - methodMetadataMap.put(dubboTransportedMethodMetadata.getMethod(), methodMetadata); + Method method = dubboTransportedMethodMetadata.getMethod(); + genericServicesMap.put(method, genericService); + restMethodMetadataMap.put(method, restMethodMetadata); }); InvocationHandler defaultFeignClientInvocationHandler = Proxy.getInvocationHandler(defaultFeignClientProxy); - DubboInvocationHandler dubboInvocationHandler = new DubboInvocationHandler(genericServicesMap, methodMetadataMap, - defaultFeignClientInvocationHandler); + DubboInvocationHandler dubboInvocationHandler = new DubboInvocationHandler(genericServicesMap, restMethodMetadataMap, + defaultFeignClientInvocationHandler, contextFactory); return dubboInvocationHandler; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java index 1904cbd5..8d05cbd0 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -23,6 +23,7 @@ import com.alibaba.dubbo.common.utils.UrlUtils; import com.alibaba.dubbo.registry.NotifyListener; import com.alibaba.dubbo.registry.RegistryFactory; import com.alibaba.dubbo.registry.support.FailbackRegistry; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.DefaultServiceInstance; @@ -47,7 +48,6 @@ import java.util.concurrent.TimeUnit; import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY; import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; -import static com.alibaba.dubbo.common.Constants.PROTOCOL_KEY; import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY; @@ -70,9 +70,11 @@ public class SpringCloudRegistry extends FailbackRegistry { private static final int CATEGORY_INDEX = 0; - private static final int PROTOCOL_INDEX = CATEGORY_INDEX + 1; +// private static final int PROTOCOL_INDEX = CATEGORY_INDEX + 1; - private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1; +// private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1; + + private static final int SERVICE_INTERFACE_INDEX = CATEGORY_INDEX + 1; private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1; @@ -169,7 +171,6 @@ public class SpringCloudRegistry extends FailbackRegistry { private static String getServiceName(URL url, String category) { StringBuilder serviceNameBuilder = new StringBuilder(category); - appendIfPresent(serviceNameBuilder, url.getParameter(PROTOCOL_KEY, url.getProtocol())); appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY); @@ -203,12 +204,11 @@ public class SpringCloudRegistry extends FailbackRegistry { // split service name to segments // (required) segments[0] = category // (required) segments[1] = serviceInterface - // (required) segments[2] = protocol - // (required) segments[3] = version - // (optional) segments[4] = group + // (required) segments[2] = version + // (optional) segments[3] = group String[] segments = getServiceSegments(serviceName); int length = segments.length; - if (length < 4) { // must present 4 segments or more + if (length < SERVICE_GROUP_INDEX) { // must present 4 segments or more return false; } @@ -217,11 +217,6 @@ public class SpringCloudRegistry extends FailbackRegistry { return false; } - String protocol = getProtocol(segments); - if (StringUtils.hasText(protocol)) { - return false; - } - String serviceInterface = getServiceInterface(segments); if (!WILDCARD.equals(targetServiceInterface) && !Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface @@ -253,9 +248,9 @@ public class SpringCloudRegistry extends FailbackRegistry { return segments[CATEGORY_INDEX]; } - public static String getProtocol(String[] segments) { - return segments[PROTOCOL_INDEX]; - } +// public static String getProtocol(String[] segments) { +// return segments[PROTOCOL_INDEX]; +// } public static String getServiceInterface(String[] segments) { return segments[SERVICE_INTERFACE_INDEX]; @@ -266,7 +261,7 @@ public class SpringCloudRegistry extends FailbackRegistry { } public static String getServiceGroup(String[] segments) { - return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null; + return segments.length > SERVICE_GROUP_INDEX ? segments[SERVICE_GROUP_INDEX] : null; } /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContext.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContext.java new file mode 100644 index 00000000..5bf8c691 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContext.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service; + +import com.alibaba.dubbo.rpc.service.GenericService; + +/** + * Dubbo {@link GenericService} execution context + * + * @author Mercy + */ +public class DubboGenericServiceExecutionContext { + + private final String methodName; + + private final String[] parameterTypes; + + private final Object[] parameters; + + public DubboGenericServiceExecutionContext(String methodName, String[] parameterTypes, Object[] parameters) { + this.methodName = methodName; + this.parameterTypes = parameterTypes; + this.parameters = parameters; + } + + public String getMethodName() { + return methodName; + } + + public String[] getParameterTypes() { + return parameterTypes; + } + + public Object[] getParameters() { + return parameters; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContextFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContextFactory.java new file mode 100644 index 00000000..a9a9e2b9 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceExecutionContextFactory.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.cloud.alibaba.dubbo.service.parameter.DubboGenericServiceParameterResolver; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.http.server.ServerHttpRequest; + +import javax.annotation.PostConstruct; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * {@link DubboGenericServiceExecutionContext} Factory + * + * @author Mercy + * @see DubboGenericServiceParameterResolver + */ +public class DubboGenericServiceExecutionContextFactory { + + @Autowired(required = false) + private final List resolvers = Collections.emptyList(); + + @PostConstruct + public void init() { + AnnotationAwareOrderComparator.sort(resolvers); + } + + public DubboGenericServiceExecutionContext create(RestMethodMetadata restMethodMetadata, Object[] arguments) { + + MethodMetadata methodMetadata = restMethodMetadata.getMethod(); + + String methodName = methodMetadata.getName(); + + String[] parameterTypes = resolveParameterTypes(methodMetadata); + + Object[] parameters = Arrays.copyOf(arguments, parameterTypes.length); + + return new DubboGenericServiceExecutionContext(methodName, parameterTypes, parameters); + } + + + public DubboGenericServiceExecutionContext create(RestMethodMetadata restMethodMetadata, + ServerHttpRequest request) { + MethodMetadata methodMetadata = restMethodMetadata.getMethod(); + + String methodName = methodMetadata.getName(); + + String[] parameterTypes = resolveParameterTypes(methodMetadata); + + Object[] parameters = resolveParameters(restMethodMetadata, request); + + return new DubboGenericServiceExecutionContext(methodName, parameterTypes, parameters); + } + + protected String[] resolveParameterTypes(MethodMetadata methodMetadata) { + + List params = methodMetadata.getParams(); + + String[] parameterTypes = new String[params.size()]; + + for (MethodParameterMetadata parameterMetadata : params) { + int index = parameterMetadata.getIndex(); + String parameterType = parameterMetadata.getType(); + parameterTypes[index] = parameterType; + } + + return parameterTypes; + } + + protected Object[] resolveParameters(RestMethodMetadata restMethodMetadata, ServerHttpRequest request) { + + MethodMetadata methodMetadata = restMethodMetadata.getMethod(); + + List params = methodMetadata.getParams(); + + Object[] parameters = new Object[params.size()]; + + for (MethodParameterMetadata parameterMetadata : params) { + + int index = parameterMetadata.getIndex(); + + for (DubboGenericServiceParameterResolver resolver : resolvers) { + if (resolver.supportParameter(restMethodMetadata, parameterMetadata)) { + parameters[index] = resolver.resolveParameter(restMethodMetadata, parameterMetadata, request); + break; + } + } + } + + return parameters; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/DubboGenericServiceFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java similarity index 64% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/DubboGenericServiceFactory.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java index fbdf19c2..0c6dfc77 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/DubboGenericServiceFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java @@ -14,15 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.metadata.service; +package org.springframework.cloud.alibaba.dubbo.service; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.rpc.service.GenericService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; 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 javax.annotation.PreDestroy; +import java.util.Collection; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -39,26 +43,28 @@ import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegist */ public class DubboGenericServiceFactory { - private final ConcurrentMap cache = new ConcurrentHashMap<>(); + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ConcurrentMap> cache = new ConcurrentHashMap<>(); public GenericService create(DubboServiceMetadata dubboServiceMetadata, DubboTransportedMetadata dubboTransportedMetadata) { Integer key = Objects.hash(dubboServiceMetadata, dubboTransportedMetadata); - GenericService genericService = cache.get(key); + ReferenceBean referenceBean = cache.get(key); - if (genericService == null) { - genericService = build(dubboServiceMetadata.getServiceRestMetadata(), dubboTransportedMetadata); - cache.putIfAbsent(key, genericService); + if (referenceBean == null) { + referenceBean = build(dubboServiceMetadata.getServiceRestMetadata(), dubboTransportedMetadata); + cache.putIfAbsent(key, referenceBean); } - return genericService; + return referenceBean == null ? null : referenceBean.get(); } - private GenericService build(ServiceRestMetadata serviceRestMetadata, - DubboTransportedMetadata dubboTransportedMetadata) { + private ReferenceBean build(ServiceRestMetadata serviceRestMetadata, + DubboTransportedMetadata dubboTransportedMetadata) { String dubboServiceName = serviceRestMetadata.getName(); String[] segments = getServiceSegments(dubboServiceName); String interfaceName = getServiceInterface(segments); @@ -73,7 +79,26 @@ public class DubboGenericServiceFactory { referenceBean.setProtocol(dubboTransportedMetadata.getProtocol()); referenceBean.setCluster(dubboTransportedMetadata.getCluster()); - return referenceBean.get(); + return referenceBean; + } + + @PreDestroy + public void destroy() { + destroyReferenceBeans(); + cache.values(); + } + + private void destroyReferenceBeans() { + Collection> referenceBeans = cache.values(); + if (logger.isInfoEnabled()) { + logger.info("The Dubbo GenericService ReferenceBeans are destroying..."); + } + for (ReferenceBean referenceBean : referenceBeans) { + referenceBean.destroy(); // destroy ReferenceBean + if (logger.isInfoEnabled()) { + logger.info("Destroyed the ReferenceBean : {} ", referenceBean); + } + } } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/MetadataConfigService.java similarity index 94% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/MetadataConfigService.java index 28b7a373..734050a2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/MetadataConfigService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.metadata.service; +package org.springframework.cloud.alibaba.dubbo.service; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/NacosMetadataConfigService.java similarity index 98% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/NacosMetadataConfigService.java index 93ce9281..13baee0d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/NacosMetadataConfigService.java @@ -14,10 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.metadata.service; +package org.springframework.cloud.alibaba.dubbo.service; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java new file mode 100644 index 00000000..ebcae398 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service.parameter; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.convert.ConversionService; +import org.springframework.format.support.FormattingConversionService; + +import static org.springframework.context.ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME; +import static org.springframework.util.ClassUtils.resolveClassName; + +/** + * Abstract {@link DubboGenericServiceParameterResolver} implementation + * + * @author Mercy + */ +public abstract class AbstractDubboGenericServiceParameterResolver implements DubboGenericServiceParameterResolver, BeanClassLoaderAware { + + private int order; + + @Autowired(required = false) + @Qualifier(CONVERSION_SERVICE_BEAN_NAME) + private ConversionService conversionService = new FormattingConversionService(); + + private ClassLoader classLoader; + + public ConversionService getConversionService() { + return conversionService; + } + + public void setConversionService(ConversionService conversionService) { + this.conversionService = conversionService; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return order; + } + + protected Class resolveClass(String className) { + return resolveClassName(className, classLoader); + } + + protected Object resolveValue(Object parameterValue, String parameterType) { + Class targetType = resolveClass(parameterType); + return resolveValue(parameterValue, targetType); + } + + protected Object resolveValue(Object parameterValue, Class parameterType) { + return conversionService.convert(parameterValue, parameterType); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/DubboGenericServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/DubboGenericServiceParameterResolver.java new file mode 100644 index 00000000..1c302b59 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/DubboGenericServiceParameterResolver.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service.parameter; + +import com.alibaba.dubbo.rpc.service.GenericService; + +import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.core.Ordered; +import org.springframework.http.server.ServerHttpRequest; + +/** + * Dubbo {@link GenericService} Parameter Resolver + * + * @author Mercy + */ +public interface DubboGenericServiceParameterResolver extends Ordered { + + /** + * Whether the given {@linkplain DubboServiceMetadata Dubbo Service Metadata} is + * supported by this resolver. + * + * @return {@code true} if this resolver supports the supplied parameter; + * {@code false} otherwise + */ + boolean supportParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata); + + /** + * Resolves a method parameter into an argument value from a given request. + * + * @return + */ + Object resolveParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, + ServerHttpRequest request); +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestBodyServerParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestBodyServerParameterResolver.java new file mode 100644 index 00000000..da156fe4 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestBodyServerParameterResolver.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service.parameter; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.cloud.alibaba.dubbo.http.converter.HttpMessageConverterHolder; +import org.springframework.cloud.alibaba.dubbo.http.util.HttpMessageConverterResolver; +import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.server.ServerHttpRequest; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.util.Collections; +import java.util.Objects; + +/** + * HTTP Request Body {@link DubboGenericServiceParameterResolver} + * + * @author Mercy + */ +public class RequestBodyServerParameterResolver extends AbstractDubboGenericServiceParameterResolver { + + public static final int DEFAULT_ORDER = 7; + + @Autowired + private ObjectProvider httpMessageConverters; + + private HttpMessageConverterResolver httpMessageConverterResolver; + + public RequestBodyServerParameterResolver() { + super(); + setOrder(DEFAULT_ORDER); + } + + @PostConstruct + public void init() { + HttpMessageConverters httpMessageConverters = this.httpMessageConverters.getIfAvailable(); + + httpMessageConverterResolver = new HttpMessageConverterResolver(httpMessageConverters == null ? + Collections.emptyList() : httpMessageConverters.getConverters(), + getClassLoader()); + } + + @Override + public boolean supportParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata) { + + Integer index = methodParameterMetadata.getIndex(); + + Integer bodyIndex = restMethodMetadata.getBodyIndex(); + + if (!Objects.equals(index, bodyIndex)) { + return false; + } + + Class parameterType = resolveClass(methodParameterMetadata.getType()); + + Class bodyType = resolveClass(restMethodMetadata.getBodyType()); + + return Objects.equals(parameterType, bodyType); + } + + @Override + public Object resolveParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, + ServerHttpRequest request) { + + Object result = null; + + Class parameterType = resolveClass(methodParameterMetadata.getType()); + + HttpMessageConverterHolder holder = httpMessageConverterResolver.resolve(request, parameterType); + + if (holder != null) { + HttpMessageConverter converter = holder.getConverter(); + try { + result = converter.read(parameterType, request); + } catch (IOException e) { + throw new HttpMessageNotReadableException("I/O error while reading input message", e); + } + } + + return result; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestParamServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestParamServiceParameterResolver.java new file mode 100644 index 00000000..a031d5fc --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/parameter/RequestParamServiceParameterResolver.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service.parameter; + +import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.util.CollectionUtils; +import org.springframework.util.MultiValueMap; +import org.springframework.web.util.UriComponents; + +import java.net.URI; +import java.util.Collection; +import java.util.Map; + +import static org.springframework.web.util.UriComponentsBuilder.fromUri; + +/** + * HTTP Request Parameter {@link DubboGenericServiceParameterResolver Dubbo GenericService Parameter Resolver} + * + * @author Mercy + */ +public class RequestParamServiceParameterResolver extends AbstractDubboGenericServiceParameterResolver { + + public static final int DEFAULT_ORDER = 1; + + public RequestParamServiceParameterResolver() { + super(); + setOrder(DEFAULT_ORDER); + } + + @Override + public boolean supportParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata) { + Map> indexToName = restMethodMetadata.getIndexToName(); + + int index = methodParameterMetadata.getIndex(); + + Collection paramNames = indexToName.get(index); + + if (CollectionUtils.isEmpty(paramNames)) { + return false; + } + + String paramName = methodParameterMetadata.getName(); + + return paramNames.contains(paramName); + } + + @Override + public Object resolveParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata parameterMetadata, + ServerHttpRequest request) { + + URI uri = request.getURI(); + + UriComponents uriComponents = fromUri(uri).build(true); + + MultiValueMap params = uriComponents.getQueryParams(); + + String paramName = parameterMetadata.getName(); + + Class parameterType = resolveClass(parameterMetadata.getType()); + + Object paramValue = null; + + if (parameterType.isArray()) { // Array type + paramValue = params.get(paramName); + } else { + paramValue = params.getFirst(paramName); + } + + return resolveValue(paramValue, parameterType); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java index 2334ebe1..b986f753 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -36,6 +36,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; +import java.util.HashMap; +import java.util.Map; + import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -112,12 +115,12 @@ public class DubboSpringCloudBootstrap { ResponseEntity entity = restTemplate.getForEntity("http://spring-cloud-alibaba-dubbo/echo?message=小马哥", String.class); System.out.println(entity.getHeaders()); System.out.println(entity.getBody()); - // Still issue -// Map data = new HashMap<>(); -// data.put("name", "小马哥"); -// data.put("age", 33); -// data.put("height", 173); -// System.out.println(restTemplate.postForEntity("http://spring-cloud-alibaba-dubbo/toString", data, String.class)); +// Still issue + Map data = new HashMap<>(); + data.put("name", "小马哥"); + data.put("age", 33); + data.put("height", 173); + System.out.println(restTemplate.postForEntity("http://spring-cloud-alibaba-dubbo/toString", data, String.class)); }; }