diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java index 2d7a08002..f992365eb 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java @@ -16,7 +16,6 @@ */ package com.alibaba.cloud.dubbo.actuate; -import com.alibaba.cloud.dubbo.actuate.endpoint.DubboRestMetadataEndpoint; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -25,6 +24,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import com.alibaba.cloud.dubbo.actuate.endpoint.DubboRestMetadataEndpoint; + /** * Dubbo Metadata Endpoints Auto-{@link Configuration} * @@ -35,12 +36,10 @@ import org.springframework.context.annotation.PropertySource; @ManagementContextConfiguration public class DubboMetadataEndpointAutoConfiguration { - @Bean - @ConditionalOnMissingBean - @ConditionalOnEnabledEndpoint - public DubboRestMetadataEndpoint dubboRestMetadataEndpoint() { - return new DubboRestMetadataEndpoint(); - } + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + public DubboRestMetadataEndpoint dubboRestMetadataEndpoint() { + return new DubboRestMetadataEndpoint(); + } } - - diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java index 41697d7e5..e04e246d5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java @@ -16,12 +16,13 @@ */ package com.alibaba.cloud.dubbo.actuate.endpoint; -import com.alibaba.cloud.dubbo.service.DubboMetadataService; +import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; -import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; +import com.alibaba.cloud.dubbo.service.DubboMetadataService; /** * Dubbo Rest Metadata {@link Endpoint} @@ -31,11 +32,11 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; @Endpoint(id = "dubborestmetadata") public class DubboRestMetadataEndpoint { - @Autowired - private DubboMetadataService dubboMetadataService; + @Autowired + private DubboMetadataService dubboMetadataService; - @ReadOperation(produces = APPLICATION_JSON_UTF8_VALUE) - public String get() { - return dubboMetadataService.getServiceRestMetadata(); - } + @ReadOperation(produces = APPLICATION_JSON_UTF8_VALUE) + public String get() { + return dubboMetadataService.getServiceRestMetadata(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java index 10724aa73..23dcf34ff 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java @@ -16,13 +16,7 @@ */ package com.alibaba.cloud.dubbo.annotation; -import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.rpc.ExporterListener; -import org.apache.dubbo.rpc.Filter; - -import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.client.RestTemplate; +import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_RETRIES; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -30,22 +24,31 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_RETRIES; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.rpc.ExporterListener; +import org.apache.dubbo.rpc.Filter; + +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.client.RestTemplate; /** - * {@link DubboTransported @DubboTransported} annotation indicates that the traditional Spring Cloud Service-to-Service call is transported - * by Dubbo under the hood, there are two main scenarios: + * {@link DubboTransported @DubboTransported} annotation indicates that the traditional + * Spring Cloud Service-to-Service call is transported by Dubbo under the hood, there are + * two main scenarios: *
    *
  1. {@link FeignClient @FeignClient} annotated classes: * * *
  2. - *
  3. {@link LoadBalanced @LoadBalanced} {@link RestTemplate} annotated field, method and parameters
  4. + *
  5. {@link LoadBalanced @LoadBalanced} {@link RestTemplate} annotated field, method and + * parameters
  6. *
*

* @@ -54,94 +57,99 @@ import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_RETRIES; * @see LoadBalanced */ @Retention(RetentionPolicy.RUNTIME) -@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, + ElementType.PARAMETER }) @Documented public @interface DubboTransported { - /** - * The protocol of Dubbo transport whose value could be used the placeholder "dubbo.transport.protocol" - * - * @return the default protocol is "dubbo" - */ - String protocol() default "${dubbo.transport.protocol:dubbo}"; - - /** - * The cluster of Dubbo transport whose value could be used the placeholder "dubbo.transport.cluster" - * - * @return the default cluster is "failover" - */ - String cluster() default "${dubbo.transport.cluster:failover}"; - - /** - * Whether to reconnect if connection is lost, if not specify, reconnect is enabled by default, and the interval - * for retry connecting is 2000 ms - * - * @see Reference#reconnect() - */ - String reconnect() default "${dubbo.transport.reconnect:2000}"; - - /** - * Maximum connections service provider can accept, default value is 0 - connection is shared - * - * @see Reference#connections() - */ - int connections() default 0; - - /** - * Service invocation retry times - * - * @see Reference#retries() - */ - int retries() default DEFAULT_RETRIES; - - /** - * Load balance strategy, legal values include: random, roundrobin, leastactive - * - * @see Reference#loadbalance() - */ - String loadbalance() default "${dubbo.transport.loadbalance:}"; - - /** - * Maximum active requests allowed, default value is 0 - * - * @see Reference#actives() - */ - int actives() default 0; - - /** - * Timeout value for service invocation, default value is 0 - * - * @see Reference#timeout() - */ - int timeout() default 0; - - /** - * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache - * - * @see Reference#cache() - */ - String cache() default "${dubbo.transport.cache:}"; - - /** - * Filters for service invocation - * - * @see Filter - * @see Reference#filter() - */ - String[] filter() default {}; - - /** - * Listeners for service exporting and unexporting - * - * @see ExporterListener - * @see Reference#listener() - */ - String[] listener() default {}; - - /** - * Customized parameter key-value pair, for example: {key1, value1, key2, value2} - * - * @see Reference#parameters() - */ - String[] parameters() default {}; + /** + * The protocol of Dubbo transport whose value could be used the placeholder + * "dubbo.transport.protocol" + * + * @return the default protocol is "dubbo" + */ + String protocol() default "${dubbo.transport.protocol:dubbo}"; + + /** + * The cluster of Dubbo transport whose value could be used the placeholder + * "dubbo.transport.cluster" + * + * @return the default cluster is "failover" + */ + String cluster() default "${dubbo.transport.cluster:failover}"; + + /** + * Whether to reconnect if connection is lost, if not specify, reconnect is enabled by + * default, and the interval for retry connecting is 2000 ms + * + * @see Reference#reconnect() + */ + String reconnect() default "${dubbo.transport.reconnect:2000}"; + + /** + * Maximum connections service provider can accept, default value is 0 - connection is + * shared + * + * @see Reference#connections() + */ + int connections() default 0; + + /** + * Service invocation retry times + * + * @see Reference#retries() + */ + int retries() default DEFAULT_RETRIES; + + /** + * Load balance strategy, legal values include: random, roundrobin, leastactive + * + * @see Reference#loadbalance() + */ + String loadbalance() default "${dubbo.transport.loadbalance:}"; + + /** + * Maximum active requests allowed, default value is 0 + * + * @see Reference#actives() + */ + int actives() default 0; + + /** + * Timeout value for service invocation, default value is 0 + * + * @see Reference#timeout() + */ + int timeout() default 0; + + /** + * Specify cache implementation for service invocation, legal values include: lru, + * threadlocal, jcache + * + * @see Reference#cache() + */ + String cache() default "${dubbo.transport.cache:}"; + + /** + * Filters for service invocation + * + * @see Filter + * @see Reference#filter() + */ + String[] filter() default {}; + + /** + * Listeners for service exporting and unexporting + * + * @see ExporterListener + * @see Reference#listener() + */ + String[] listener() default {}; + + /** + * Customized parameter key-value pair, for example: {key1, value1, key2, value2} + * + * @see Reference#parameters() + */ + String[] parameters() default {}; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java index 00c464dff..5165e4b53 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java @@ -16,13 +16,11 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; -import com.alibaba.cloud.dubbo.annotation.DubboTransported; -import com.alibaba.cloud.dubbo.client.loadbalancer.DubboMetadataInitializerInterceptor; -import com.alibaba.cloud.dubbo.client.loadbalancer.DubboTransporterInterceptor; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.metadata.resolver.DubboTransportedAttributesResolver; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; @@ -44,133 +42,154 @@ import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import com.alibaba.cloud.dubbo.annotation.DubboTransported; +import com.alibaba.cloud.dubbo.client.loadbalancer.DubboMetadataInitializerInterceptor; +import com.alibaba.cloud.dubbo.client.loadbalancer.DubboTransporterInterceptor; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.metadata.resolver.DubboTransportedAttributesResolver; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; /** - * Dubbo Auto-{@link Configuration} for {@link LoadBalanced @LoadBalanced} {@link RestTemplate} + * Dubbo Auto-{@link Configuration} for {@link LoadBalanced @LoadBalanced} + * {@link RestTemplate} * * @author Mercy */ @Configuration -@ConditionalOnClass(name = {"org.springframework.web.client.RestTemplate"}) -@AutoConfigureAfter(name = {"org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration"}) -public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClassLoaderAware, SmartInitializingSingleton { - - private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class; - - private static final String DUBBO_TRANSPORTED_CLASS_NAME = DUBBO_TRANSPORTED_CLASS.getName(); - - @Autowired - private DubboServiceMetadataRepository repository; - - @Autowired(required = false) - private LoadBalancerInterceptor loadBalancerInterceptor; - - @Autowired(required = false) - private RetryLoadBalancerInterceptor retryLoadBalancerInterceptor; - - @Autowired - private ConfigurableListableBeanFactory beanFactory; - - @Autowired - private DubboGenericServiceFactory serviceFactory; - - @Autowired - private DubboGenericServiceExecutionContextFactory contextFactory; - - @Autowired - private Environment environment; - - @LoadBalanced - @Autowired(required = false) - private Map restTemplates = Collections.emptyMap(); - - private ClassLoader classLoader; - - /** - * The {@link ClientHttpRequestInterceptor} bean that may be {@link LoadBalancerInterceptor} or {@link RetryLoadBalancerInterceptor} - */ - private ClientHttpRequestInterceptor loadBalancerInterceptorBean; - - @Override - public void afterSingletonsInstantiated() { - loadBalancerInterceptorBean = retryLoadBalancerInterceptor != null ? - retryLoadBalancerInterceptor : - loadBalancerInterceptor; - } - - /** - * Adapt the {@link RestTemplate} beans that are annotated {@link LoadBalanced @LoadBalanced} and - * {@link LoadBalanced @LoadBalanced} when Spring Boot application started - * (after the callback of {@link SmartInitializingSingleton} beans or - * {@link RestTemplateCustomizer#customize(RestTemplate) customization}) - */ - @EventListener(ApplicationStartedEvent.class) - public void adaptRestTemplates() { - - DubboTransportedAttributesResolver attributesResolver = new DubboTransportedAttributesResolver(environment); - - for (Map.Entry entry : restTemplates.entrySet()) { - String beanName = entry.getKey(); - Map dubboTranslatedAttributes = getDubboTranslatedAttributes(beanName, attributesResolver); - if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) { - adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes); - } - } - } - - /** - * Gets the annotation attributes {@link RestTemplate} bean being annotated - * {@link DubboTransported @DubboTransported} - * - * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} {@link RestTemplate} - * @param attributesResolver {@link DubboTransportedAttributesResolver} - * @return non-null {@link Map} - */ - private Map getDubboTranslatedAttributes(String beanName, - DubboTransportedAttributesResolver attributesResolver) { - Map attributes = Collections.emptyMap(); - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); - if (beanDefinition instanceof AnnotatedBeanDefinition) { - AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; - MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata(); - attributes = factoryMethodMetadata != null ? - factoryMethodMetadata.getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME) : Collections.emptyMap(); - } - return attributesResolver.resolve(attributes); - } - - - /** - * Adapt the instance of {@link DubboTransporterInterceptor} to the {@link LoadBalancerInterceptor} 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, Map dubboTranslatedAttributes) { - - List interceptors = new ArrayList<>(restTemplate.getInterceptors()); - - int index = loadBalancerInterceptorBean == null ? -1 : interceptors.indexOf(loadBalancerInterceptorBean); - - index = index < 0 ? 0 : index; - - // Add ClientHttpRequestInterceptor instances before loadBalancerInterceptor - interceptors.add(index++, new DubboMetadataInitializerInterceptor(repository)); - - interceptors.add(index++, new DubboTransporterInterceptor(repository, restTemplate.getMessageConverters(), - classLoader, dubboTranslatedAttributes, serviceFactory, contextFactory)); - - restTemplate.setInterceptors(interceptors); - } - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } +@ConditionalOnClass(name = { "org.springframework.web.client.RestTemplate" }) +@AutoConfigureAfter(name = { + "org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration" }) +public class DubboLoadBalancedRestTemplateAutoConfiguration + implements BeanClassLoaderAware, SmartInitializingSingleton { + + private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class; + + private static final String DUBBO_TRANSPORTED_CLASS_NAME = DUBBO_TRANSPORTED_CLASS + .getName(); + + @Autowired + private DubboServiceMetadataRepository repository; + + @Autowired(required = false) + private LoadBalancerInterceptor loadBalancerInterceptor; + + @Autowired(required = false) + private RetryLoadBalancerInterceptor retryLoadBalancerInterceptor; + + @Autowired + private ConfigurableListableBeanFactory beanFactory; + + @Autowired + private DubboGenericServiceFactory serviceFactory; + + @Autowired + private DubboGenericServiceExecutionContextFactory contextFactory; + + @Autowired + private Environment environment; + + @LoadBalanced + @Autowired(required = false) + private Map restTemplates = Collections.emptyMap(); + + private ClassLoader classLoader; + + /** + * The {@link ClientHttpRequestInterceptor} bean that may be + * {@link LoadBalancerInterceptor} or {@link RetryLoadBalancerInterceptor} + */ + private ClientHttpRequestInterceptor loadBalancerInterceptorBean; + + @Override + public void afterSingletonsInstantiated() { + loadBalancerInterceptorBean = retryLoadBalancerInterceptor != null + ? retryLoadBalancerInterceptor + : loadBalancerInterceptor; + } + + /** + * Adapt the {@link RestTemplate} beans that are annotated + * {@link LoadBalanced @LoadBalanced} and {@link LoadBalanced @LoadBalanced} when + * Spring Boot application started (after the callback of + * {@link SmartInitializingSingleton} beans or + * {@link RestTemplateCustomizer#customize(RestTemplate) customization}) + */ + @EventListener(ApplicationStartedEvent.class) + public void adaptRestTemplates() { + + DubboTransportedAttributesResolver attributesResolver = new DubboTransportedAttributesResolver( + environment); + + for (Map.Entry entry : restTemplates.entrySet()) { + String beanName = entry.getKey(); + Map dubboTranslatedAttributes = getDubboTranslatedAttributes( + beanName, attributesResolver); + if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) { + adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes); + } + } + } + + /** + * Gets the annotation attributes {@link RestTemplate} bean being annotated + * {@link DubboTransported @DubboTransported} + * + * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} + * {@link RestTemplate} + * @param attributesResolver {@link DubboTransportedAttributesResolver} + * @return non-null {@link Map} + */ + private Map getDubboTranslatedAttributes(String beanName, + DubboTransportedAttributesResolver attributesResolver) { + Map attributes = Collections.emptyMap(); + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + if (beanDefinition instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; + MethodMetadata factoryMethodMetadata = annotatedBeanDefinition + .getFactoryMethodMetadata(); + attributes = factoryMethodMetadata != null + ? factoryMethodMetadata + .getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME) + : Collections.emptyMap(); + } + return attributesResolver.resolve(attributes); + } + + /** + * Adapt the instance of {@link DubboTransporterInterceptor} to the + * {@link LoadBalancerInterceptor} 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, + Map dubboTranslatedAttributes) { + + List interceptors = new ArrayList<>( + restTemplate.getInterceptors()); + + int index = loadBalancerInterceptorBean == null ? -1 + : interceptors.indexOf(loadBalancerInterceptorBean); + + index = index < 0 ? 0 : index; + + // Add ClientHttpRequestInterceptor instances before loadBalancerInterceptor + interceptors.add(index++, new DubboMetadataInitializerInterceptor(repository)); + + interceptors.add(index++, + new DubboTransporterInterceptor(repository, + restTemplate.getMessageConverters(), classLoader, + dubboTranslatedAttributes, serviceFactory, contextFactory)); + + restTemplate.setInterceptors(interceptors); + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index cfab21fc1..f39aa5fb2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -16,20 +16,13 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; +import java.util.Collection; +import java.util.function.Supplier; + import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; -import com.alibaba.cloud.dubbo.metadata.DubboProtocolConfigSupplier; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver; -import com.alibaba.cloud.dubbo.metadata.resolver.MetadataResolver; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; -import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter; -import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; -import com.alibaba.cloud.dubbo.service.IntrospectiveDubboMetadataService; -import com.alibaba.cloud.dubbo.util.JSONUtils; -import feign.Contract; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -40,8 +33,17 @@ import org.springframework.context.annotation.Import; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.EventListener; -import java.util.Collection; -import java.util.function.Supplier; +import com.alibaba.cloud.dubbo.metadata.DubboProtocolConfigSupplier; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver; +import com.alibaba.cloud.dubbo.metadata.resolver.MetadataResolver; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; +import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter; +import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; +import com.alibaba.cloud.dubbo.service.IntrospectiveDubboMetadataService; +import com.alibaba.cloud.dubbo.util.JSONUtils; + +import feign.Contract; /** * Spring Boot Auto-Configuration class for Dubbo Metadata @@ -49,61 +51,62 @@ import java.util.function.Supplier; * @author Mercy */ @Configuration -@Import({DubboServiceMetadataRepository.class, - IntrospectiveDubboMetadataService.class, - DubboMetadataServiceExporter.class, - JSONUtils.class}) +@Import({ DubboServiceMetadataRepository.class, IntrospectiveDubboMetadataService.class, + DubboMetadataServiceExporter.class, JSONUtils.class }) public class DubboMetadataAutoConfiguration { - @Autowired - private ObjectProvider dubboServiceMetadataRepository; - - @Autowired - private MetadataResolver metadataResolver; - - @Autowired - private DubboMetadataServiceExporter dubboMetadataConfigServiceExporter; - - @Bean - @ConditionalOnMissingBean - public MetadataResolver metadataJsonResolver(ObjectProvider contract) { - return new DubboServiceBeanMetadataResolver(contract); - } - - @Bean - public Supplier dubboProtocolConfigSupplier(ObjectProvider> protocols) { - return new DubboProtocolConfigSupplier(protocols); - } - - @Bean - @ConditionalOnMissingBean - public DubboMetadataServiceProxy dubboMetadataConfigServiceProxy(DubboGenericServiceFactory factory) { - return new DubboMetadataServiceProxy(factory); - } - - // Event-Handling - - @EventListener(ServiceBeanExportedEvent.class) - public void onServiceBeanExported(ServiceBeanExportedEvent event) { - ServiceBean serviceBean = event.getServiceBean(); - publishServiceRestMetadata(serviceBean); - } - - @EventListener(ApplicationFailedEvent.class) - public void onApplicationFailed() { - unExportDubboMetadataConfigService(); - } - - @EventListener(ContextClosedEvent.class) - public void onContextClosed() { - unExportDubboMetadataConfigService(); - } - - private void publishServiceRestMetadata(ServiceBean serviceBean) { - dubboServiceMetadataRepository.getIfAvailable().publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); - } - - private void unExportDubboMetadataConfigService() { - dubboMetadataConfigServiceExporter.unexport(); - } + @Autowired + private ObjectProvider dubboServiceMetadataRepository; + + @Autowired + private MetadataResolver metadataResolver; + + @Autowired + private DubboMetadataServiceExporter dubboMetadataConfigServiceExporter; + + @Bean + @ConditionalOnMissingBean + public MetadataResolver metadataJsonResolver(ObjectProvider contract) { + return new DubboServiceBeanMetadataResolver(contract); + } + + @Bean + public Supplier dubboProtocolConfigSupplier( + ObjectProvider> protocols) { + return new DubboProtocolConfigSupplier(protocols); + } + + @Bean + @ConditionalOnMissingBean + public DubboMetadataServiceProxy dubboMetadataConfigServiceProxy( + DubboGenericServiceFactory factory) { + return new DubboMetadataServiceProxy(factory); + } + + // Event-Handling + + @EventListener(ServiceBeanExportedEvent.class) + public void onServiceBeanExported(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + publishServiceRestMetadata(serviceBean); + } + + @EventListener(ApplicationFailedEvent.class) + public void onApplicationFailed() { + unExportDubboMetadataConfigService(); + } + + @EventListener(ContextClosedEvent.class) + public void onContextClosed() { + unExportDubboMetadataConfigService(); + } + + private void publishServiceRestMetadata(ServiceBean serviceBean) { + dubboServiceMetadataRepository.getIfAvailable().publishServiceRestMetadata( + metadataResolver.resolveServiceRestMetadata(serviceBean)); + } + + private void unExportDubboMetadataConfigService() { + dubboMetadataConfigServiceExporter.unexport(); + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java index 230b54b01..0f282bf3f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java @@ -16,38 +16,39 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.openfeign.TargeterBeanPostProcessor; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.TARGETER_CLASS_NAME; + import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.TARGETER_CLASS_NAME; - +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.openfeign.TargeterBeanPostProcessor; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; /** * Dubbo Feign Auto-{@link Configuration Configuration} * * @author Mercy */ -@ConditionalOnClass(name = {"feign.Feign", TARGETER_CLASS_NAME}) -@AutoConfigureAfter(name = {"org.springframework.cloud.openfeign.FeignAutoConfiguration"}) +@ConditionalOnClass(name = { "feign.Feign", TARGETER_CLASS_NAME }) +@AutoConfigureAfter(name = { + "org.springframework.cloud.openfeign.FeignAutoConfiguration" }) @Configuration public class DubboOpenFeignAutoConfiguration { - public static final String TARGETER_CLASS_NAME = "org.springframework.cloud.openfeign.Targeter"; + public static final String TARGETER_CLASS_NAME = "org.springframework.cloud.openfeign.Targeter"; - @Bean - public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment, - DubboServiceMetadataRepository dubboServiceMetadataRepository, - DubboGenericServiceFactory dubboGenericServiceFactory, - DubboGenericServiceExecutionContextFactory contextFactory) { - return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository, - dubboGenericServiceFactory, contextFactory); - } + @Bean + public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment, + DubboServiceMetadataRepository dubboServiceMetadataRepository, + 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/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java index 70ba733ba..70d992dcd 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java @@ -16,13 +16,6 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; -import com.alibaba.cloud.dubbo.env.DubboCloudProperties; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; -import com.alibaba.cloud.dubbo.service.parameter.PathVariableServiceParameterResolver; -import com.alibaba.cloud.dubbo.service.parameter.RequestBodyServiceParameterResolver; -import com.alibaba.cloud.dubbo.service.parameter.RequestHeaderServiceParameterResolver; -import com.alibaba.cloud.dubbo.service.parameter.RequestParamServiceParameterResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -33,6 +26,14 @@ import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertyResolver; +import com.alibaba.cloud.dubbo.env.DubboCloudProperties; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; +import com.alibaba.cloud.dubbo.service.parameter.PathVariableServiceParameterResolver; +import com.alibaba.cloud.dubbo.service.parameter.RequestBodyServiceParameterResolver; +import com.alibaba.cloud.dubbo.service.parameter.RequestHeaderServiceParameterResolver; +import com.alibaba.cloud.dubbo.service.parameter.RequestParamServiceParameterResolver; + /** * Spring Boot Auto-Configuration class for Dubbo Service * @@ -42,32 +43,30 @@ import org.springframework.core.env.PropertyResolver; @EnableConfigurationProperties(DubboCloudProperties.class) public class DubboServiceAutoConfiguration { - @Bean - @ConditionalOnMissingBean - public DubboGenericServiceFactory dubboGenericServiceFactory() { - return new DubboGenericServiceFactory(); - } + @Bean + @ConditionalOnMissingBean + public DubboGenericServiceFactory dubboGenericServiceFactory() { + return new DubboGenericServiceFactory(); + } - /** - * Build a primary {@link PropertyResolver} bean to {@link Autowired @Autowired} - * - * @param environment {@link Environment} - * @return alias bean for {@link Environment} - */ - @Bean - @Primary - public PropertyResolver primaryPropertyResolver(Environment environment) { - return environment; - } + /** + * Build a primary {@link PropertyResolver} bean to {@link Autowired @Autowired} + * + * @param environment {@link Environment} + * @return alias bean for {@link Environment} + */ + @Bean + @Primary + public PropertyResolver primaryPropertyResolver(Environment environment) { + return environment; + } - @Configuration - @Import(value = { - DubboGenericServiceExecutionContextFactory.class, - RequestParamServiceParameterResolver.class, - RequestBodyServiceParameterResolver.class, - RequestHeaderServiceParameterResolver.class, - PathVariableServiceParameterResolver.class - }) - static class ParameterResolversConfiguration { - } + @Configuration + @Import(value = { DubboGenericServiceExecutionContextFactory.class, + RequestParamServiceParameterResolver.class, + RequestBodyServiceParameterResolver.class, + RequestHeaderServiceParameterResolver.class, + PathVariableServiceParameterResolver.class }) + static class ParameterResolversConfiguration { + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java index 4a91b762b..db22da918 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java @@ -16,21 +16,24 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.registry.NotifyListener; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient.hostToServiceInstanceList; +import static org.springframework.util.StringUtils.hasText; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; +import java.util.stream.Stream; -import com.alibaba.cloud.dubbo.env.DubboCloudProperties; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.registry.AbstractSpringCloudRegistry; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; -import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; -import com.alibaba.cloud.nacos.NacosDiscoveryProperties; -import com.alibaba.cloud.nacos.discovery.NacosWatch; -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.NamingService; -import com.alibaba.nacos.api.naming.listener.NamingEvent; -import com.netflix.discovery.CacheRefreshedEvent; -import com.netflix.discovery.shared.Applications; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.listen.Listenable; import org.apache.curator.framework.listen.ListenerContainer; @@ -38,6 +41,10 @@ import org.apache.curator.framework.recipes.cache.ChildData; import org.apache.curator.framework.recipes.cache.TreeCache; import org.apache.curator.framework.recipes.cache.TreeCacheEvent; import org.apache.curator.framework.recipes.cache.TreeCacheListener; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.registry.NotifyListener; + import org.apache.zookeeper.Watcher; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; @@ -67,26 +74,22 @@ import org.springframework.scheduling.TaskScheduler; import org.springframework.util.AntPathMatcher; import org.springframework.util.ReflectionUtils; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient.hostToServiceInstanceList; -import static org.springframework.util.StringUtils.hasText; +import com.alibaba.cloud.dubbo.env.DubboCloudProperties; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.AbstractSpringCloudRegistry; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; +import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.cloud.nacos.discovery.NacosWatch; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.netflix.discovery.CacheRefreshedEvent; +import com.netflix.discovery.shared.Applications; /** - * Dubbo Service Discovery Auto {@link Configuration} (after {@link DubboServiceRegistrationAutoConfiguration}) + * Dubbo Service Discovery Auto {@link Configuration} (after + * {@link DubboServiceRegistrationAutoConfiguration}) * * @author Mercy * @see DubboServiceRegistrationAutoConfiguration @@ -96,421 +99,454 @@ import static org.springframework.util.StringUtils.hasText; @Configuration @ConditionalOnClass(name = "org.springframework.cloud.client.discovery.DiscoveryClient") @ConditionalOnProperty(name = "spring.cloud.discovery.enabled", matchIfMissing = true) -@AutoConfigureAfter(name = { - EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, - ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, - CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, - NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME -}, value = {DubboServiceRegistrationAutoConfiguration.class}) +@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, + ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, + NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME }, value = { + DubboServiceRegistrationAutoConfiguration.class }) public class DubboServiceDiscoveryAutoConfiguration { - public static final String ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryAutoConfiguration"; - - public static final String CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration"; - - public static final String NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration"; - - private final DubboServiceMetadataRepository dubboServiceMetadataRepository; - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final ApplicationEventPublisher applicationEventPublisher; - - private final DiscoveryClient discoveryClient; - - private final AtomicReference heartbeatState = new AtomicReference<>(); - - /** - * @see #defaultHeartbeatEventChangePredicate() - */ - private final ObjectProvider> heartbeatEventChangedPredicate; - - public DubboServiceDiscoveryAutoConfiguration(DubboServiceMetadataRepository dubboServiceMetadataRepository, - ApplicationEventPublisher applicationEventPublisher, - DiscoveryClient discoveryClient, - ObjectProvider> heartbeatEventChangedPredicate) { - this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; - this.applicationEventPublisher = applicationEventPublisher; - this.discoveryClient = discoveryClient; - this.heartbeatEventChangedPredicate = heartbeatEventChangedPredicate; - } - - /** - * Dispatch a {@link ServiceInstancesChangedEvent} - * - * @param serviceName the name of service - * @param serviceInstances the {@link ServiceInstance instances} of some service - * @see AbstractSpringCloudRegistry#registerServiceInstancesChangedEventListener(URL, NotifyListener) - */ - private void dispatchServiceInstancesChangedEvent(String serviceName, Collection serviceInstances) { - if (!hasText(serviceName) || serviceInstances == null) { - return; - } - ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(serviceName, serviceInstances); - if (logger.isInfoEnabled()) { - logger.info("The event of the service instances[name : {} , size : {}] change is about to be dispatched", - serviceName, serviceInstances.size()); - } - applicationEventPublisher.publishEvent(event); - } - - private List getInstances(String serviceName) { - return discoveryClient.getInstances(serviceName); - } - - /** - * Dispatch a {@link ServiceInstancesChangedEvent} when the {@link HeartbeatEvent} raised, use for these scenarios: - *
    - *
  • Eureka : {@link CloudEurekaClient#onCacheRefreshed()} publishes a {@link HeartbeatEvent} instead of {@link CacheRefreshedEvent}
  • - *
  • Zookeeper : {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} publishes a - * {@link HeartbeatEvent} when {@link ZookeeperDiscoveryProperties#getRoot() the services' root path} has been changed
  • - *
  • Consul : {@link ConsulCatalogWatch#catalogServicesWatch()} publishes a {@link HeartbeatEvent} when - * Consul's Blocking Queries response - *
  • - *
  • Nacos : {@link NacosWatch#nacosServicesWatch()} publishes a {@link HeartbeatEvent} under a - * {@link TaskScheduler} every {@link NacosDiscoveryProperties#getWatchDelay()} milliseconds
  • - *
- *

- * In order to reduce the duplicated handling for {@link ServiceInstancesChangedEvent}, - * {@link #defaultHeartbeatEventChangePredicate()} method providers the default implementation to detect whether the - * {@link HeartbeatEvent#getValue() state} is changed or not. If and only if changed, the - * {@link #dispatchServiceInstancesChangedEvent(String, Collection)} will be executed. - *

- * Note : - * Spring Cloud {@link HeartbeatEvent} has a critical flaw that can't figure out which service was changed precisely, - * it's just used for a notification that the - * {@link DubboServiceMetadataRepository#getSubscribedServices() subscribed services} used to - * {@link NotifyListener#notify(List) notify} the Dubbo consumer cached {@link URL URLs}. - * Because of some {@link DiscoveryClient} implementations have the better and fine-grained the event mechanism for service instances - * change, thus {@link HeartbeatEvent} handle will be ignored in these scenarios: - *

    - *
  • Zookeeper : {@link Watcher}, see {@link ZookeeperConfiguration#heartbeatEventChangedPredicate()}
  • - *
  • Nacos : {@link com.alibaba.nacos.api.naming.listener.EventListener} , see {@link NacosConfiguration#heartbeatEventChangedPredicate()}
  • - *
- *

- * If the customized {@link DiscoveryClient} also providers the similar mechanism, the implementation could declare - * a Spring Bean of {@link Predicate} of {@link HeartbeatEvent} to override - * {@link #defaultHeartbeatEventChangePredicate() default one}. - * - * @param event the instance of {@link HeartbeatEvent} - * @see HeartbeatEvent - */ - @EventListener(HeartbeatEvent.class) - public void onHeartbeatEvent(HeartbeatEvent event) { - /** - * Try to re-initialize the subscribed services, in order to sense the change of services if - * {@link DubboCloudProperties#getSubscribedServices()} is wildcard that indicates all services should be - * subscribed. - */ - Stream subscribedServices = dubboServiceMetadataRepository.initSubscribedServices(); - - heartbeatEventChangedPredicate.ifAvailable(predicate -> { - if (predicate.test(event)) { - // Dispatch ServiceInstancesChangedEvent for each service - subscribedServices.forEach(serviceName -> { - List serviceInstances = getInstances(serviceName); - dispatchServiceInstancesChangedEvent(serviceName, serviceInstances); - }); - } - }); - } - - /** - * The default {@link Predicate} implementation of {@link HeartbeatEvent} based on the comparison between - * previous and current {@link HeartbeatEvent#getValue() state value}, the {@link DiscoveryClient} - * implementation may override current. - * - * @return {@link Predicate} - * @see EurekaConfiguration#heartbeatEventChangedPredicate() - */ - @Bean - @ConditionalOnMissingBean - public Predicate defaultHeartbeatEventChangePredicate() { - return event -> { - Object oldState = heartbeatState.get(); - Object newState = event.getValue(); - return heartbeatState.compareAndSet(oldState, newState) && !Objects.equals(oldState, newState); - }; - } - - - /** - * Eureka Customized Configuration - */ - @Configuration - @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) - public class EurekaConfiguration { - - private final AtomicReference appsHashCodeCache = new AtomicReference<>(); - - /** - * Compare {@link Applications#getAppsHashCode() apps hash code} between last {@link Applications} and current. - * - * @see Applications#getAppsHashCode() - */ - @Bean - public Predicate heartbeatEventChangedPredicate() { - return event -> { - String oldAppsHashCode = appsHashCodeCache.get(); - CloudEurekaClient cloudEurekaClient = (CloudEurekaClient) event.getSource(); - Applications applications = cloudEurekaClient.getApplications(); - String appsHashCode = applications.getAppsHashCode(); - return appsHashCodeCache.compareAndSet(oldAppsHashCode, appsHashCode) && - !Objects.equals(oldAppsHashCode, appsHashCode); - }; - } - } - - /** - * Zookeeper Customized Configuration - */ - @Configuration - @ConditionalOnBean(name = ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) - @Aspect - public class ZookeeperConfiguration implements ApplicationListener { - /** - * The pointcut expression for {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} - */ - public static final String CHILD_EVENT_POINTCUT_EXPRESSION = - "execution(void org.springframework.cloud.zookeeper.discovery.ZookeeperServiceWatch.childEvent(..)) && args(client,event)"; - - /** - * The path separator of Zookeeper node - */ - public static final String NODE_PATH_SEPARATOR = "/"; - - /** - * The path variable name for the name of service - */ - private static final String SERVICE_NAME_PATH_VARIABLE_NAME = "serviceName"; - - /** - * The path variable name for the id of {@link ServiceInstance service instance} - */ - private static final String SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME = "serviceInstanceId"; - - private final ZookeeperServiceWatch zookeeperServiceWatch; - - private final String rootPath; - - private final AntPathMatcher pathMatcher; - - /** - * Ant Path pattern for {@link ServiceInstance} : - *

- *

- * ${{@link #rootPath}}/{serviceName}/{serviceInstanceId} - * - * @see #rootPath - * @see #SERVICE_NAME_PATH_VARIABLE_NAME - * @see #SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME - */ - private final String serviceInstancePathPattern; - - /** - * The {@link ThreadLocal} holds the processed service name - */ - private final ThreadLocal processedServiceNameThreadLocal; - - ZookeeperConfiguration( - ZookeeperDiscoveryProperties zookeeperDiscoveryProperties, - ZookeeperServiceWatch zookeeperServiceWatch) { - this.zookeeperServiceWatch = zookeeperServiceWatch; - this.rootPath = zookeeperDiscoveryProperties.getRoot(); - this.pathMatcher = new AntPathMatcher(NODE_PATH_SEPARATOR); - this.serviceInstancePathPattern = rootPath + - NODE_PATH_SEPARATOR + "{" + SERVICE_NAME_PATH_VARIABLE_NAME + "}" + - NODE_PATH_SEPARATOR + "{" + SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME + "}"; - this.processedServiceNameThreadLocal = new ThreadLocal<>(); - } - - /** - * Zookeeper uses {@link TreeCacheEvent} to trigger {@link #dispatchServiceInstancesChangedEvent(String, Collection)} - * , thus {@link HeartbeatEvent} handle is always ignored - * - * @return false forever - */ - @Bean - public Predicate heartbeatEventChangedPredicate() { - return event -> false; - } - - /** - * Handle on {@link InstanceRegisteredEvent} after - * {@link ZookeeperServiceWatch#onApplicationEvent(InstanceRegisteredEvent)} - * - * @param event {@link InstanceRegisteredEvent} - * @see #reattachTreeCacheListeners() - */ - @Override - public void onApplicationEvent(InstanceRegisteredEvent event) { - reattachTreeCacheListeners(); - } - - /** - * Re-attach the {@link TreeCacheListener TreeCacheListeners} - */ - private void reattachTreeCacheListeners() { - - TreeCache treeCache = zookeeperServiceWatch.getCache(); - - Listenable listenable = treeCache.getListenable(); - - /** - * All registered TreeCacheListeners except {@link ZookeeperServiceWatch}. - * Usually, "otherListeners" will be empty because Spring Cloud Zookeeper only adds - * "zookeeperServiceWatch" bean as {@link TreeCacheListener} - */ - List otherListeners = new LinkedList<>(); - - if (listenable instanceof ListenerContainer) { - ListenerContainer listenerContainer = (ListenerContainer) listenable; - listenerContainer.forEach(listener -> { - /** - * Even though "listener" is an instance of {@link ZookeeperServiceWatch}, - * "zookeeperServiceWatch" bean that was enhanced by AOP is different from the former, - * thus it's required to exclude "listener" - */ - if (!(listener instanceof ZookeeperServiceWatch)) { - otherListeners.add(listener); - } - return null; - }); - - // remove all TreeCacheListeners temporarily - listenerContainer.clear(); - // re-store zookeeperServiceWatch, and make sure it's first one - // now "beforeChildEvent" is available for Spring AOP - listenerContainer.addListener(zookeeperServiceWatch); - // re-store others - otherListeners.forEach(listenerContainer::addListener); - } else { - if (logger.isWarnEnabled()) { - logger.warn("Tell me which version Curator framework current application used? I will do better :D"); - } - } - } - - /** - * Try to {@link #dispatchServiceInstancesChangedEvent(String, Collection) dispatch} - * {@link ServiceInstancesChangedEvent} before {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} - * execution if required - * - * @param client {@link CuratorFramework} - * @param event {@link TreeCacheEvent} - */ - @Before(CHILD_EVENT_POINTCUT_EXPRESSION) - public void beforeChildEvent(CuratorFramework client, TreeCacheEvent event) { - if (supportsEventType(event)) { - String serviceName = resolveServiceName(event); - if (hasText(serviceName)) { - dispatchServiceInstancesChangedEvent(serviceName, getInstances(serviceName)); - } - } - } - - @After(CHILD_EVENT_POINTCUT_EXPRESSION) - public void afterChildEvent(CuratorFramework client, TreeCacheEvent event) { - } - - /** - * Resolve the name of service - * - * @param event {@link TreeCacheEvent} - * @return If the Zookeeper's {@link ChildData#getPath() node path} that was notified comes from - * {@link ServiceInstance the service instance}, return it's parent path as the service name, - * or return null - */ - private String resolveServiceName(TreeCacheEvent event) { - ChildData childData = event.getData(); - String path = childData.getPath(); - if (logger.isDebugEnabled()) { - logger.debug("ZK node[path : {}] event type : {}", path, event.getType()); - } - - String serviceName = null; - - if (pathMatcher.match(serviceInstancePathPattern, path)) { - Map variables = pathMatcher.extractUriTemplateVariables(serviceInstancePathPattern, path); - serviceName = variables.get(SERVICE_NAME_PATH_VARIABLE_NAME); - } - - return serviceName; - } - - /** - * The {@link TreeCacheEvent#getType() event type} is supported or not - * - * @param event {@link TreeCacheEvent} - * @return the rule is same as {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} method - */ - private boolean supportsEventType(TreeCacheEvent event) { - TreeCacheEvent.Type eventType = event.getType(); - return eventType.equals(TreeCacheEvent.Type.NODE_ADDED) - || eventType.equals(TreeCacheEvent.Type.NODE_REMOVED) - || eventType.equals(TreeCacheEvent.Type.NODE_UPDATED); - } - } - - /** - * Consul Customized Configuration - */ - @Configuration - @ConditionalOnBean(name = CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) - class ConsulConfiguration { - - } - - /** - * Nacos Customized Configuration - */ - @Configuration - @ConditionalOnBean(name = NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) - class NacosConfiguration { - - private final NamingService namingService; - - /** - * the set of services is listening - */ - private final Set listeningServices; - - NacosConfiguration(NacosDiscoveryProperties nacosDiscoveryProperties) { - this.namingService = nacosDiscoveryProperties.namingServiceInstance(); - this.listeningServices = new ConcurrentSkipListSet<>(); - } - - /** - * Nacos uses {@link EventListener} to trigger {@link #dispatchServiceInstancesChangedEvent(String, Collection)} - * , thus {@link HeartbeatEvent} handle is always ignored - * - * @return false forever - */ - @Bean - public Predicate heartbeatEventChangedPredicate() { - return event -> false; - } - - @EventListener(SubscribedServicesChangedEvent.class) - public void onSubscribedServicesChangedEvent(SubscribedServicesChangedEvent event) throws Exception { - // subscribe EventListener for each service - event.getNewSubscribedServices().forEach(this::subscribeEventListener); - } - - private void subscribeEventListener(String serviceName) { - if (listeningServices.add(serviceName)) { - try { - namingService.subscribe(serviceName, event -> { - if (event instanceof NamingEvent) { - NamingEvent namingEvent = (NamingEvent) event; - List serviceInstances = hostToServiceInstanceList(namingEvent.getInstances(), serviceName); - dispatchServiceInstancesChangedEvent(serviceName, serviceInstances); - } - }); - } catch (NacosException e) { - ReflectionUtils.rethrowRuntimeException(e); - } - } - } - } + public static final String ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryAutoConfiguration"; + + public static final String CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration"; + + public static final String NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration"; + + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ApplicationEventPublisher applicationEventPublisher; + + private final DiscoveryClient discoveryClient; + + private final AtomicReference heartbeatState = new AtomicReference<>(); + + /** + * @see #defaultHeartbeatEventChangePredicate() + */ + private final ObjectProvider> heartbeatEventChangedPredicate; + + public DubboServiceDiscoveryAutoConfiguration( + DubboServiceMetadataRepository dubboServiceMetadataRepository, + ApplicationEventPublisher applicationEventPublisher, + DiscoveryClient discoveryClient, + ObjectProvider> heartbeatEventChangedPredicate) { + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + this.applicationEventPublisher = applicationEventPublisher; + this.discoveryClient = discoveryClient; + this.heartbeatEventChangedPredicate = heartbeatEventChangedPredicate; + } + + /** + * Dispatch a {@link ServiceInstancesChangedEvent} + * + * @param serviceName the name of service + * @param serviceInstances the {@link ServiceInstance instances} of some service + * @see AbstractSpringCloudRegistry#registerServiceInstancesChangedEventListener(URL, + * NotifyListener) + */ + private void dispatchServiceInstancesChangedEvent(String serviceName, + Collection serviceInstances) { + if (!hasText(serviceName) || serviceInstances == null) { + return; + } + ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(serviceName, + serviceInstances); + if (logger.isInfoEnabled()) { + logger.info( + "The event of the service instances[name : {} , size : {}] change is about to be dispatched", + serviceName, serviceInstances.size()); + } + applicationEventPublisher.publishEvent(event); + } + + private List getInstances(String serviceName) { + return discoveryClient.getInstances(serviceName); + } + + /** + * Dispatch a {@link ServiceInstancesChangedEvent} when the {@link HeartbeatEvent} + * raised, use for these scenarios: + *
    + *
  • Eureka : {@link CloudEurekaClient#onCacheRefreshed()} publishes a + * {@link HeartbeatEvent} instead of {@link CacheRefreshedEvent}
  • + *
  • Zookeeper : + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + * publishes a {@link HeartbeatEvent} when + * {@link ZookeeperDiscoveryProperties#getRoot() the services' root path} has been + * changed
  • + *
  • Consul : {@link ConsulCatalogWatch#catalogServicesWatch()} publishes a + * {@link HeartbeatEvent} when + * Consul's Blocking + * Queries response
  • + *
  • Nacos : {@link NacosWatch#nacosServicesWatch()} publishes a + * {@link HeartbeatEvent} under a {@link TaskScheduler} every + * {@link NacosDiscoveryProperties#getWatchDelay()} milliseconds
  • + *
+ *

+ * In order to reduce the duplicated handling for + * {@link ServiceInstancesChangedEvent}, + * {@link #defaultHeartbeatEventChangePredicate()} method providers the default + * implementation to detect whether the {@link HeartbeatEvent#getValue() state} is + * changed or not. If and only if changed, the + * {@link #dispatchServiceInstancesChangedEvent(String, Collection)} will be executed. + *

+ * Note : Spring Cloud {@link HeartbeatEvent} has a critical flaw that can't + * figure out which service was changed precisely, it's just used for a notification + * that the {@link DubboServiceMetadataRepository#getSubscribedServices() subscribed + * services} used to {@link NotifyListener#notify(List) notify} the Dubbo consumer + * cached {@link URL URLs}. Because of some {@link DiscoveryClient} implementations + * have the better and fine-grained the event mechanism for service instances change, + * thus {@link HeartbeatEvent} handle will be ignored in these scenarios: + *

    + *
  • Zookeeper : {@link Watcher}, see + * {@link ZookeeperConfiguration#heartbeatEventChangedPredicate()}
  • + *
  • Nacos : {@link com.alibaba.nacos.api.naming.listener.EventListener} , see + * {@link NacosConfiguration#heartbeatEventChangedPredicate()}
  • + *
+ *

+ * If the customized {@link DiscoveryClient} also providers the similar mechanism, the + * implementation could declare a Spring Bean of {@link Predicate} of + * {@link HeartbeatEvent} to override {@link #defaultHeartbeatEventChangePredicate() + * default one}. + * + * @param event the instance of {@link HeartbeatEvent} + * @see HeartbeatEvent + */ + @EventListener(HeartbeatEvent.class) + public void onHeartbeatEvent(HeartbeatEvent event) { + /** + * Try to re-initialize the subscribed services, in order to sense the change of + * services if {@link DubboCloudProperties#getSubscribedServices()} is wildcard + * that indicates all services should be subscribed. + */ + Stream subscribedServices = dubboServiceMetadataRepository + .initSubscribedServices(); + + heartbeatEventChangedPredicate.ifAvailable(predicate -> { + if (predicate.test(event)) { + // Dispatch ServiceInstancesChangedEvent for each service + subscribedServices.forEach(serviceName -> { + List serviceInstances = getInstances(serviceName); + dispatchServiceInstancesChangedEvent(serviceName, serviceInstances); + }); + } + }); + } + + /** + * The default {@link Predicate} implementation of {@link HeartbeatEvent} based on the + * comparison between previous and current {@link HeartbeatEvent#getValue() state + * value}, the {@link DiscoveryClient} implementation may override current. + * + * @return {@link Predicate} + * @see EurekaConfiguration#heartbeatEventChangedPredicate() + */ + @Bean + @ConditionalOnMissingBean + public Predicate defaultHeartbeatEventChangePredicate() { + return event -> { + Object oldState = heartbeatState.get(); + Object newState = event.getValue(); + return heartbeatState.compareAndSet(oldState, newState) + && !Objects.equals(oldState, newState); + }; + } + + /** + * Eureka Customized Configuration + */ + @Configuration + @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) + public class EurekaConfiguration { + + private final AtomicReference appsHashCodeCache = new AtomicReference<>(); + + /** + * Compare {@link Applications#getAppsHashCode() apps hash code} between last + * {@link Applications} and current. + * + * @see Applications#getAppsHashCode() + */ + @Bean + public Predicate heartbeatEventChangedPredicate() { + return event -> { + String oldAppsHashCode = appsHashCodeCache.get(); + CloudEurekaClient cloudEurekaClient = (CloudEurekaClient) event + .getSource(); + Applications applications = cloudEurekaClient.getApplications(); + String appsHashCode = applications.getAppsHashCode(); + return appsHashCodeCache.compareAndSet(oldAppsHashCode, appsHashCode) + && !Objects.equals(oldAppsHashCode, appsHashCode); + }; + } + } + + /** + * Zookeeper Customized Configuration + */ + @Configuration + @ConditionalOnBean(name = ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + @Aspect + public class ZookeeperConfiguration + implements ApplicationListener { + /** + * The pointcut expression for + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + */ + public static final String CHILD_EVENT_POINTCUT_EXPRESSION = "execution(void org.springframework.cloud.zookeeper.discovery.ZookeeperServiceWatch.childEvent(..)) && args(client,event)"; + + /** + * The path separator of Zookeeper node + */ + public static final String NODE_PATH_SEPARATOR = "/"; + + /** + * The path variable name for the name of service + */ + private static final String SERVICE_NAME_PATH_VARIABLE_NAME = "serviceName"; + + /** + * The path variable name for the id of {@link ServiceInstance service instance} + */ + private static final String SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME = "serviceInstanceId"; + + private final ZookeeperServiceWatch zookeeperServiceWatch; + + private final String rootPath; + + private final AntPathMatcher pathMatcher; + + /** + * Ant Path pattern for {@link ServiceInstance} : + *

+ *

+ * ${{@link #rootPath}}/{serviceName}/{serviceInstanceId} + * + * @see #rootPath + * @see #SERVICE_NAME_PATH_VARIABLE_NAME + * @see #SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME + */ + private final String serviceInstancePathPattern; + + /** + * The {@link ThreadLocal} holds the processed service name + */ + private final ThreadLocal processedServiceNameThreadLocal; + + ZookeeperConfiguration(ZookeeperDiscoveryProperties zookeeperDiscoveryProperties, + ZookeeperServiceWatch zookeeperServiceWatch) { + this.zookeeperServiceWatch = zookeeperServiceWatch; + this.rootPath = zookeeperDiscoveryProperties.getRoot(); + this.pathMatcher = new AntPathMatcher(NODE_PATH_SEPARATOR); + this.serviceInstancePathPattern = rootPath + NODE_PATH_SEPARATOR + "{" + + SERVICE_NAME_PATH_VARIABLE_NAME + "}" + NODE_PATH_SEPARATOR + "{" + + SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME + "}"; + this.processedServiceNameThreadLocal = new ThreadLocal<>(); + } + + /** + * Zookeeper uses {@link TreeCacheEvent} to trigger + * {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus + * {@link HeartbeatEvent} handle is always ignored + * + * @return false forever + */ + @Bean + public Predicate heartbeatEventChangedPredicate() { + return event -> false; + } + + /** + * Handle on {@link InstanceRegisteredEvent} after + * {@link ZookeeperServiceWatch#onApplicationEvent(InstanceRegisteredEvent)} + * + * @param event {@link InstanceRegisteredEvent} + * @see #reattachTreeCacheListeners() + */ + @Override + public void onApplicationEvent(InstanceRegisteredEvent event) { + reattachTreeCacheListeners(); + } + + /** + * Re-attach the {@link TreeCacheListener TreeCacheListeners} + */ + private void reattachTreeCacheListeners() { + + TreeCache treeCache = zookeeperServiceWatch.getCache(); + + Listenable listenable = treeCache.getListenable(); + + /** + * All registered TreeCacheListeners except {@link ZookeeperServiceWatch}. + * Usually, "otherListeners" will be empty because Spring Cloud Zookeeper only + * adds "zookeeperServiceWatch" bean as {@link TreeCacheListener} + */ + List otherListeners = new LinkedList<>(); + + if (listenable instanceof ListenerContainer) { + ListenerContainer listenerContainer = (ListenerContainer) listenable; + listenerContainer.forEach(listener -> { + /** + * Even though "listener" is an instance of + * {@link ZookeeperServiceWatch}, "zookeeperServiceWatch" bean that + * was enhanced by AOP is different from the former, thus it's + * required to exclude "listener" + */ + if (!(listener instanceof ZookeeperServiceWatch)) { + otherListeners.add(listener); + } + return null; + }); + + // remove all TreeCacheListeners temporarily + listenerContainer.clear(); + // re-store zookeeperServiceWatch, and make sure it's first one + // now "beforeChildEvent" is available for Spring AOP + listenerContainer.addListener(zookeeperServiceWatch); + // re-store others + otherListeners.forEach(listenerContainer::addListener); + } + else { + if (logger.isWarnEnabled()) { + logger.warn( + "Tell me which version Curator framework current application used? I will do better :D"); + } + } + } + + /** + * Try to {@link #dispatchServiceInstancesChangedEvent(String, Collection) + * dispatch} {@link ServiceInstancesChangedEvent} before + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + * execution if required + * + * @param client {@link CuratorFramework} + * @param event {@link TreeCacheEvent} + */ + @Before(CHILD_EVENT_POINTCUT_EXPRESSION) + public void beforeChildEvent(CuratorFramework client, TreeCacheEvent event) { + if (supportsEventType(event)) { + String serviceName = resolveServiceName(event); + if (hasText(serviceName)) { + dispatchServiceInstancesChangedEvent(serviceName, + getInstances(serviceName)); + } + } + } + + @After(CHILD_EVENT_POINTCUT_EXPRESSION) + public void afterChildEvent(CuratorFramework client, TreeCacheEvent event) { + } + + /** + * Resolve the name of service + * + * @param event {@link TreeCacheEvent} + * @return If the Zookeeper's {@link ChildData#getPath() node path} that was + * notified comes from {@link ServiceInstance the service instance}, return it's + * parent path as the service name, or return null + */ + private String resolveServiceName(TreeCacheEvent event) { + ChildData childData = event.getData(); + String path = childData.getPath(); + if (logger.isDebugEnabled()) { + logger.debug("ZK node[path : {}] event type : {}", path, event.getType()); + } + + String serviceName = null; + + if (pathMatcher.match(serviceInstancePathPattern, path)) { + Map variables = pathMatcher + .extractUriTemplateVariables(serviceInstancePathPattern, path); + serviceName = variables.get(SERVICE_NAME_PATH_VARIABLE_NAME); + } + + return serviceName; + } + + /** + * The {@link TreeCacheEvent#getType() event type} is supported or not + * + * @param event {@link TreeCacheEvent} + * @return the rule is same as + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + * method + */ + private boolean supportsEventType(TreeCacheEvent event) { + TreeCacheEvent.Type eventType = event.getType(); + return eventType.equals(TreeCacheEvent.Type.NODE_ADDED) + || eventType.equals(TreeCacheEvent.Type.NODE_REMOVED) + || eventType.equals(TreeCacheEvent.Type.NODE_UPDATED); + } + } + + /** + * Consul Customized Configuration + */ + @Configuration + @ConditionalOnBean(name = CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + class ConsulConfiguration { + + } + + /** + * Nacos Customized Configuration + */ + @Configuration + @ConditionalOnBean(name = NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + class NacosConfiguration { + + private final NamingService namingService; + + /** + * the set of services is listening + */ + private final Set listeningServices; + + NacosConfiguration(NacosDiscoveryProperties nacosDiscoveryProperties) { + this.namingService = nacosDiscoveryProperties.namingServiceInstance(); + this.listeningServices = new ConcurrentSkipListSet<>(); + } + + /** + * Nacos uses {@link EventListener} to trigger + * {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus + * {@link HeartbeatEvent} handle is always ignored + * + * @return false forever + */ + @Bean + public Predicate heartbeatEventChangedPredicate() { + return event -> false; + } + + @EventListener(SubscribedServicesChangedEvent.class) + public void onSubscribedServicesChangedEvent(SubscribedServicesChangedEvent event) + throws Exception { + // subscribe EventListener for each service + event.getNewSubscribedServices().forEach(this::subscribeEventListener); + } + + private void subscribeEventListener(String serviceName) { + if (listeningServices.add(serviceName)) { + try { + namingService.subscribe(serviceName, event -> { + if (event instanceof NamingEvent) { + NamingEvent namingEvent = (NamingEvent) event; + List serviceInstances = hostToServiceInstanceList( + namingEvent.getInstances(), serviceName); + dispatchServiceInstancesChangedEvent(serviceName, + serviceInstances); + } + }); + } + catch (NacosException e) { + ReflectionUtils.rethrowRuntimeException(e); + } + } + } + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index b9cce47a5..6031edce2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -16,15 +16,19 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS; +import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL; +import static org.springframework.util.ObjectUtils.isEmpty; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ServiceBean; -import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; -import com.ecwid.consul.v1.agent.model.NewService; -import com.netflix.appinfo.InstanceInfo; import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,15 +53,12 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS; -import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL; -import static org.springframework.util.ObjectUtils.isEmpty; +import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; +import com.ecwid.consul.v1.agent.model.NewService; +import com.netflix.appinfo.InstanceInfo; /** * Dubbo Service Registration Auto-{@link Configuration} @@ -65,125 +66,126 @@ import static org.springframework.util.ObjectUtils.isEmpty; * @author Mercy */ @Configuration -@Import({DubboServiceRegistrationEventPublishingAspect.class}) +@Import({ DubboServiceRegistrationEventPublishingAspect.class }) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureAfter(name = { - EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, - CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME, - "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" -}, value = { - DubboMetadataAutoConfiguration.class -}) +@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME, + "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" }, value = { + DubboMetadataAutoConfiguration.class }) public class DubboServiceRegistrationAutoConfiguration { - public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = - "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"; - - public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = - "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; - - public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = - "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; - - public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = - "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration"; - - private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class); - - @Autowired - private DubboServiceMetadataRepository dubboServiceMetadataRepository; - - @Bean - @Conditional(value = { - MissingSpringCloudRegistryConfigPropertyCondition.class - }) - public RegistryConfig defaultSpringCloudRegistryConfig() { - return new RegistryConfig(ADDRESS, PROTOCOL); - } - - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - Registration registration = event.getSource(); - attachDubboMetadataServiceMetadata(registration); - } - - private void attachDubboMetadataServiceMetadata(Registration registration) { - if (registration == null) { - return; - } - synchronized (registration) { - Map metadata = registration.getMetadata(); - attachDubboMetadataServiceMetadata(metadata); - } - } - - private void attachDubboMetadataServiceMetadata(Map metadata) { - Map serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata(); - if (!isEmpty(serviceMetadata)) { - metadata.putAll(serviceMetadata); - } - } - - @Configuration - @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) - @Aspect - class EurekaConfiguration implements SmartInitializingSingleton { - - @Autowired - private ObjectProvider> serviceBeans; - - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - Registration registration = event.getSource(); - EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration); - InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo(); - attachDubboMetadataServiceMetadata(instanceInfo.getMetadata()); - } - - /** - * {@link EurekaServiceRegistry} will register current {@link ServiceInstance service instance} on - * {@link EurekaAutoServiceRegistration#start()} execution(in {@link SmartLifecycle#start() start phase}), - * thus this method must {@link ServiceBean#export() export} all {@link ServiceBean ServiceBeans} in advance. - */ - @Override - public void afterSingletonsInstantiated() { - Collection serviceBeans = this.serviceBeans.getIfAvailable(); - if (!isEmpty(serviceBeans)) { - serviceBeans.forEach(ServiceBean::export); - } - } - } - - @Configuration - @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) - @AutoConfigureOrder - class ConsulConfiguration { - - /** - * Handle the pre-registered event of {@link ServiceInstance} for Consul - * - * @param event {@link ServiceInstancePreRegisteredEvent} - */ - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - Registration registration = event.getSource(); - Class registrationClass = AopUtils.getTargetClass(registration); - String registrationClassName = registrationClass.getName(); - if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { - ConsulRegistration consulRegistration = (ConsulRegistration) registration; - attachURLsIntoMetadata(consulRegistration); - } - } - - private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) { - NewService newService = consulRegistration.getService(); - Map serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata(); - if (!isEmpty(serviceMetadata)) { - List tags = newService.getTags(); - for (Map.Entry entry : serviceMetadata.entrySet()) { - tags.add(entry.getKey() + "=" + entry.getValue()); - } - } - } - } + public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"; + + public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; + + public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; + + public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration"; + + private static final Logger logger = LoggerFactory + .getLogger(DubboServiceRegistrationAutoConfiguration.class); + + @Autowired + private DubboServiceMetadataRepository dubboServiceMetadataRepository; + + @Bean + @Conditional(value = { MissingSpringCloudRegistryConfigPropertyCondition.class }) + public RegistryConfig defaultSpringCloudRegistryConfig() { + return new RegistryConfig(ADDRESS, PROTOCOL); + } + + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + attachDubboMetadataServiceMetadata(registration); + } + + private void attachDubboMetadataServiceMetadata(Registration registration) { + if (registration == null) { + return; + } + synchronized (registration) { + Map metadata = registration.getMetadata(); + attachDubboMetadataServiceMetadata(metadata); + } + } + + private void attachDubboMetadataServiceMetadata(Map metadata) { + Map serviceMetadata = dubboServiceMetadataRepository + .getDubboMetadataServiceMetadata(); + if (!isEmpty(serviceMetadata)) { + metadata.putAll(serviceMetadata); + } + } + + @Configuration + @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) + @Aspect + class EurekaConfiguration implements SmartInitializingSingleton { + + @Autowired + private ObjectProvider> serviceBeans; + + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered( + ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + EurekaRegistration eurekaRegistration = EurekaRegistration.class + .cast(registration); + InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager() + .getInfo(); + attachDubboMetadataServiceMetadata(instanceInfo.getMetadata()); + } + + /** + * {@link EurekaServiceRegistry} will register current {@link ServiceInstance + * service instance} on {@link EurekaAutoServiceRegistration#start()} execution(in + * {@link SmartLifecycle#start() start phase}), thus this method must + * {@link ServiceBean#export() export} all {@link ServiceBean ServiceBeans} in + * advance. + */ + @Override + public void afterSingletonsInstantiated() { + Collection serviceBeans = this.serviceBeans.getIfAvailable(); + if (!isEmpty(serviceBeans)) { + serviceBeans.forEach(ServiceBean::export); + } + } + } + + @Configuration + @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) + @AutoConfigureOrder + class ConsulConfiguration { + + /** + * Handle the pre-registered event of {@link ServiceInstance} for Consul + * + * @param event {@link ServiceInstancePreRegisteredEvent} + */ + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered( + ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + Class registrationClass = AopUtils.getTargetClass(registration); + String registrationClassName = registrationClass.getName(); + if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME + .equalsIgnoreCase(registrationClassName)) { + ConsulRegistration consulRegistration = (ConsulRegistration) registration; + attachURLsIntoMetadata(consulRegistration); + } + } + + private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) { + NewService newService = consulRegistration.getService(); + Map serviceMetadata = dubboServiceMetadataRepository + .getDubboMetadataServiceMetadata(); + if (!isEmpty(serviceMetadata)) { + List tags = newService.getTags(); + for (Map.Entry entry : serviceMetadata.entrySet()) { + tags.add(entry.getKey() + "=" + entry.getValue()); + } + } + } + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java index 34d743935..9c8e209c2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java @@ -16,12 +16,14 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; + +import java.util.List; + import org.apache.dubbo.common.URL; import org.apache.dubbo.config.spring.ServiceBean; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; -import com.ecwid.consul.v1.agent.model.NewService; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -41,10 +43,9 @@ import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegist import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; -import java.util.List; - -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; +import com.ecwid.consul.v1.agent.model.NewService; /** * Dubbo Service Registration Auto-{@link Configuration} for Non-Web application @@ -58,111 +59,113 @@ import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAuto @Aspect public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { - private static final String REST_PROTOCOL = "rest"; - - @Autowired - private ServiceRegistry serviceRegistry; - - @Autowired - private Registration registration; - - private volatile Integer serverPort = null; - - private volatile boolean registered = false; - - @Autowired - private DubboServiceMetadataRepository repository; - - @Around("execution(* org.springframework.cloud.client.serviceregistry.Registration.getPort())") - public Object getPort(ProceedingJoinPoint pjp) throws Throwable { - return serverPort != null ? serverPort : pjp.proceed(); - } - - @EventListener(ApplicationStartedEvent.class) - public void onApplicationStarted() { - setServerPort(); - register(); - } - - private void register() { - if (registered) { - return; - } - serviceRegistry.register(registration); - registered = true; - } - - /** - * Set web port from {@link ServiceBean#getExportedUrls() exported URLs} if "rest" protocol is present. - */ - private void setServerPort() { - if (serverPort == null) { - for (List urls : repository.getAllExportedUrls().values()) { - urls.stream() - .filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol())) - .findFirst() - .ifPresent(url -> { - serverPort = url.getPort(); - }); - - // If REST protocol is not present, use any applied port. - if (serverPort == null) { - urls.stream() - .findAny().ifPresent(url -> { - serverPort = url.getPort(); - }); - } - } - } - } - - @Configuration - @ConditionalOnBean(name = ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) - class ZookeeperConfiguration implements SmartInitializingSingleton { - - @Autowired - private ServiceInstanceRegistration registration; - - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - registration.setPort(serverPort); - } - - @Override - public void afterSingletonsInstantiated() { - // invoke getServiceInstance() method to trigger the ServiceInstance building before register - registration.getServiceInstance(); - } - } - - @Configuration - @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) - class ConsulConfiguration { - - /** - * Handle the pre-registered event of {@link ServiceInstance} for Consul - * - * @param event {@link ServiceInstancePreRegisteredEvent} - */ - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - Registration registration = event.getSource(); - ConsulAutoRegistration consulRegistration = (ConsulAutoRegistration) registration; - setPort(consulRegistration); - } - - /** - * Set port on Non-Web Application - * - * @param consulRegistration {@link ConsulRegistration} - */ - private void setPort(ConsulAutoRegistration consulRegistration) { - int port = consulRegistration.getPort(); - NewService newService = consulRegistration.getService(); - if (newService.getPort() == null) { - newService.setPort(port); - } - } - } + private static final String REST_PROTOCOL = "rest"; + + @Autowired + private ServiceRegistry serviceRegistry; + + @Autowired + private Registration registration; + + private volatile Integer serverPort = null; + + private volatile boolean registered = false; + + @Autowired + private DubboServiceMetadataRepository repository; + + @Around("execution(* org.springframework.cloud.client.serviceregistry.Registration.getPort())") + public Object getPort(ProceedingJoinPoint pjp) throws Throwable { + return serverPort != null ? serverPort : pjp.proceed(); + } + + @EventListener(ApplicationStartedEvent.class) + public void onApplicationStarted() { + setServerPort(); + register(); + } + + private void register() { + if (registered) { + return; + } + serviceRegistry.register(registration); + registered = true; + } + + /** + * Set web port from {@link ServiceBean#getExportedUrls() exported URLs} if "rest" + * protocol is present. + */ + private void setServerPort() { + if (serverPort == null) { + for (List urls : repository.getAllExportedUrls().values()) { + urls.stream() + .filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol())) + .findFirst().ifPresent(url -> { + serverPort = url.getPort(); + }); + + // If REST protocol is not present, use any applied port. + if (serverPort == null) { + urls.stream().findAny().ifPresent(url -> { + serverPort = url.getPort(); + }); + } + } + } + } + + @Configuration + @ConditionalOnBean(name = ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) + class ZookeeperConfiguration implements SmartInitializingSingleton { + + @Autowired + private ServiceInstanceRegistration registration; + + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered( + ServiceInstancePreRegisteredEvent event) { + registration.setPort(serverPort); + } + + @Override + public void afterSingletonsInstantiated() { + // invoke getServiceInstance() method to trigger the ServiceInstance building + // before register + registration.getServiceInstance(); + } + } + + @Configuration + @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) + class ConsulConfiguration { + + /** + * Handle the pre-registered event of {@link ServiceInstance} for Consul + * + * @param event {@link ServiceInstancePreRegisteredEvent} + */ + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered( + ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + ConsulAutoRegistration consulRegistration = (ConsulAutoRegistration) registration; + setPort(consulRegistration); + } + + /** + * Set port on Non-Web Application + * + * @param consulRegistration {@link ConsulRegistration} + */ + private void setPort(ConsulAutoRegistration consulRegistration) { + int port = consulRegistration.getPort(); + NewService newService = consulRegistration.getService(); + if (newService.getPort() == null) { + newService.setPort(port); + } + } + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java index 1fe77da03..3aa14cd73 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java @@ -16,7 +16,11 @@ */ package com.alibaba.cloud.dubbo.autoconfigure.condition; -import com.alibaba.cloud.dubbo.registry.SpringCloudRegistry; +import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL; +import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; + +import java.util.Map; + import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.context.annotation.Condition; @@ -25,10 +29,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.StringUtils; -import java.util.Map; - -import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL; -import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; +import com.alibaba.cloud.dubbo.registry.SpringCloudRegistry; /** * Missing {@link SpringCloudRegistry} Property {@link Condition} @@ -37,35 +38,43 @@ import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubPro * @see SpringCloudRegistry * @see Condition */ -public class MissingSpringCloudRegistryConfigPropertyCondition extends SpringBootCondition { - +public class MissingSpringCloudRegistryConfigPropertyCondition + extends SpringBootCondition { - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment(); + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + ConfigurableEnvironment environment = (ConfigurableEnvironment) context + .getEnvironment(); - String protocol = environment.getProperty("dubbo.registry.protocol"); + String protocol = environment.getProperty("dubbo.registry.protocol"); - if (PROTOCOL.equals(protocol)) { - return ConditionOutcome.noMatch("'spring-cloud' protocol was found from 'dubbo.registry.protocol'"); - } + if (PROTOCOL.equals(protocol)) { + return ConditionOutcome.noMatch( + "'spring-cloud' protocol was found from 'dubbo.registry.protocol'"); + } - String address = environment.getProperty("dubbo.registry.address"); + String address = environment.getProperty("dubbo.registry.address"); - if (StringUtils.startsWithIgnoreCase(address, PROTOCOL)) { - return ConditionOutcome.noMatch("'spring-cloud' protocol was found from 'dubbo.registry.address'"); - } + if (StringUtils.startsWithIgnoreCase(address, PROTOCOL)) { + return ConditionOutcome.noMatch( + "'spring-cloud' protocol was found from 'dubbo.registry.address'"); + } - Map properties = getSubProperties(environment, "dubbo.registries."); + Map properties = getSubProperties(environment, + "dubbo.registries."); - boolean found = properties.entrySet().stream().anyMatch(entry -> { - String key = entry.getKey(); - String value = String.valueOf(entry.getValue()); - return (key.endsWith(".address") && value.startsWith(PROTOCOL)) || - (key.endsWith(".protocol") && PROTOCOL.equals(value)); + boolean found = properties.entrySet().stream().anyMatch(entry -> { + String key = entry.getKey(); + String value = String.valueOf(entry.getValue()); + return (key.endsWith(".address") && value.startsWith(PROTOCOL)) + || (key.endsWith(".protocol") && PROTOCOL.equals(value)); - }); + }); - return found ? ConditionOutcome.noMatch("'spring-cloud' protocol was found in 'dubbo.registries.*'") : ConditionOutcome.match(); - } + return found + ? ConditionOutcome.noMatch( + "'spring-cloud' protocol was found in 'dubbo.registries.*'") + : ConditionOutcome.match(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java index ef02aa989..27fc1c943 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java @@ -16,15 +16,15 @@ */ package com.alibaba.cloud.dubbo.client.loadbalancer; +import java.io.IOException; +import java.io.InputStream; + import org.apache.dubbo.rpc.service.GenericException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; -import java.io.IOException; -import java.io.InputStream; - /** * Dubbo {@link ClientHttpResponse} implementation * @@ -33,47 +33,50 @@ import java.io.InputStream; */ class DubboClientHttpResponse implements ClientHttpResponse { - private final HttpStatus httpStatus; + private final HttpStatus httpStatus; - private final String statusText; + private final String statusText; - private final HttpHeaders httpHeaders = new HttpHeaders(); + private final HttpHeaders httpHeaders = new HttpHeaders(); - private final DubboHttpOutputMessage httpOutputMessage; + private final DubboHttpOutputMessage httpOutputMessage; - public DubboClientHttpResponse(DubboHttpOutputMessage httpOutputMessage, GenericException exception) { - this.httpStatus = exception != null ? HttpStatus.INTERNAL_SERVER_ERROR : HttpStatus.OK; - this.statusText = exception != null ? exception.getExceptionMessage() : httpStatus.getReasonPhrase(); - this.httpOutputMessage = httpOutputMessage; - this.httpHeaders.putAll(httpOutputMessage.getHeaders()); - } + public DubboClientHttpResponse(DubboHttpOutputMessage httpOutputMessage, + GenericException exception) { + this.httpStatus = exception != null ? HttpStatus.INTERNAL_SERVER_ERROR + : HttpStatus.OK; + this.statusText = exception != null ? exception.getExceptionMessage() + : httpStatus.getReasonPhrase(); + this.httpOutputMessage = httpOutputMessage; + this.httpHeaders.putAll(httpOutputMessage.getHeaders()); + } - @Override - public HttpStatus getStatusCode() throws IOException { - return httpStatus; - } + @Override + public HttpStatus getStatusCode() throws IOException { + return httpStatus; + } - @Override - public int getRawStatusCode() throws IOException { - return httpStatus.value(); - } + @Override + public int getRawStatusCode() throws IOException { + return httpStatus.value(); + } - @Override - public String getStatusText() throws IOException { - return statusText; - } + @Override + public String getStatusText() throws IOException { + return statusText; + } - @Override - public void close() { - } + @Override + public void close() { + } - @Override - public InputStream getBody() throws IOException { - return httpOutputMessage.getBody().getInputStream(); - } + @Override + public InputStream getBody() throws IOException { + return httpOutputMessage.getBody().getInputStream(); + } - @Override - public HttpHeaders getHeaders() { - return httpHeaders; - } + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java index cb51ccd33..561515f78 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java @@ -16,18 +16,19 @@ */ package com.alibaba.cloud.dubbo.client.loadbalancer; +import java.io.IOException; +import java.util.List; + import org.apache.dubbo.rpc.service.GenericException; -import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder; -import com.alibaba.cloud.dubbo.http.util.HttpMessageConverterResolver; -import com.alibaba.cloud.dubbo.metadata.RequestMetadata; -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.HttpMessageConverter; -import java.io.IOException; -import java.util.List; +import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder; +import com.alibaba.cloud.dubbo.http.util.HttpMessageConverterResolver; +import com.alibaba.cloud.dubbo.metadata.RequestMetadata; +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; /** * Dubbo {@link ClientHttpResponse} Factory @@ -36,29 +37,33 @@ import java.util.List; */ class DubboClientHttpResponseFactory { - private final HttpMessageConverterResolver httpMessageConverterResolver; + private final HttpMessageConverterResolver httpMessageConverterResolver; - public DubboClientHttpResponseFactory(List> messageConverters, ClassLoader classLoader) { - this.httpMessageConverterResolver = new HttpMessageConverterResolver(messageConverters, classLoader); - } + public DubboClientHttpResponseFactory(List> messageConverters, + ClassLoader classLoader) { + this.httpMessageConverterResolver = new HttpMessageConverterResolver( + messageConverters, classLoader); + } - public ClientHttpResponse build(Object result, GenericException exception, - RequestMetadata requestMetadata, RestMethodMetadata restMethodMetadata) { + public ClientHttpResponse build(Object result, GenericException exception, + RequestMetadata requestMetadata, RestMethodMetadata restMethodMetadata) { - DubboHttpOutputMessage httpOutputMessage = new DubboHttpOutputMessage(); + DubboHttpOutputMessage httpOutputMessage = new DubboHttpOutputMessage(); - HttpMessageConverterHolder httpMessageConverterHolder = httpMessageConverterResolver.resolve(requestMetadata, restMethodMetadata); + HttpMessageConverterHolder httpMessageConverterHolder = httpMessageConverterResolver + .resolve(requestMetadata, restMethodMetadata); - if (httpMessageConverterHolder != null) { - MediaType mediaType = httpMessageConverterHolder.getMediaType(); - HttpMessageConverter converter = httpMessageConverterHolder.getConverter(); - try { - converter.write(result, mediaType, httpOutputMessage); - } catch (IOException e) { - e.printStackTrace(); - } - } + if (httpMessageConverterHolder != null) { + MediaType mediaType = httpMessageConverterHolder.getMediaType(); + HttpMessageConverter converter = httpMessageConverterHolder.getConverter(); + try { + converter.write(result, mediaType, httpOutputMessage); + } + catch (IOException e) { + e.printStackTrace(); + } + } - return new DubboClientHttpResponse(httpOutputMessage, exception); - } + return new DubboClientHttpResponse(httpOutputMessage, exception); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java index 634579028..96a3e6c8c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java @@ -16,12 +16,12 @@ */ package com.alibaba.cloud.dubbo.client.loadbalancer; +import java.io.IOException; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpOutputMessage; import org.springframework.util.FastByteArrayOutputStream; -import java.io.IOException; - /** * Dubbo {@link HttpOutputMessage} implementation * @@ -29,17 +29,17 @@ import java.io.IOException; */ class DubboHttpOutputMessage implements HttpOutputMessage { - private final FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream(); + private final FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream(); - private final HttpHeaders httpHeaders = new HttpHeaders(); + private final HttpHeaders httpHeaders = new HttpHeaders(); - @Override - public FastByteArrayOutputStream getBody() throws IOException { - return outputStream; - } + @Override + public FastByteArrayOutputStream getBody() throws IOException { + return outputStream; + } - @Override - public HttpHeaders getHeaders() { - return httpHeaders; - } + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java index 43b14ffff..53bc6a3fa 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java @@ -16,39 +16,42 @@ */ package com.alibaba.cloud.dubbo.client.loadbalancer; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import java.io.IOException; +import java.net.URI; + import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; -import java.io.IOException; -import java.net.URI; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; /** - * Dubbo Metadata {@link ClientHttpRequestInterceptor} Initializing Interceptor executes intercept before - * {@link DubboTransporterInterceptor} + * Dubbo Metadata {@link ClientHttpRequestInterceptor} Initializing Interceptor executes + * intercept before {@link DubboTransporterInterceptor} * * @author Mercy */ public class DubboMetadataInitializerInterceptor implements ClientHttpRequestInterceptor { - private final DubboServiceMetadataRepository repository; + private final DubboServiceMetadataRepository repository; - public DubboMetadataInitializerInterceptor(DubboServiceMetadataRepository repository) { - this.repository = repository; - } + public DubboMetadataInitializerInterceptor( + DubboServiceMetadataRepository repository) { + this.repository = repository; + } - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, + ClientHttpRequestExecution execution) throws IOException { - URI originalUri = request.getURI(); + URI originalUri = request.getURI(); - String serviceName = originalUri.getHost(); + String serviceName = originalUri.getHost(); - repository.initializeMetadata(serviceName); + repository.initializeMetadata(serviceName); - // Execute next - return execution.execute(request, body); - } + // Execute next + return execution.execute(request, body); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java index bec422ed5..4d73112d5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java @@ -16,17 +16,16 @@ */ package com.alibaba.cloud.dubbo.client.loadbalancer; +import static org.springframework.web.util.UriComponentsBuilder.fromUri; + +import java.io.IOException; +import java.net.URI; +import java.util.List; +import java.util.Map; + import org.apache.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericService; -import com.alibaba.cloud.dubbo.http.MutableHttpServerRequest; -import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; -import com.alibaba.cloud.dubbo.metadata.RequestMetadata; -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContext; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; @@ -38,12 +37,14 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.PathMatcher; import org.springframework.web.util.UriComponents; -import java.io.IOException; -import java.net.URI; -import java.util.List; -import java.util.Map; - -import static org.springframework.web.util.UriComponentsBuilder.fromUri; +import com.alibaba.cloud.dubbo.http.MutableHttpServerRequest; +import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; +import com.alibaba.cloud.dubbo.metadata.RequestMetadata; +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContext; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; /** * Dubbo Transporter {@link ClientHttpRequestInterceptor} implementation @@ -53,91 +54,100 @@ import static org.springframework.web.util.UriComponentsBuilder.fromUri; */ public class DubboTransporterInterceptor implements ClientHttpRequestInterceptor { - private final DubboServiceMetadataRepository repository; + private final DubboServiceMetadataRepository repository; - private final DubboClientHttpResponseFactory clientHttpResponseFactory; + private final DubboClientHttpResponseFactory clientHttpResponseFactory; - private final Map dubboTranslatedAttributes; + private final Map dubboTranslatedAttributes; - private final DubboGenericServiceFactory serviceFactory; + private final DubboGenericServiceFactory serviceFactory; - private final DubboGenericServiceExecutionContextFactory contextFactory; + private final DubboGenericServiceExecutionContextFactory contextFactory; - private final PathMatcher pathMatcher = new AntPathMatcher(); + private final PathMatcher pathMatcher = new AntPathMatcher(); - public DubboTransporterInterceptor(DubboServiceMetadataRepository dubboServiceMetadataRepository, - List> messageConverters, - ClassLoader classLoader, - Map dubboTranslatedAttributes, - DubboGenericServiceFactory serviceFactory, - DubboGenericServiceExecutionContextFactory contextFactory) { - this.repository = dubboServiceMetadataRepository; - this.dubboTranslatedAttributes = dubboTranslatedAttributes; - this.clientHttpResponseFactory = new DubboClientHttpResponseFactory(messageConverters, classLoader); - this.serviceFactory = serviceFactory; - this.contextFactory = contextFactory; - } + public DubboTransporterInterceptor( + DubboServiceMetadataRepository dubboServiceMetadataRepository, + List> messageConverters, ClassLoader classLoader, + Map dubboTranslatedAttributes, + DubboGenericServiceFactory serviceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { + this.repository = dubboServiceMetadataRepository; + this.dubboTranslatedAttributes = dubboTranslatedAttributes; + this.clientHttpResponseFactory = new DubboClientHttpResponseFactory( + messageConverters, classLoader); + this.serviceFactory = serviceFactory; + this.contextFactory = contextFactory; + } - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, + ClientHttpRequestExecution execution) throws IOException { - URI originalUri = request.getURI(); + URI originalUri = request.getURI(); - String serviceName = originalUri.getHost(); + String serviceName = originalUri.getHost(); - RequestMetadata clientMetadata = buildRequestMetadata(request); + RequestMetadata clientMetadata = buildRequestMetadata(request); - DubboRestServiceMetadata metadata = repository.get(serviceName, clientMetadata); + DubboRestServiceMetadata metadata = repository.get(serviceName, clientMetadata); - if (metadata == null) { - // if DubboServiceMetadata is not found, executes next - return execution.execute(request, body); - } + if (metadata == null) { + // if DubboServiceMetadata is not found, executes next + return execution.execute(request, body); + } - RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata(); + RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata(); - GenericService genericService = serviceFactory.create(metadata, dubboTranslatedAttributes); + GenericService genericService = serviceFactory.create(metadata, + dubboTranslatedAttributes); - MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(request, body); + MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(request, + body); - customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata); + customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata); - DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, httpServerRequest); + DubboGenericServiceExecutionContext context = contextFactory + .create(dubboRestMethodMetadata, httpServerRequest); - Object result = null; - GenericException exception = null; + Object result = null; + GenericException exception = null; - try { - result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters()); - } catch (GenericException e) { - exception = e; - } + try { + result = genericService.$invoke(context.getMethodName(), + context.getParameterTypes(), context.getParameters()); + } + catch (GenericException e) { + exception = e; + } - return clientHttpResponseFactory.build(result, exception, clientMetadata, dubboRestMethodMetadata); - } + return clientHttpResponseFactory.build(result, exception, clientMetadata, + dubboRestMethodMetadata); + } - protected void customizeRequest(MutableHttpServerRequest httpServerRequest, - RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) { + protected void customizeRequest(MutableHttpServerRequest httpServerRequest, + RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) { - RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest(); - String pathPattern = dubboRequestMetadata.getPath(); + RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest(); + String pathPattern = dubboRequestMetadata.getPath(); - Map pathVariables = pathMatcher.extractUriTemplateVariables(pathPattern, httpServerRequest.getPath()); + Map pathVariables = pathMatcher + .extractUriTemplateVariables(pathPattern, httpServerRequest.getPath()); - if (!CollectionUtils.isEmpty(pathVariables)) { - // Put path variables Map into query parameters Map - httpServerRequest.params(pathVariables); - } + if (!CollectionUtils.isEmpty(pathVariables)) { + // Put path variables Map into query parameters Map + httpServerRequest.params(pathVariables); + } - } + } - private RequestMetadata buildRequestMetadata(HttpRequest request) { - UriComponents uriComponents = fromUri(request.getURI()).build(true); - RequestMetadata requestMetadata = new RequestMetadata(); - requestMetadata.setPath(uriComponents.getPath()); - requestMetadata.setMethod(request.getMethod().name()); - requestMetadata.setParams(uriComponents.getQueryParams()); - requestMetadata.setHeaders(request.getHeaders()); - return requestMetadata; - } + private RequestMetadata buildRequestMetadata(HttpRequest request) { + UriComponents uriComponents = fromUri(request.getURI()).build(true); + RequestMetadata requestMetadata = new RequestMetadata(); + requestMetadata.setPath(uriComponents.getPath()); + requestMetadata.setMethod(request.getMethod().name()); + requestMetadata.setParams(uriComponents.getQueryParams()); + requestMetadata.setHeaders(request.getHeaders()); + return requestMetadata; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java index 83dd98318..e9c747cf4 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java @@ -16,23 +16,26 @@ */ package com.alibaba.cloud.dubbo.context; -import com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; +import com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory; + /** - * The Dubbo services will be registered as the specified Spring cloud applications that will not be considered - * normal ones, but only are used to Dubbo's service discovery even if it is based on Spring Cloud Commons abstraction. - * However, current application will be registered by other DiscoveryClientAutoConfiguration. + * The Dubbo services will be registered as the specified Spring cloud applications that + * will not be considered normal ones, but only are used to Dubbo's service discovery even + * if it is based on Spring Cloud Commons abstraction. However, current application will + * be registered by other DiscoveryClientAutoConfiguration. * * @author Mercy */ -public class DubboServiceRegistrationApplicationContextInitializer implements - ApplicationContextInitializer { +public class DubboServiceRegistrationApplicationContextInitializer + implements ApplicationContextInitializer { - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register - SpringCloudRegistryFactory.setApplicationContext(applicationContext); - } + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service + // Register + SpringCloudRegistryFactory.setApplicationContext(applicationContext); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java index dc349e584..b9d33c376 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java @@ -16,15 +16,15 @@ */ package com.alibaba.cloud.dubbo.env; -import org.springframework.boot.context.properties.ConfigurationProperties; +import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; +import static org.springframework.util.StringUtils.hasText; +import static org.springframework.util.StringUtils.trimAllWhitespace; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; -import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; -import static org.springframework.util.StringUtils.hasText; -import static org.springframework.util.StringUtils.trimAllWhitespace; +import org.springframework.boot.context.properties.ConfigurationProperties; /** * Dubbo Cloud {@link ConfigurationProperties Properties} @@ -34,48 +34,49 @@ import static org.springframework.util.StringUtils.trimAllWhitespace; @ConfigurationProperties(prefix = "dubbo.cloud") public class DubboCloudProperties { - /** - * All services of Dubbo - */ - public static final String ALL_DUBBO_SERVICES = "*"; + /** + * All services of Dubbo + */ + public static final String ALL_DUBBO_SERVICES = "*"; - /** - * The subscribed services, the default value is "*". The multiple value will use comma(",") as the separator. - * - * @see #ALL_DUBBO_SERVICES - */ - private String subscribedServices = ALL_DUBBO_SERVICES; + /** + * The subscribed services, the default value is "*". The multiple value will use + * comma(",") as the separator. + * + * @see #ALL_DUBBO_SERVICES + */ + private String subscribedServices = ALL_DUBBO_SERVICES; - public String getSubscribedServices() { - return subscribedServices; - } + public String getSubscribedServices() { + return subscribedServices; + } - public void setSubscribedServices(String subscribedServices) { - this.subscribedServices = subscribedServices; - } + public void setSubscribedServices(String subscribedServices) { + this.subscribedServices = subscribedServices; + } - /** - * Get the subscribed services as a {@link Set} with configuration order. - * - * @return non-null Read-only {@link Set} - */ - public Set subscribedServices() { + /** + * Get the subscribed services as a {@link Set} with configuration order. + * + * @return non-null Read-only {@link Set} + */ + public Set subscribedServices() { - String[] services = commaDelimitedListToStringArray(getSubscribedServices()); + String[] services = commaDelimitedListToStringArray(getSubscribedServices()); - if (services.length < 1) { - return Collections.emptySet(); - } + if (services.length < 1) { + return Collections.emptySet(); + } - Set subscribedServices = new LinkedHashSet<>(); + Set subscribedServices = new LinkedHashSet<>(); - for (String service : services) { - if (hasText(service)) { // filter blank service name - // remove all whitespace - subscribedServices.add(trimAllWhitespace(service)); - } - } + for (String service : services) { + if (hasText(service)) { // filter blank service name + // remove all whitespace + subscribedServices.add(trimAllWhitespace(service)); + } + } - return Collections.unmodifiableSet(subscribedServices); - } + return Collections.unmodifiableSet(subscribedServices); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java index d03f6ccf6..90eae0697 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java @@ -16,6 +16,13 @@ */ package com.alibaba.cloud.dubbo.env; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL; +import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; @@ -29,179 +36,191 @@ import org.springframework.core.env.PropertySource; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL; -import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; - /** - * Dubbo {@link WebApplicationType#NONE Non-Web Application} {@link EnvironmentPostProcessor} + * Dubbo {@link WebApplicationType#NONE Non-Web Application} + * {@link EnvironmentPostProcessor} * * @author Mercy */ -public class DubboNonWebApplicationEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { - - private static final String DOT = "."; - - /** - * The name of default {@link PropertySource} defined in SpringApplication#configurePropertySources method. - */ - private static final String PROPERTY_SOURCE_NAME = "defaultProperties"; +public class DubboNonWebApplicationEnvironmentPostProcessor + implements EnvironmentPostProcessor, Ordered { - private static final String SERVER_PORT_PROPERTY_NAME = "server.port"; + private static final String DOT = "."; - private static final String PORT_PROPERTY_NAME = "port"; + /** + * The name of default {@link PropertySource} defined in + * SpringApplication#configurePropertySources method. + */ + private static final String PROPERTY_SOURCE_NAME = "defaultProperties"; - private static final String PROTOCOL_PROPERTY_NAME_PREFIX = "dubbo.protocol"; + private static final String SERVER_PORT_PROPERTY_NAME = "server.port"; - private static final String PROTOCOL_NAME_PROPERTY_NAME_SUFFIX = DOT + "name"; + private static final String PORT_PROPERTY_NAME = "port"; - private static final String PROTOCOL_PORT_PROPERTY_NAME_SUFFIX = DOT + PORT_PROPERTY_NAME; + private static final String PROTOCOL_PROPERTY_NAME_PREFIX = "dubbo.protocol"; - private static final String PROTOCOL_PORT_PROPERTY_NAME = PROTOCOL_PROPERTY_NAME_PREFIX + PROTOCOL_PORT_PROPERTY_NAME_SUFFIX; + private static final String PROTOCOL_NAME_PROPERTY_NAME_SUFFIX = DOT + "name"; - private static final String PROTOCOL_NAME_PROPERTY_NAME = PROTOCOL_PROPERTY_NAME_PREFIX + PROTOCOL_NAME_PROPERTY_NAME_SUFFIX; + private static final String PROTOCOL_PORT_PROPERTY_NAME_SUFFIX = DOT + + PORT_PROPERTY_NAME; - private static final String PROTOCOLS_PROPERTY_NAME_PREFIX = "dubbo.protocols"; + private static final String PROTOCOL_PORT_PROPERTY_NAME = PROTOCOL_PROPERTY_NAME_PREFIX + + PROTOCOL_PORT_PROPERTY_NAME_SUFFIX; - private static final String REST_PROTOCOL = "rest"; + private static final String PROTOCOL_NAME_PROPERTY_NAME = PROTOCOL_PROPERTY_NAME_PREFIX + + PROTOCOL_NAME_PROPERTY_NAME_SUFFIX; - private final Logger logger = LoggerFactory.getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class); + private static final String PROTOCOLS_PROPERTY_NAME_PREFIX = "dubbo.protocols"; - private static boolean isRestProtocol(String protocol) { - return REST_PROTOCOL.equalsIgnoreCase(protocol); - } + private static final String REST_PROTOCOL = "rest"; - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - WebApplicationType webApplicationType = application.getWebApplicationType(); + private final Logger logger = LoggerFactory + .getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class); - if (!WebApplicationType.NONE.equals(webApplicationType)) { // Just works in Non-Web Application - if (logger.isDebugEnabled()) { - logger.debug("Current application is a Web Application, the process will be ignored."); - } - return; - } + private static boolean isRestProtocol(String protocol) { + return REST_PROTOCOL.equalsIgnoreCase(protocol); + } - MutablePropertySources propertySources = environment.getPropertySources(); - Map defaultProperties = createDefaultProperties(environment); - if (!CollectionUtils.isEmpty(defaultProperties)) { - addOrReplace(propertySources, defaultProperties); - } - } + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, + SpringApplication application) { + WebApplicationType webApplicationType = application.getWebApplicationType(); + + if (!WebApplicationType.NONE.equals(webApplicationType)) { // Just works in + // Non-Web Application + if (logger.isDebugEnabled()) { + logger.debug( + "Current application is a Web Application, the process will be ignored."); + } + return; + } - private Map createDefaultProperties(ConfigurableEnvironment environment) { - Map defaultProperties = new HashMap(); - resetServerPort(environment, defaultProperties); - return defaultProperties; - } - - /** - * Reset server port property if it's absent, whose value is configured by "dubbbo.protocol.port" - * or "dubbo.protcols.rest.port" - * - * @param environment - * @param defaultProperties - */ - private void resetServerPort(ConfigurableEnvironment environment, Map defaultProperties) { - - String serverPort = environment.getProperty(SERVER_PORT_PROPERTY_NAME, environment.getProperty(PORT_PROPERTY_NAME)); - - if (serverPort != null) { - return; - } - - serverPort = getRestPortFromProtocolProperty(environment); - - if (serverPort == null) { - serverPort = getRestPortFromProtocolsProperties(environment); - } - - setServerPort(environment, serverPort, defaultProperties); - } - - private String getRestPortFromProtocolProperty(ConfigurableEnvironment environment) { - - String protocol = environment.getProperty(PROTOCOL_NAME_PROPERTY_NAME, DEFAULT_PROTOCOL); - - return isRestProtocol(protocol) ? - environment.getProperty(PROTOCOL_PORT_PROPERTY_NAME) : - null; - } - - private String getRestPortFromProtocolsProperties(ConfigurableEnvironment environment) { - - String restPort = null; - - Map subProperties = getSubProperties(environment, PROTOCOLS_PROPERTY_NAME_PREFIX); - - Properties properties = new Properties(); - - properties.putAll(subProperties); - - for (String propertyName : properties.stringPropertyNames()) { - if (propertyName.endsWith(PROTOCOL_NAME_PROPERTY_NAME_SUFFIX)) { // protocol name property - String protocol = properties.getProperty(propertyName); - if (isRestProtocol(protocol)) { - String beanName = resolveBeanName(propertyName); - if (StringUtils.hasText(beanName)) { - restPort = properties.getProperty(beanName + PROTOCOL_PORT_PROPERTY_NAME_SUFFIX); - break; - } - } - } - } - - return restPort; - } - - private String resolveBeanName(String propertyName) { - int index = propertyName.indexOf(DOT); - return index > -1 ? propertyName.substring(0, index) : null; - } - - private void setServerPort(ConfigurableEnvironment environment, String serverPort, - Map defaultProperties) { - if (serverPort == null) { - return; - } - - defaultProperties.put(SERVER_PORT_PROPERTY_NAME, serverPort); - - } - - /** - * Copy from BusEnvironmentPostProcessor#addOrReplace(MutablePropertySources, Map) - * - * @param propertySources {@link MutablePropertySources} - * @param map Default Dubbo Properties - */ - private void addOrReplace(MutablePropertySources propertySources, - Map map) { - MapPropertySource target = null; - if (propertySources.contains(PROPERTY_SOURCE_NAME)) { - PropertySource source = propertySources.get(PROPERTY_SOURCE_NAME); - if (source instanceof MapPropertySource) { - target = (MapPropertySource) source; - for (String key : map.keySet()) { - if (!target.containsProperty(key)) { - target.getSource().put(key, map.get(key)); - } - } - } - } - if (target == null) { - target = new MapPropertySource(PROPERTY_SOURCE_NAME, map); - } - if (!propertySources.contains(PROPERTY_SOURCE_NAME)) { - propertySources.addLast(target); - } - } - - @Override - public int getOrder() { // Keep LOWEST_PRECEDENCE - return LOWEST_PRECEDENCE; - } + MutablePropertySources propertySources = environment.getPropertySources(); + Map defaultProperties = createDefaultProperties(environment); + if (!CollectionUtils.isEmpty(defaultProperties)) { + addOrReplace(propertySources, defaultProperties); + } + } + + private Map createDefaultProperties( + ConfigurableEnvironment environment) { + Map defaultProperties = new HashMap(); + resetServerPort(environment, defaultProperties); + return defaultProperties; + } + + /** + * Reset server port property if it's absent, whose value is configured by + * "dubbbo.protocol.port" or "dubbo.protcols.rest.port" + * + * @param environment + * @param defaultProperties + */ + private void resetServerPort(ConfigurableEnvironment environment, + Map defaultProperties) { + + String serverPort = environment.getProperty(SERVER_PORT_PROPERTY_NAME, + environment.getProperty(PORT_PROPERTY_NAME)); + + if (serverPort != null) { + return; + } + + serverPort = getRestPortFromProtocolProperty(environment); + + if (serverPort == null) { + serverPort = getRestPortFromProtocolsProperties(environment); + } + + setServerPort(environment, serverPort, defaultProperties); + } + + private String getRestPortFromProtocolProperty(ConfigurableEnvironment environment) { + + String protocol = environment.getProperty(PROTOCOL_NAME_PROPERTY_NAME, + DEFAULT_PROTOCOL); + + return isRestProtocol(protocol) + ? environment.getProperty(PROTOCOL_PORT_PROPERTY_NAME) + : null; + } + + private String getRestPortFromProtocolsProperties( + ConfigurableEnvironment environment) { + + String restPort = null; + + Map subProperties = getSubProperties(environment, + PROTOCOLS_PROPERTY_NAME_PREFIX); + + Properties properties = new Properties(); + + properties.putAll(subProperties); + + for (String propertyName : properties.stringPropertyNames()) { + if (propertyName.endsWith(PROTOCOL_NAME_PROPERTY_NAME_SUFFIX)) { // protocol + // name + // property + String protocol = properties.getProperty(propertyName); + if (isRestProtocol(protocol)) { + String beanName = resolveBeanName(propertyName); + if (StringUtils.hasText(beanName)) { + restPort = properties.getProperty( + beanName + PROTOCOL_PORT_PROPERTY_NAME_SUFFIX); + break; + } + } + } + } + + return restPort; + } + + private String resolveBeanName(String propertyName) { + int index = propertyName.indexOf(DOT); + return index > -1 ? propertyName.substring(0, index) : null; + } + + private void setServerPort(ConfigurableEnvironment environment, String serverPort, + Map defaultProperties) { + if (serverPort == null) { + return; + } + + defaultProperties.put(SERVER_PORT_PROPERTY_NAME, serverPort); + + } + + /** + * Copy from BusEnvironmentPostProcessor#addOrReplace(MutablePropertySources, Map) + * + * @param propertySources {@link MutablePropertySources} + * @param map Default Dubbo Properties + */ + private void addOrReplace(MutablePropertySources propertySources, + Map map) { + MapPropertySource target = null; + if (propertySources.contains(PROPERTY_SOURCE_NAME)) { + PropertySource source = propertySources.get(PROPERTY_SOURCE_NAME); + if (source instanceof MapPropertySource) { + target = (MapPropertySource) source; + for (String key : map.keySet()) { + if (!target.containsProperty(key)) { + target.getSource().put(key, map.get(key)); + } + } + } + } + if (target == null) { + target = new MapPropertySource(PROPERTY_SOURCE_NAME, map); + } + if (!propertySources.contains(PROPERTY_SOURCE_NAME)) { + propertySources.addLast(target); + } + } + + @Override + public int getOrder() { // Keep LOWEST_PRECEDENCE + return LOWEST_PRECEDENCE; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java index 4b2b12b22..4484a5805 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java @@ -16,14 +16,14 @@ */ package com.alibaba.cloud.dubbo.http; +import java.io.IOException; +import java.io.InputStream; + import org.apache.dubbo.common.io.UnsafeByteArrayInputStream; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; -import java.io.IOException; -import java.io.InputStream; - /** * Byte array {@link HttpInputMessage} implementation * @@ -31,26 +31,26 @@ import java.io.InputStream; */ class ByteArrayHttpInputMessage implements HttpInputMessage { - private final HttpHeaders httpHeaders; + private final HttpHeaders httpHeaders; - private final InputStream inputStream; + private final InputStream inputStream; - public ByteArrayHttpInputMessage(byte[] body) { - this(new HttpHeaders(), body); - } + public ByteArrayHttpInputMessage(byte[] body) { + this(new HttpHeaders(), body); + } - public ByteArrayHttpInputMessage(HttpHeaders httpHeaders, byte[] body) { - this.httpHeaders = httpHeaders; - this.inputStream = new UnsafeByteArrayInputStream(body); - } + public ByteArrayHttpInputMessage(HttpHeaders httpHeaders, byte[] body) { + this.httpHeaders = httpHeaders; + this.inputStream = new UnsafeByteArrayInputStream(body); + } - @Override - public InputStream getBody() throws IOException { - return inputStream; - } + @Override + public InputStream getBody() throws IOException { + return inputStream; + } - @Override - public HttpHeaders getHeaders() { - return httpHeaders; - } + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java index 4c1e26fe3..183c40966 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java @@ -16,6 +16,12 @@ */ package com.alibaba.cloud.dubbo.http; +import static org.springframework.web.util.UriComponentsBuilder.fromPath; + +import java.net.URI; +import java.util.List; +import java.util.Map; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRequest; @@ -23,12 +29,6 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponentsBuilder; -import java.net.URI; -import java.util.List; -import java.util.Map; - -import static org.springframework.web.util.UriComponentsBuilder.fromPath; - /** * Default {@link HttpRequest} implementation * @@ -36,96 +36,95 @@ import static org.springframework.web.util.UriComponentsBuilder.fromPath; */ public class DefaultHttpRequest implements HttpRequest { - private final String method; - - private final URI uri; + private final String method; - private final HttpHeaders headers = new HttpHeaders(); + private final URI uri; - public DefaultHttpRequest(String method, String path, Map> params, - Map> headers) { - this.method = method == null ? HttpMethod.GET.name() : method.toUpperCase(); - this.uri = buildURI(path, params); - this.headers.putAll(headers); - } + private final HttpHeaders headers = new HttpHeaders(); - public static Builder builder() { - return new Builder(); - } + public DefaultHttpRequest(String method, String path, + Map> params, Map> headers) { + this.method = method == null ? HttpMethod.GET.name() : method.toUpperCase(); + this.uri = buildURI(path, params); + this.headers.putAll(headers); + } - private URI buildURI(String path, Map> params) { - UriComponentsBuilder builder = fromPath(path) - .queryParams(new LinkedMultiValueMap<>(params)); - return builder.build().toUri(); - } + public static Builder builder() { + return new Builder(); + } - @Override - public HttpMethod getMethod() { - return HttpMethod.resolve(getMethodValue()); - } + private URI buildURI(String path, Map> params) { + UriComponentsBuilder builder = fromPath(path) + .queryParams(new LinkedMultiValueMap<>(params)); + return builder.build().toUri(); + } - @Override - public String getMethodValue() { - return method; - } + @Override + public HttpMethod getMethod() { + return HttpMethod.resolve(getMethodValue()); + } - @Override - public URI getURI() { - return uri; - } + @Override + public String getMethodValue() { + return method; + } - @Override - public HttpHeaders getHeaders() { - return headers; - } + @Override + public URI getURI() { + return uri; + } - /** - * {@link HttpRequest} Builder - */ - public static class Builder { + @Override + public HttpHeaders getHeaders() { + return headers; + } - String method; + /** + * {@link HttpRequest} Builder + */ + public static class Builder { - String path; + String method; - MultiValueMap params = new LinkedMultiValueMap<>(); + String path; - MultiValueMap headers = new LinkedMultiValueMap<>(); + MultiValueMap params = new LinkedMultiValueMap<>(); - public Builder method(String method) { - this.method = method; - return this; - } + MultiValueMap headers = new LinkedMultiValueMap<>(); - public Builder path(String path) { - this.path = path; - return this; - } + public Builder method(String method) { + this.method = method; + return this; + } - public Builder param(String name, String value) { - this.params.add(name, value); - return this; - } + public Builder path(String path) { + this.path = path; + return this; + } - public Builder header(String name, String value) { - this.headers.add(name, value); - return this; - } + public Builder param(String name, String value) { + this.params.add(name, value); + return this; + } - public Builder params(Map> params) { - this.params.putAll(params); - return this; - } + public Builder header(String name, String value) { + this.headers.add(name, value); + return this; + } - public Builder headers(Map> headers) { - this.headers.putAll(headers); - return this; - } + public Builder params(Map> params) { + this.params.putAll(params); + return this; + } - public HttpRequest build() { - return new DefaultHttpRequest(method, path, params, headers); - } - } + public Builder headers(Map> headers) { + this.headers.putAll(headers); + return this; + } + public HttpRequest build() { + return new DefaultHttpRequest(method, path, params, headers); + } + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java index 00bcbf40a..11af67672 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java @@ -27,16 +27,16 @@ import org.springframework.util.MultiValueMap; */ public interface HttpServerRequest extends HttpRequest, HttpInputMessage { - /** - * Return a path of current HTTP request - * - * @return - */ - String getPath(); + /** + * Return a path of current HTTP request + * + * @return + */ + String getPath(); - /** - * Return a map with parsed and decoded query parameter values. - */ - MultiValueMap getQueryParams(); + /** + * Return a map with parsed and decoded query parameter values. + */ + MultiValueMap getQueryParams(); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java index 602c685a3..3348bd69c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java @@ -16,18 +16,18 @@ */ package com.alibaba.cloud.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.util.MultiValueMap; +import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Map; -import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.util.MultiValueMap; /** * Mutable {@link HttpServerRequest} implementation @@ -36,65 +36,65 @@ import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters; */ public class MutableHttpServerRequest implements HttpServerRequest { - private final HttpMethod httpMethod; + private final HttpMethod httpMethod; - private final URI uri; + private final URI uri; - private final String path; + private final String path; - private final MultiValueMap queryParams; + private final MultiValueMap queryParams; - private final HttpHeaders httpHeaders; + private final HttpHeaders httpHeaders; - private final HttpInputMessage httpInputMessage; + private final HttpInputMessage httpInputMessage; - public MutableHttpServerRequest(HttpRequest httpRequest, byte[] body) { - this.httpMethod = httpRequest.getMethod(); - this.uri = httpRequest.getURI(); - this.path = uri.getPath(); - this.httpHeaders = httpRequest.getHeaders(); - this.queryParams = getParameters(httpRequest); - this.httpInputMessage = new ByteArrayHttpInputMessage(body); - } + public MutableHttpServerRequest(HttpRequest httpRequest, byte[] body) { + this.httpMethod = httpRequest.getMethod(); + this.uri = httpRequest.getURI(); + this.path = uri.getPath(); + this.httpHeaders = httpRequest.getHeaders(); + this.queryParams = getParameters(httpRequest); + this.httpInputMessage = new ByteArrayHttpInputMessage(body); + } - public MutableHttpServerRequest params(Map params) { - queryParams.setAll(params); - return this; - } + public MutableHttpServerRequest params(Map params) { + queryParams.setAll(params); + return this; + } - @Override - public InputStream getBody() throws IOException { - return httpInputMessage.getBody(); - } + @Override + public InputStream getBody() throws IOException { + return httpInputMessage.getBody(); + } - @Override - public HttpMethod getMethod() { - return httpMethod; - } + @Override + public HttpMethod getMethod() { + return httpMethod; + } - // Override method since Spring Framework 5.0 - @Override - public String getMethodValue() { - return httpMethod.name(); - } + // Override method since Spring Framework 5.0 + @Override + public String getMethodValue() { + return httpMethod.name(); + } - @Override - public URI getURI() { - return uri; - } + @Override + public URI getURI() { + return uri; + } - @Override - public HttpHeaders getHeaders() { - return httpHeaders; - } + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } - @Override - public String getPath() { - return path; - } + @Override + public String getPath() { + return path; + } - @Override - public MultiValueMap getQueryParams() { - return queryParams; - } + @Override + public MultiValueMap getQueryParams() { + return queryParams; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java index 2a2423863..67d2f30b7 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java @@ -26,20 +26,21 @@ import org.springframework.http.converter.HttpMessageConverter; */ public class HttpMessageConverterHolder { - private final MediaType mediaType; + private final MediaType mediaType; - private final HttpMessageConverter converter; + private final HttpMessageConverter converter; - public HttpMessageConverterHolder(MediaType mediaType, HttpMessageConverter converter) { - this.mediaType = mediaType; - this.converter = converter; - } + public HttpMessageConverterHolder(MediaType mediaType, + HttpMessageConverter converter) { + this.mediaType = mediaType; + this.converter = converter; + } - public MediaType getMediaType() { - return mediaType; - } + public MediaType getMediaType() { + return mediaType; + } - public HttpMessageConverter getConverter() { - return converter; - } + public HttpMessageConverter getConverter() { + return converter; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java index c823de4fd..4bc1c2817 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java @@ -27,50 +27,50 @@ import java.util.Iterator; */ public abstract class AbstractHttpRequestMatcher implements HttpRequestMatcher { - /** - * Return the discrete items a request condition is composed of. - *

- * For example URL patterns, HTTP request methods, param expressions, etc. - * - * @return a collection of objects, never {@code null} - */ - protected abstract Collection getContent(); + /** + * Return the discrete items a request condition is composed of. + *

+ * For example URL patterns, HTTP request methods, param expressions, etc. + * + * @return a collection of objects, never {@code null} + */ + protected abstract Collection getContent(); - /** - * The notation to use when printing discrete items of content. - *

- * For example {@code " || "} for URL patterns or {@code " && "} for param - * expressions. - */ - protected abstract String getToStringInfix(); + /** + * The notation to use when printing discrete items of content. + *

+ * For example {@code " || "} for URL patterns or {@code " && "} for param + * expressions. + */ + protected abstract String getToStringInfix(); - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - return getContent().equals(((AbstractHttpRequestMatcher) other).getContent()); - } + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + return getContent().equals(((AbstractHttpRequestMatcher) other).getContent()); + } - @Override - public int hashCode() { - return getContent().hashCode(); - } + @Override + public int hashCode() { + return getContent().hashCode(); + } - @Override - public String toString() { - StringBuilder builder = new StringBuilder("["); - for (Iterator iterator = getContent().iterator(); iterator.hasNext(); ) { - Object expression = iterator.next(); - builder.append(expression.toString()); - if (iterator.hasNext()) { - builder.append(getToStringInfix()); - } - } - builder.append("]"); - return builder.toString(); - } + @Override + public String toString() { + StringBuilder builder = new StringBuilder("["); + for (Iterator iterator = getContent().iterator(); iterator.hasNext();) { + Object expression = iterator.next(); + builder.append(expression.toString()); + if (iterator.hasNext()) { + builder.append(getToStringInfix()); + } + } + builder.append("]"); + return builder.toString(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java index 5f47f1bc0..60e8939f5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java @@ -19,73 +19,77 @@ package com.alibaba.cloud.dubbo.http.matcher; import org.springframework.http.MediaType; /** - * The some source code is scratched from org.springframework.web.servlet.mvc.condition.AbstractMediaTypeExpression + * The some source code is scratched from + * org.springframework.web.servlet.mvc.condition.AbstractMediaTypeExpression * * @author Arjen Poutsma * @author Rossen Stoyanchev * @author Mercy */ -public class AbstractMediaTypeExpression implements MediaTypeExpression, Comparable { +public class AbstractMediaTypeExpression + implements MediaTypeExpression, Comparable { - private final MediaType mediaType; + private final MediaType mediaType; - private final boolean negated; + private final boolean negated; - AbstractMediaTypeExpression(String expression) { - if (expression.startsWith("!")) { - this.negated = true; - expression = expression.substring(1); - } else { - this.negated = false; - } - this.mediaType = MediaType.parseMediaType(expression); - } + AbstractMediaTypeExpression(String expression) { + if (expression.startsWith("!")) { + this.negated = true; + expression = expression.substring(1); + } + else { + this.negated = false; + } + this.mediaType = MediaType.parseMediaType(expression); + } - AbstractMediaTypeExpression(MediaType mediaType, boolean negated) { - this.mediaType = mediaType; - this.negated = negated; - } + AbstractMediaTypeExpression(MediaType mediaType, boolean negated) { + this.mediaType = mediaType; + this.negated = negated; + } - @Override - public MediaType getMediaType() { - return this.mediaType; - } + @Override + public MediaType getMediaType() { + return this.mediaType; + } - @Override - public boolean isNegated() { - return this.negated; - } + @Override + public boolean isNegated() { + return this.negated; + } + @Override + public int compareTo(AbstractMediaTypeExpression other) { + return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), + other.getMediaType()); + } - @Override - public int compareTo(AbstractMediaTypeExpression other) { - return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType()); - } + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + AbstractMediaTypeExpression otherExpr = (AbstractMediaTypeExpression) other; + return (this.mediaType.equals(otherExpr.mediaType) + && this.negated == otherExpr.negated); + } - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - AbstractMediaTypeExpression otherExpr = (AbstractMediaTypeExpression) other; - return (this.mediaType.equals(otherExpr.mediaType) && this.negated == otherExpr.negated); - } + @Override + public int hashCode() { + return this.mediaType.hashCode(); + } - @Override - public int hashCode() { - return this.mediaType.hashCode(); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (this.negated) { - builder.append('!'); - } - builder.append(this.mediaType.toString()); - return builder.toString(); - } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (this.negated) { + builder.append('!'); + } + builder.append(this.mediaType.toString()); + return builder.toString(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java index 877a7aa08..fe50e187c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java @@ -16,14 +16,15 @@ */ package com.alibaba.cloud.dubbo.http.matcher; +import static org.springframework.util.StringUtils.trimWhitespace; + import org.springframework.http.HttpRequest; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; -import static org.springframework.util.StringUtils.trimWhitespace; - /** - * The some source code is scratched from org.springframework.web.servlet.mvc.condition.AbstractNameValueExpression + * The some source code is scratched from + * org.springframework.web.servlet.mvc.condition.AbstractNameValueExpression * * @author Rossen Stoyanchev * @author Arjen Poutsma @@ -31,116 +32,123 @@ import static org.springframework.util.StringUtils.trimWhitespace; */ abstract class AbstractNameValueExpression implements NameValueExpression { - protected final String name; - - protected final T value; - - protected final boolean negated; - - AbstractNameValueExpression(String expression) { - int separator = expression.indexOf('='); - if (separator == -1) { - this.negated = expression.startsWith("!"); - this.name = trimWhitespace((this.negated ? expression.substring(1) : expression)); - this.value = null; - } else { - this.negated = (separator > 0) && (expression.charAt(separator - 1) == '!'); - this.name = trimWhitespace((this.negated ? expression.substring(0, separator - 1) - : expression.substring(0, separator))); - String valueExpression = getValueExpression(expression, separator); - this.value = isExcludedValue(valueExpression) ? null : parseValue(valueExpression); - } - } - - private String getValueExpression(String expression, int separator) { - return trimWhitespace(expression.substring(separator + 1)); - } - - /** - * Exclude the pattern value Expression: "{value}", subclass could override this method. - * - * @param valueExpression - * @return - */ - protected boolean isExcludedValue(String valueExpression) { - return StringUtils.hasText(valueExpression) && - valueExpression.startsWith("{") - && valueExpression.endsWith("}"); - } - - @Override - public String getName() { - return this.name; - } - - @Override - public T getValue() { - return this.value; - } - - @Override - public boolean isNegated() { - return this.negated; - } - - public final boolean match(HttpRequest request) { - boolean isMatch; - if (this.value != null) { - isMatch = matchValue(request); - } else { - isMatch = matchName(request); - } - return (this.negated ? !isMatch : isMatch); - } - - - protected abstract boolean isCaseSensitiveName(); - - protected abstract T parseValue(String valueExpression); - - protected abstract boolean matchName(HttpRequest request); - - protected abstract boolean matchValue(HttpRequest request); - - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - AbstractNameValueExpression that = (AbstractNameValueExpression) other; - return ((isCaseSensitiveName() ? this.name.equals(that.name) : this.name.equalsIgnoreCase(that.name)) && - ObjectUtils.nullSafeEquals(this.value, that.value) && this.negated == that.negated); - } - - @Override - public int hashCode() { - int result = (isCaseSensitiveName() ? this.name.hashCode() : this.name.toLowerCase().hashCode()); - result = 31 * result + (this.value != null ? this.value.hashCode() : 0); - result = 31 * result + (this.negated ? 1 : 0); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (this.value != null) { - builder.append(this.name); - if (this.negated) { - builder.append('!'); - } - builder.append('='); - builder.append(this.value); - } else { - if (this.negated) { - builder.append('!'); - } - builder.append(this.name); - } - return builder.toString(); - } + protected final String name; + + protected final T value; + + protected final boolean negated; + + AbstractNameValueExpression(String expression) { + int separator = expression.indexOf('='); + if (separator == -1) { + this.negated = expression.startsWith("!"); + this.name = trimWhitespace( + (this.negated ? expression.substring(1) : expression)); + this.value = null; + } + else { + this.negated = (separator > 0) && (expression.charAt(separator - 1) == '!'); + this.name = trimWhitespace( + (this.negated ? expression.substring(0, separator - 1) + : expression.substring(0, separator))); + String valueExpression = getValueExpression(expression, separator); + this.value = isExcludedValue(valueExpression) ? null + : parseValue(valueExpression); + } + } + + private String getValueExpression(String expression, int separator) { + return trimWhitespace(expression.substring(separator + 1)); + } + + /** + * Exclude the pattern value Expression: "{value}", subclass could override this + * method. + * + * @param valueExpression + * @return + */ + protected boolean isExcludedValue(String valueExpression) { + return StringUtils.hasText(valueExpression) && valueExpression.startsWith("{") + && valueExpression.endsWith("}"); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public T getValue() { + return this.value; + } + + @Override + public boolean isNegated() { + return this.negated; + } + + public final boolean match(HttpRequest request) { + boolean isMatch; + if (this.value != null) { + isMatch = matchValue(request); + } + else { + isMatch = matchName(request); + } + return (this.negated ? !isMatch : isMatch); + } + + protected abstract boolean isCaseSensitiveName(); + + protected abstract T parseValue(String valueExpression); + + protected abstract boolean matchName(HttpRequest request); + + protected abstract boolean matchValue(HttpRequest request); + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + AbstractNameValueExpression that = (AbstractNameValueExpression) other; + return ((isCaseSensitiveName() ? this.name.equals(that.name) + : this.name.equalsIgnoreCase(that.name)) + && ObjectUtils.nullSafeEquals(this.value, that.value) + && this.negated == that.negated); + } + + @Override + public int hashCode() { + int result = (isCaseSensitiveName() ? this.name.hashCode() + : this.name.toLowerCase().hashCode()); + result = 31 * result + (this.value != null ? this.value.hashCode() : 0); + result = 31 * result + (this.negated ? 1 : 0); + return result; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (this.value != null) { + builder.append(this.name); + if (this.negated) { + builder.append('!'); + } + builder.append('='); + builder.append(this.value); + } + else { + if (this.negated) { + builder.append('!'); + } + builder.append(this.name); + } + return builder.toString(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java index 255a8829a..2e6347320 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpRequest; - import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import org.springframework.http.HttpRequest; + /** * Composite {@link HttpRequestMatcher} implementation * @@ -30,44 +30,44 @@ import java.util.List; */ public abstract class CompositeHttpRequestMatcher extends AbstractHttpRequestMatcher { - private final List matchers = new LinkedList<>(); + private final List matchers = new LinkedList<>(); - public CompositeHttpRequestMatcher(HttpRequestMatcher... matchers) { - this.matchers.addAll(Arrays.asList(matchers)); - } + public CompositeHttpRequestMatcher(HttpRequestMatcher... matchers) { + this.matchers.addAll(Arrays.asList(matchers)); + } - public CompositeHttpRequestMatcher and(HttpRequestMatcher matcher) { - this.matchers.add(matcher); - return this; - } + public CompositeHttpRequestMatcher and(HttpRequestMatcher matcher) { + this.matchers.add(matcher); + return this; + } - @Override - public boolean match(HttpRequest request) { - for (HttpRequestMatcher matcher : matchers) { - if (!matcher.match(request)) { - return false; - } - } - return true; - } + @Override + public boolean match(HttpRequest request) { + for (HttpRequestMatcher matcher : matchers) { + if (!matcher.match(request)) { + return false; + } + } + return true; + } - protected List getMatchers() { - return this.matchers; - } + protected List getMatchers() { + return this.matchers; + } - @Override - protected Collection getContent() { - List content = new LinkedList<>(); - for (HttpRequestMatcher matcher : getMatchers()) { - if (matcher instanceof AbstractHttpRequestMatcher) { - content.addAll(((AbstractHttpRequestMatcher) matcher).getContent()); - } - } - return content; - } + @Override + protected Collection getContent() { + List content = new LinkedList<>(); + for (HttpRequestMatcher matcher : getMatchers()) { + if (matcher instanceof AbstractHttpRequestMatcher) { + content.addAll(((AbstractHttpRequestMatcher) matcher).getContent()); + } + } + return content; + } - @Override - protected String getToStringInfix() { - return " && "; - } + @Override + protected String getToStringInfix() { + return " && "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpression.java index 33f39a2ac..e34c394a8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpression.java @@ -29,16 +29,16 @@ import org.springframework.http.MediaType; */ class ConsumeMediaTypeExpression extends AbstractMediaTypeExpression { - ConsumeMediaTypeExpression(String expression) { - super(expression); - } + ConsumeMediaTypeExpression(String expression) { + super(expression); + } - ConsumeMediaTypeExpression(MediaType mediaType, boolean negated) { - super(mediaType, negated); - } + ConsumeMediaTypeExpression(MediaType mediaType, boolean negated) { + super(mediaType, negated); + } - public final boolean match(MediaType contentType) { - boolean match = getMediaType().includes(contentType); - return (!isNegated() ? match : !match); - } + public final boolean match(MediaType contentType) { + boolean match = getMediaType().includes(contentType); + return (!isNegated() ? match : !match); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpression.java index 12a85bc07..1f2e80cfb 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpression.java @@ -23,7 +23,8 @@ import org.springframework.util.ObjectUtils; /** * Parses and matches a single header expression to a request. *

- * The some source code is scratched from org.springframework.web.servlet.mvc.condition.HeadersRequestCondition.HeaderExpression + * The some source code is scratched from + * org.springframework.web.servlet.mvc.condition.HeadersRequestCondition.HeaderExpression * * @author Arjen Poutsma * @author Rossen Stoyanchev @@ -31,30 +32,30 @@ import org.springframework.util.ObjectUtils; */ class HeaderExpression extends AbstractNameValueExpression { - HeaderExpression(String expression) { - super(expression); - } + HeaderExpression(String expression) { + super(expression); + } - @Override - protected boolean isCaseSensitiveName() { - return false; - } + @Override + protected boolean isCaseSensitiveName() { + return false; + } - @Override - protected String parseValue(String valueExpression) { - return valueExpression; - } + @Override + protected String parseValue(String valueExpression) { + return valueExpression; + } - @Override - protected boolean matchName(HttpRequest request) { - HttpHeaders httpHeaders = request.getHeaders(); - return httpHeaders.containsKey(this.name); - } + @Override + protected boolean matchName(HttpRequest request) { + HttpHeaders httpHeaders = request.getHeaders(); + return httpHeaders.containsKey(this.name); + } - @Override - protected boolean matchValue(HttpRequest request) { - HttpHeaders httpHeaders = request.getHeaders(); - String headerValue = httpHeaders.getFirst(this.name); - return ObjectUtils.nullSafeEquals(this.value, headerValue); - } + @Override + protected boolean matchValue(HttpRequest request) { + HttpHeaders httpHeaders = request.getHeaders(); + String headerValue = httpHeaders.getFirst(this.name); + return ObjectUtils.nullSafeEquals(this.value, headerValue); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java index 35f58a9bc..aa160e295 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java @@ -16,10 +16,6 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpRequest; -import org.springframework.http.MediaType; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -27,6 +23,10 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; +import org.springframework.http.MediaType; + /** * {@link HttpRequest} 'Content-Type' header {@link HttpRequestMatcher matcher} * @@ -36,88 +36,91 @@ import java.util.Set; */ public class HttpRequestConsumersMatcher extends AbstractHttpRequestMatcher { - private final List expressions; - - /** - * Creates a new instance from 0 or more "consumes" expressions. - * - * @param consumes consumes expressions if 0 expressions are provided, - * the condition will match to every request - */ - public HttpRequestConsumersMatcher(String... consumes) { - this(consumes, null); - } - - /** - * Creates a new instance with "consumes" and "header" expressions. - * "Header" expressions where the header name is not 'Content-Type' or have - * no header value defined are ignored. If 0 expressions are provided in - * total, the condition will match to every request - * - * @param consumes consumes expressions - * @param headers headers expressions - */ - public HttpRequestConsumersMatcher(String[] consumes, String[] headers) { - this(parseExpressions(consumes, headers)); - } - - /** - * Private constructor accepting parsed media type expressions. - */ - private HttpRequestConsumersMatcher(Collection expressions) { - this.expressions = new ArrayList<>(expressions); - Collections.sort(this.expressions); - } - - private static Set parseExpressions(String[] consumes, String[] headers) { - Set result = new LinkedHashSet<>(); - if (headers != null) { - for (String header : headers) { - HeaderExpression expr = new HeaderExpression(header); - if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) { - for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) { - result.add(new ConsumeMediaTypeExpression(mediaType, expr.negated)); - } - } - } - } - for (String consume : consumes) { - result.add(new ConsumeMediaTypeExpression(consume)); - } - return result; - } - - @Override - public boolean match(HttpRequest request) { - - if (expressions.isEmpty()) { - return true; - } - - HttpHeaders httpHeaders = request.getHeaders(); - - MediaType contentType = httpHeaders.getContentType(); - - if (contentType == null) { - contentType = MediaType.APPLICATION_OCTET_STREAM; - } - - for (ConsumeMediaTypeExpression expression : expressions) { - if (!expression.match(contentType)) { - return false; - } - } - - return true; - } - - @Override - protected Collection getContent() { - return this.expressions; - } - - @Override - protected String getToStringInfix() { - return " || "; - } + private final List expressions; + + /** + * Creates a new instance from 0 or more "consumes" expressions. + * + * @param consumes consumes expressions if 0 expressions are provided, the condition + * will match to every request + */ + public HttpRequestConsumersMatcher(String... consumes) { + this(consumes, null); + } + + /** + * Creates a new instance with "consumes" and "header" expressions. "Header" + * expressions where the header name is not 'Content-Type' or have no header value + * defined are ignored. If 0 expressions are provided in total, the condition will + * match to every request + * + * @param consumes consumes expressions + * @param headers headers expressions + */ + public HttpRequestConsumersMatcher(String[] consumes, String[] headers) { + this(parseExpressions(consumes, headers)); + } + + /** + * Private constructor accepting parsed media type expressions. + */ + private HttpRequestConsumersMatcher( + Collection expressions) { + this.expressions = new ArrayList<>(expressions); + Collections.sort(this.expressions); + } + + private static Set parseExpressions(String[] consumes, + String[] headers) { + Set result = new LinkedHashSet<>(); + if (headers != null) { + for (String header : headers) { + HeaderExpression expr = new HeaderExpression(header); + if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) { + for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) { + result.add( + new ConsumeMediaTypeExpression(mediaType, expr.negated)); + } + } + } + } + for (String consume : consumes) { + result.add(new ConsumeMediaTypeExpression(consume)); + } + return result; + } + + @Override + public boolean match(HttpRequest request) { + + if (expressions.isEmpty()) { + return true; + } + + HttpHeaders httpHeaders = request.getHeaders(); + + MediaType contentType = httpHeaders.getContentType(); + + if (contentType == null) { + contentType = MediaType.APPLICATION_OCTET_STREAM; + } + + for (ConsumeMediaTypeExpression expression : expressions) { + if (!expression.match(contentType)) { + return false; + } + } + + return true; + } + + @Override + protected Collection getContent() { + return this.expressions; + } + + @Override + protected String getToStringInfix() { + return " || "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestHeadersMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestHeadersMatcher.java index b83a02b04..8ad427e49 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestHeadersMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestHeadersMatcher.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpRequest; - import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; + /** * {@link HttpRequest} headers {@link HttpRequestMatcher matcher} * @@ -30,42 +30,42 @@ import java.util.Set; */ public class HttpRequestHeadersMatcher extends AbstractHttpRequestMatcher { - private final Set expressions; + private final Set expressions; - public HttpRequestHeadersMatcher(String... headers) { - this.expressions = parseExpressions(headers); - } + public HttpRequestHeadersMatcher(String... headers) { + this.expressions = parseExpressions(headers); + } - private static Set parseExpressions(String... headers) { - Set expressions = new LinkedHashSet<>(); - for (String header : headers) { - HeaderExpression expr = new HeaderExpression(header); - if (HttpHeaders.ACCEPT.equalsIgnoreCase(expr.name) || - HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(expr.name)) { - continue; - } - expressions.add(expr); - } - return expressions; - } + private static Set parseExpressions(String... headers) { + Set expressions = new LinkedHashSet<>(); + for (String header : headers) { + HeaderExpression expr = new HeaderExpression(header); + if (HttpHeaders.ACCEPT.equalsIgnoreCase(expr.name) + || HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(expr.name)) { + continue; + } + expressions.add(expr); + } + return expressions; + } - @Override - public boolean match(HttpRequest request) { - for (HeaderExpression expression : this.expressions) { - if (!expression.match(request)) { - return false; - } - } - return true; - } + @Override + public boolean match(HttpRequest request) { + for (HeaderExpression expression : this.expressions) { + if (!expression.match(request)) { + return false; + } + } + return true; + } - @Override - protected Collection getContent() { - return this.expressions; - } + @Override + protected Collection getContent() { + return this.expressions; + } - @Override - protected String getToStringInfix() { - return " && "; - } + @Override + protected String getToStringInfix() { + return " && "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMatcher.java index 85606f2a5..d53536b92 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMatcher.java @@ -25,11 +25,11 @@ import org.springframework.http.HttpRequest; */ public interface HttpRequestMatcher { - /** - * Match {@link HttpRequest} or not - * - * @param request The {@link HttpRequest} instance - * @return if matched, return true, or false. - */ - boolean match(HttpRequest request); + /** + * Match {@link HttpRequest} or not + * + * @param request The {@link HttpRequest} instance + * @return if matched, return true, or false. + */ + boolean match(HttpRequest request); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcher.java index 88a323942..d520f792d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcher.java @@ -16,15 +16,15 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpRequest; -import org.springframework.util.StringUtils; +import static org.springframework.http.HttpMethod.resolve; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; -import static org.springframework.http.HttpMethod.resolve; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.util.StringUtils; /** * {@link HttpRequest} {@link HttpMethod methods} {@link HttpRequestMatcher matcher} @@ -33,50 +33,50 @@ import static org.springframework.http.HttpMethod.resolve; */ public class HttpRequestMethodsMatcher extends AbstractHttpRequestMatcher { - private final Set methods; + private final Set methods; - public HttpRequestMethodsMatcher(String... methods) { - this.methods = resolveHttpMethods(methods); - } + public HttpRequestMethodsMatcher(String... methods) { + this.methods = resolveHttpMethods(methods); + } - private Set resolveHttpMethods(String[] methods) { - Set httpMethods = new LinkedHashSet<>(methods.length); - for (String method : methods) { - if (!StringUtils.hasText(method)) { - continue; - } - HttpMethod httpMethod = resolve(method); - httpMethods.add(httpMethod); - } - return httpMethods; - } + private Set resolveHttpMethods(String[] methods) { + Set httpMethods = new LinkedHashSet<>(methods.length); + for (String method : methods) { + if (!StringUtils.hasText(method)) { + continue; + } + HttpMethod httpMethod = resolve(method); + httpMethods.add(httpMethod); + } + return httpMethods; + } - public Set getMethods() { - return methods; - } + public Set getMethods() { + return methods; + } - @Override - public boolean match(HttpRequest request) { - boolean matched = false; - HttpMethod httpMethod = request.getMethod(); - if (httpMethod != null) { - for (HttpMethod method : getMethods()) { - if (httpMethod.equals(method)) { - matched = true; - break; - } - } - } - return matched; - } + @Override + public boolean match(HttpRequest request) { + boolean matched = false; + HttpMethod httpMethod = request.getMethod(); + if (httpMethod != null) { + for (HttpMethod method : getMethods()) { + if (httpMethod.equals(method)) { + matched = true; + break; + } + } + } + return matched; + } - @Override - protected Collection getContent() { - return methods; - } + @Override + protected Collection getContent() { + return methods; + } - @Override - protected String getToStringInfix() { - return " || "; - } + @Override + protected String getToStringInfix() { + return " || "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java index 234431435..01cafdfd0 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpRequest; -import org.springframework.util.CollectionUtils; - import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.http.HttpRequest; +import org.springframework.util.CollectionUtils; + /** * {@link HttpRequest} parameters {@link HttpRequestMatcher matcher} * @@ -30,47 +30,47 @@ import java.util.Set; */ public class HttpRequestParamsMatcher extends AbstractHttpRequestMatcher { - private final Set expressions; + private final Set expressions; - /** - * @param params The pattern of params : - *

    - *
  • name=value
  • - *
  • name
  • - *
- */ - public HttpRequestParamsMatcher(String... params) { - this.expressions = parseExpressions(params); - } + /** + * @param params The pattern of params : + *
    + *
  • name=value
  • + *
  • name
  • + *
+ */ + public HttpRequestParamsMatcher(String... params) { + this.expressions = parseExpressions(params); + } - private static Set parseExpressions(String... params) { - Set expressions = new LinkedHashSet<>(); - for (String param : params) { - expressions.add(new ParamExpression(param)); - } - return expressions; - } + private static Set parseExpressions(String... params) { + Set expressions = new LinkedHashSet<>(); + for (String param : params) { + expressions.add(new ParamExpression(param)); + } + return expressions; + } - @Override - public boolean match(HttpRequest request) { - if (CollectionUtils.isEmpty(expressions)) { - return true; - } - for (ParamExpression paramExpression : expressions) { - if (paramExpression.match(request)) { - return true; - } - } - return false; - } + @Override + public boolean match(HttpRequest request) { + if (CollectionUtils.isEmpty(expressions)) { + return true; + } + for (ParamExpression paramExpression : expressions) { + if (paramExpression.match(request)) { + return true; + } + } + return false; + } - @Override - protected Collection getContent() { - return this.expressions; - } + @Override + protected Collection getContent() { + return this.expressions; + } - @Override - protected String getToStringInfix() { - return " && "; - } + @Override + protected String getToStringInfix() { + return " && "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java index 64443511c..1d2a2264e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java @@ -16,11 +16,6 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpRequest; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.PathMatcher; -import org.springframework.util.StringUtils; - import java.net.URI; import java.util.ArrayList; import java.util.Collection; @@ -29,6 +24,11 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.springframework.http.HttpRequest; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; +import org.springframework.util.StringUtils; + /** * {@link HttpRequest} {@link URI} {@link HttpRequestMatcher matcher} * @@ -36,82 +36,82 @@ import java.util.Set; */ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher { - private final Set patterns; + private final Set patterns; - private final PathMatcher pathMatcher; + private final PathMatcher pathMatcher; - public HttpRequestPathMatcher(String... patterns) { - this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns)); - this.pathMatcher = new AntPathMatcher(); - } + public HttpRequestPathMatcher(String... patterns) { + this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns)); + this.pathMatcher = new AntPathMatcher(); + } - private static Set prependLeadingSlash(String[] patterns) { - Set result = new LinkedHashSet<>(patterns.length); - for (String pattern : patterns) { - if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) { - pattern = "/" + pattern; - } - result.add(pattern); - } - return result; - } + private static Set prependLeadingSlash(String[] patterns) { + Set result = new LinkedHashSet<>(patterns.length); + for (String pattern : patterns) { + if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) { + pattern = "/" + pattern; + } + result.add(pattern); + } + return result; + } - @Override - public boolean match(HttpRequest request) { - List matches = getMatchingPatterns(request); - return !matches.isEmpty(); - } + @Override + public boolean match(HttpRequest request) { + List matches = getMatchingPatterns(request); + return !matches.isEmpty(); + } - public List getMatchingPatterns(HttpRequest request) { - String path = getPath(request); - List matches = getMatchingPatterns(path); - return matches; - } + public List getMatchingPatterns(HttpRequest request) { + String path = getPath(request); + List matches = getMatchingPatterns(path); + return matches; + } - public List getMatchingPatterns(String lookupPath) { - List matches = new ArrayList<>(); - for (String pattern : this.patterns) { - String match = getMatchingPattern(pattern, lookupPath); - if (match != null) { - matches.add(match); - } - } - if (matches.size() > 1) { - matches.sort(this.pathMatcher.getPatternComparator(lookupPath)); - } - return matches; - } + public List getMatchingPatterns(String lookupPath) { + List matches = new ArrayList<>(); + for (String pattern : this.patterns) { + String match = getMatchingPattern(pattern, lookupPath); + if (match != null) { + matches.add(match); + } + } + if (matches.size() > 1) { + matches.sort(this.pathMatcher.getPatternComparator(lookupPath)); + } + return matches; + } - private String getMatchingPattern(String pattern, String lookupPath) { - if (pattern.equals(lookupPath)) { - return pattern; - } - boolean hasSuffix = pattern.indexOf('.') != -1; - if (!hasSuffix && this.pathMatcher.match(pattern + ".*", lookupPath)) { - return pattern + ".*"; - } - if (this.pathMatcher.match(pattern, lookupPath)) { - return pattern; - } + private String getMatchingPattern(String pattern, String lookupPath) { + if (pattern.equals(lookupPath)) { + return pattern; + } + boolean hasSuffix = pattern.indexOf('.') != -1; + if (!hasSuffix && this.pathMatcher.match(pattern + ".*", lookupPath)) { + return pattern + ".*"; + } + if (this.pathMatcher.match(pattern, lookupPath)) { + return pattern; + } - if (!pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath)) { - return pattern + "/"; - } - return null; - } + if (!pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath)) { + return pattern + "/"; + } + return null; + } - private String getPath(HttpRequest request) { - URI uri = request.getURI(); - return uri.getPath(); - } + private String getPath(HttpRequest request) { + URI uri = request.getURI(); + return uri.getPath(); + } - @Override - protected Collection getContent() { - return this.patterns; - } + @Override + protected Collection getContent() { + return this.patterns; + } - @Override - protected String getToStringInfix() { - return " || "; - } + @Override + protected String getToStringInfix() { + return " || "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java index f99297778..ea949aed9 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java @@ -16,10 +16,6 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpRequest; -import org.springframework.http.MediaType; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -27,6 +23,10 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; +import org.springframework.http.MediaType; + /** * {@link HttpRequest} 'Accept' header {@link HttpRequestMatcher matcher} * @@ -36,84 +36,88 @@ import java.util.Set; */ public class HttpRequestProducesMatcher extends AbstractHttpRequestMatcher { - private final List expressions; - - /** - * Creates a new instance from "produces" expressions. If 0 expressions - * are provided in total, this condition will match to any request. - * - * @param produces produces expressions - */ - public HttpRequestProducesMatcher(String... produces) { - this(produces, null); - } - - /** - * Creates a new instance with "produces" and "header" expressions. "Header" - * expressions where the header name is not 'Accept' or have no header value - * defined are ignored. If 0 expressions are provided in total, this condition - * will match to any request. - * - * @param produces produces expressions - * @param headers headers expressions - */ - public HttpRequestProducesMatcher(String[] produces, String[] headers) { - this(parseExpressions(produces, headers)); - } - - /** - * Private constructor accepting parsed media type expressions. - */ - private HttpRequestProducesMatcher(Collection expressions) { - this.expressions = new ArrayList<>(expressions); - Collections.sort(this.expressions); - } - - private static Set parseExpressions(String[] produces, String[] headers) { - Set result = new LinkedHashSet<>(); - if (headers != null) { - for (String header : headers) { - HeaderExpression expr = new HeaderExpression(header); - if (HttpHeaders.ACCEPT.equalsIgnoreCase(expr.name) && expr.value != null) { - for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) { - result.add(new ProduceMediaTypeExpression(mediaType, expr.negated)); - } - } - } - } - for (String produce : produces) { - result.add(new ProduceMediaTypeExpression(produce)); - } - return result; - } - - @Override - public boolean match(HttpRequest request) { - - if (expressions.isEmpty()) { - return true; - } - - HttpHeaders httpHeaders = request.getHeaders(); - - List acceptedMediaTypes = httpHeaders.getAccept(); - - for (ProduceMediaTypeExpression expression : expressions) { - if (!expression.match(acceptedMediaTypes)) { - return false; - } - } - - return true; - } - - @Override - protected Collection getContent() { - return expressions; - } - - @Override - protected String getToStringInfix() { - return " || "; - } + private final List expressions; + + /** + * Creates a new instance from "produces" expressions. If 0 expressions are provided + * in total, this condition will match to any request. + * + * @param produces produces expressions + */ + public HttpRequestProducesMatcher(String... produces) { + this(produces, null); + } + + /** + * Creates a new instance with "produces" and "header" expressions. "Header" + * expressions where the header name is not 'Accept' or have no header value defined + * are ignored. If 0 expressions are provided in total, this condition will match to + * any request. + * + * @param produces produces expressions + * @param headers headers expressions + */ + public HttpRequestProducesMatcher(String[] produces, String[] headers) { + this(parseExpressions(produces, headers)); + } + + /** + * Private constructor accepting parsed media type expressions. + */ + private HttpRequestProducesMatcher( + Collection expressions) { + this.expressions = new ArrayList<>(expressions); + Collections.sort(this.expressions); + } + + private static Set parseExpressions(String[] produces, + String[] headers) { + Set result = new LinkedHashSet<>(); + if (headers != null) { + for (String header : headers) { + HeaderExpression expr = new HeaderExpression(header); + if (HttpHeaders.ACCEPT.equalsIgnoreCase(expr.name) + && expr.value != null) { + for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) { + result.add( + new ProduceMediaTypeExpression(mediaType, expr.negated)); + } + } + } + } + for (String produce : produces) { + result.add(new ProduceMediaTypeExpression(produce)); + } + return result; + } + + @Override + public boolean match(HttpRequest request) { + + if (expressions.isEmpty()) { + return true; + } + + HttpHeaders httpHeaders = request.getHeaders(); + + List acceptedMediaTypes = httpHeaders.getAccept(); + + for (ProduceMediaTypeExpression expression : expressions) { + if (!expression.match(acceptedMediaTypes)) { + return false; + } + } + + return true; + } + + @Override + protected Collection getContent() { + return expressions; + } + + @Override + protected String getToStringInfix() { + return " || "; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/MediaTypeExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/MediaTypeExpression.java index 61244f0ad..5f33de347 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/MediaTypeExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/MediaTypeExpression.java @@ -19,17 +19,18 @@ package com.alibaba.cloud.dubbo.http.matcher; import org.springframework.http.MediaType; /** - * A contract for media type expressions (e.g. "text/plain", "!text/plain") as - * defined in the for "consumes" and "produces". + * A contract for media type expressions (e.g. "text/plain", "!text/plain") as defined in + * the for "consumes" and "produces". *

- * The source code is scratched from org.springframework.web.servlet.mvc.condition.MediaTypeExpression + * The source code is scratched from + * org.springframework.web.servlet.mvc.condition.MediaTypeExpression * * @author Rossen Stoyanchev */ interface MediaTypeExpression { - MediaType getMediaType(); + MediaType getMediaType(); - boolean isNegated(); + boolean isNegated(); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/NameValueExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/NameValueExpression.java index 1da0b2fab..bbf3a96af 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/NameValueExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/NameValueExpression.java @@ -16,12 +16,12 @@ */ package com.alibaba.cloud.dubbo.http.matcher; - /** * A contract for {@code "name!=value"} style expression used to specify request * parameters and request header in HTTP request *

- * The some source code is scratched from org.springframework.web.servlet.mvc.condition.NameValueExpression + * The some source code is scratched from + * org.springframework.web.servlet.mvc.condition.NameValueExpression * * @param the value type * @author Rossen Stoyanchev @@ -29,10 +29,10 @@ package com.alibaba.cloud.dubbo.http.matcher; */ interface NameValueExpression { - String getName(); + String getName(); - T getValue(); + T getValue(); - boolean isNegated(); + boolean isNegated(); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpression.java index 8d14cd7ba..555d1d577 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpression.java @@ -16,16 +16,17 @@ */ package com.alibaba.cloud.dubbo.http.matcher; +import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters; + import org.springframework.http.HttpRequest; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; -import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters; - /** * Parses and matches a single param expression to a request. *

- * The some source code is scratched from org.springframework.web.servlet.mvc.condition.ParamsRequestCondition.ParamExpression + * The some source code is scratched from + * org.springframework.web.servlet.mvc.condition.ParamsRequestCondition.ParamExpression * * @author Arjen Poutsma * @author Rossen Stoyanchev @@ -33,30 +34,30 @@ import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters; */ class ParamExpression extends AbstractNameValueExpression { - ParamExpression(String expression) { - super(expression); - } - - @Override - protected boolean isCaseSensitiveName() { - return true; - } - - @Override - protected String parseValue(String valueExpression) { - return valueExpression; - } - - @Override - protected boolean matchName(HttpRequest request) { - MultiValueMap parametersMap = getParameters(request); - return parametersMap.containsKey(this.name); - } - - @Override - protected boolean matchValue(HttpRequest request) { - MultiValueMap parametersMap = getParameters(request); - String parameterValue = parametersMap.getFirst(this.name); - return ObjectUtils.nullSafeEquals(this.value, parameterValue); - } + ParamExpression(String expression) { + super(expression); + } + + @Override + protected boolean isCaseSensitiveName() { + return true; + } + + @Override + protected String parseValue(String valueExpression) { + return valueExpression; + } + + @Override + protected boolean matchName(HttpRequest request) { + MultiValueMap parametersMap = getParameters(request); + return parametersMap.containsKey(this.name); + } + + @Override + protected boolean matchValue(HttpRequest request) { + MultiValueMap parametersMap = getParameters(request); + String parameterValue = parametersMap.getFirst(this.name); + return ObjectUtils.nullSafeEquals(this.value, parameterValue); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpression.java index d9830695b..7b9cfe3fc 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpression.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpression.java @@ -16,10 +16,10 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import org.springframework.http.MediaType; - import java.util.List; +import org.springframework.http.MediaType; + /** * Parses and matches a single media type expression to a request's 'Accept' header. *

@@ -31,25 +31,25 @@ import java.util.List; */ class ProduceMediaTypeExpression extends AbstractMediaTypeExpression { - ProduceMediaTypeExpression(String expression) { - super(expression); - } + ProduceMediaTypeExpression(String expression) { + super(expression); + } - ProduceMediaTypeExpression(MediaType mediaType, boolean negated) { - super(mediaType, negated); - } + ProduceMediaTypeExpression(MediaType mediaType, boolean negated) { + super(mediaType, negated); + } - public final boolean match(List acceptedMediaTypes) { - boolean match = matchMediaType(acceptedMediaTypes); - return (!isNegated() ? match : !match); - } + public final boolean match(List acceptedMediaTypes) { + boolean match = matchMediaType(acceptedMediaTypes); + return (!isNegated() ? match : !match); + } - private boolean matchMediaType(List acceptedMediaTypes) { - for (MediaType acceptedMediaType : acceptedMediaTypes) { - if (getMediaType().isCompatibleWith(acceptedMediaType)) { - return true; - } - } - return false; - } + private boolean matchMediaType(List acceptedMediaTypes) { + for (MediaType acceptedMediaType : acceptedMediaTypes) { + if (getMediaType().isCompatibleWith(acceptedMediaType)) { + return true; + } + } + return false; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/RequestMetadataMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/RequestMetadataMatcher.java index 1f1b5b8e3..0385bd34b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/RequestMetadataMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/RequestMetadataMatcher.java @@ -16,10 +16,10 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import com.alibaba.cloud.dubbo.metadata.RequestMetadata; - import static com.alibaba.cloud.dubbo.http.util.HttpUtils.toNameAndValues; +import com.alibaba.cloud.dubbo.metadata.RequestMetadata; + /** * {@link RequestMetadata} {@link HttpRequestMatcher} implementation * @@ -27,20 +27,21 @@ import static com.alibaba.cloud.dubbo.http.util.HttpUtils.toNameAndValues; */ public class RequestMetadataMatcher extends CompositeHttpRequestMatcher { - public RequestMetadataMatcher(RequestMetadata metadata) { - super( - // method - new HttpRequestMethodsMatcher(metadata.getMethod()), - // url - new HttpRequestPathMatcher(metadata.getPath()), - // params - new HttpRequestParamsMatcher(toNameAndValues(metadata.getParams())), - // headers - new HttpRequestHeadersMatcher(toNameAndValues(metadata.getHeaders())), - // consumes - new HttpRequestConsumersMatcher(metadata.getConsumes().toArray(new String[0])), - // produces - new HttpRequestProducesMatcher(metadata.getProduces().toArray(new String[0])) - ); - } + public RequestMetadataMatcher(RequestMetadata metadata) { + super( + // method + new HttpRequestMethodsMatcher(metadata.getMethod()), + // url + new HttpRequestPathMatcher(metadata.getPath()), + // params + new HttpRequestParamsMatcher(toNameAndValues(metadata.getParams())), + // headers + new HttpRequestHeadersMatcher(toNameAndValues(metadata.getHeaders())), + // consumes + new HttpRequestConsumersMatcher( + metadata.getConsumes().toArray(new String[0])), + // produces + new HttpRequestProducesMatcher( + metadata.getProduces().toArray(new String[0]))); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpMessageConverterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpMessageConverterResolver.java index a5488f625..e27b0df60 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpMessageConverterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpMessageConverterResolver.java @@ -16,9 +16,14 @@ */ package com.alibaba.cloud.dubbo.http.util; -import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder; -import com.alibaba.cloud.dubbo.metadata.RequestMetadata; -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; +import static java.util.Collections.unmodifiableList; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpRequest; @@ -30,13 +35,9 @@ import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import static java.util.Collections.unmodifiableList; +import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder; +import com.alibaba.cloud.dubbo.metadata.RequestMetadata; +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; /** * {@link HttpMessageConverter} Resolver @@ -45,184 +46,202 @@ import static java.util.Collections.unmodifiableList; */ public class HttpMessageConverterResolver { - private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType("application"); - - private final List> messageConverters; - - private final List allSupportedMediaTypes; - - private final ClassLoader classLoader; - - public HttpMessageConverterResolver(List> messageConverters, ClassLoader classLoader) { - this.messageConverters = messageConverters; - this.allSupportedMediaTypes = getAllSupportedMediaTypes(messageConverters); - 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 instanceof GenericHttpMessageConverter) { - GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; - if (genericConverter.canRead(parameterType, parameterType, contentType)) { - httpMessageConverterHolder = new HttpMessageConverterHolder(contentType, converter); - break; - } - } else { - if (converter.canRead(parameterType, contentType)) { - httpMessageConverterHolder = new HttpMessageConverterHolder(contentType, converter); - break; - } - } - - } - - return httpMessageConverterHolder; - } - - /** - * Resolve the most match {@link HttpMessageConverter} from {@link RequestMetadata} - * - * @param requestMetadata {@link RequestMetadata} - * @param restMethodMetadata {@link RestMethodMetadata} - * @return - */ - public HttpMessageConverterHolder resolve(RequestMetadata requestMetadata, RestMethodMetadata - restMethodMetadata) { - - HttpMessageConverterHolder httpMessageConverterHolder = null; - - Class returnValueClass = resolveReturnValueClass(restMethodMetadata); - - /** - * @see AbstractMessageConverterMethodProcessor#writeWithMessageConverters(Object, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse) - */ - List requestedMediaTypes = getAcceptableMediaTypes(requestMetadata); - List producibleMediaTypes = getProducibleMediaTypes(restMethodMetadata, returnValueClass); - - Set compatibleMediaTypes = new LinkedHashSet(); - for (MediaType requestedType : requestedMediaTypes) { - for (MediaType producibleType : producibleMediaTypes) { - if (requestedType.isCompatibleWith(producibleType)) { - compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType)); - } - } - } - - if (compatibleMediaTypes.isEmpty()) { - return httpMessageConverterHolder; - } - - List mediaTypes = new ArrayList<>(compatibleMediaTypes); - - MediaType.sortBySpecificityAndQuality(mediaTypes); - - MediaType selectedMediaType = null; - for (MediaType mediaType : mediaTypes) { - if (mediaType.isConcrete()) { - selectedMediaType = mediaType; - break; - } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { - selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; - break; - } - } - - if (selectedMediaType != null) { - selectedMediaType = selectedMediaType.removeQualityValue(); - for (HttpMessageConverter messageConverter : this.messageConverters) { - if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { - httpMessageConverterHolder = new HttpMessageConverterHolder(selectedMediaType, messageConverter); - break; - } - } - } - - return httpMessageConverterHolder; - } - - public List getAllSupportedMediaTypes() { - return unmodifiableList(allSupportedMediaTypes); - } - - private Class resolveReturnValueClass(RestMethodMetadata restMethodMetadata) { - String returnClassName = restMethodMetadata.getMethod().getReturnType(); - return ClassUtils.resolveClassName(returnClassName, classLoader); - } - - /** - * Resolve the {@link MediaType media-types} - * - * @param requestMetadata {@link RequestMetadata} from client side - * @return non-null {@link List} - */ - private List getAcceptableMediaTypes(RequestMetadata requestMetadata) { - return requestMetadata.getProduceMediaTypes(); - } - - /** - * Returns - * the media types that can be produced:

  • The producible media types specified in the request mappings, or - *
  • Media types of configured converters that can write the specific return value, or
  • {@link MediaType#ALL} - *
- * - * @param restMethodMetadata {@link RestMethodMetadata} from server side - * @param returnValueClass the class of return value - * @return non-null {@link List} - */ - private List getProducibleMediaTypes(RestMethodMetadata restMethodMetadata, Class - returnValueClass) { - RequestMetadata serverRequestMetadata = restMethodMetadata.getRequest(); - List mediaTypes = serverRequestMetadata.getProduceMediaTypes(); - if (!CollectionUtils.isEmpty(mediaTypes)) { // Empty - return mediaTypes; - } else if (!this.allSupportedMediaTypes.isEmpty()) { - List result = new ArrayList<>(); - for (HttpMessageConverter converter : this.messageConverters) { - if (converter.canWrite(returnValueClass, null)) { - result.addAll(converter.getSupportedMediaTypes()); - } - } - return result; - } else { - return Collections.singletonList(MediaType.ALL); - } - } - - /** - * Return the media types - * supported by all provided message converters sorted by specificity via {@link - * MediaType#sortBySpecificity(List)}. - * - * @param messageConverters - * @return - */ - private List getAllSupportedMediaTypes(List> messageConverters) { - Set allSupportedMediaTypes = new LinkedHashSet(); - for (HttpMessageConverter messageConverter : messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - } - List result = new ArrayList(allSupportedMediaTypes); - MediaType.sortBySpecificity(result); - return unmodifiableList(result); - } - - /** - * Return the more specific of the acceptable and the producible media types - * with the q-value of the former. - */ - private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) { - MediaType produceTypeToUse = produceType.copyQualityValue(acceptType); - return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceTypeToUse) <= 0 ? acceptType : produceTypeToUse); - } + private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType("application"); + + private final List> messageConverters; + + private final List allSupportedMediaTypes; + + private final ClassLoader classLoader; + + public HttpMessageConverterResolver(List> messageConverters, + ClassLoader classLoader) { + this.messageConverters = messageConverters; + this.allSupportedMediaTypes = getAllSupportedMediaTypes(messageConverters); + 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 instanceof GenericHttpMessageConverter) { + GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; + if (genericConverter.canRead(parameterType, parameterType, contentType)) { + httpMessageConverterHolder = new HttpMessageConverterHolder( + contentType, converter); + break; + } + } + else { + if (converter.canRead(parameterType, contentType)) { + httpMessageConverterHolder = new HttpMessageConverterHolder( + contentType, converter); + break; + } + } + + } + + return httpMessageConverterHolder; + } + + /** + * Resolve the most match {@link HttpMessageConverter} from {@link RequestMetadata} + * + * @param requestMetadata {@link RequestMetadata} + * @param restMethodMetadata {@link RestMethodMetadata} + * @return + */ + public HttpMessageConverterHolder resolve(RequestMetadata requestMetadata, + RestMethodMetadata restMethodMetadata) { + + HttpMessageConverterHolder httpMessageConverterHolder = null; + + Class returnValueClass = resolveReturnValueClass(restMethodMetadata); + + /** + * @see AbstractMessageConverterMethodProcessor#writeWithMessageConverters(Object, + * MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse) + */ + List requestedMediaTypes = getAcceptableMediaTypes(requestMetadata); + List producibleMediaTypes = getProducibleMediaTypes(restMethodMetadata, + returnValueClass); + + Set compatibleMediaTypes = new LinkedHashSet(); + for (MediaType requestedType : requestedMediaTypes) { + for (MediaType producibleType : producibleMediaTypes) { + if (requestedType.isCompatibleWith(producibleType)) { + compatibleMediaTypes + .add(getMostSpecificMediaType(requestedType, producibleType)); + } + } + } + + if (compatibleMediaTypes.isEmpty()) { + return httpMessageConverterHolder; + } + + List mediaTypes = new ArrayList<>(compatibleMediaTypes); + + MediaType.sortBySpecificityAndQuality(mediaTypes); + + MediaType selectedMediaType = null; + for (MediaType mediaType : mediaTypes) { + if (mediaType.isConcrete()) { + selectedMediaType = mediaType; + break; + } + else if (mediaType.equals(MediaType.ALL) + || mediaType.equals(MEDIA_TYPE_APPLICATION)) { + selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; + break; + } + } + + if (selectedMediaType != null) { + selectedMediaType = selectedMediaType.removeQualityValue(); + for (HttpMessageConverter messageConverter : this.messageConverters) { + if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { + httpMessageConverterHolder = new HttpMessageConverterHolder( + selectedMediaType, messageConverter); + break; + } + } + } + + return httpMessageConverterHolder; + } + + public List getAllSupportedMediaTypes() { + return unmodifiableList(allSupportedMediaTypes); + } + + private Class resolveReturnValueClass(RestMethodMetadata restMethodMetadata) { + String returnClassName = restMethodMetadata.getMethod().getReturnType(); + return ClassUtils.resolveClassName(returnClassName, classLoader); + } + + /** + * Resolve the {@link MediaType media-types} + * + * @param requestMetadata {@link RequestMetadata} from client side + * @return non-null {@link List} + */ + private List getAcceptableMediaTypes(RequestMetadata requestMetadata) { + return requestMetadata.getProduceMediaTypes(); + } + + /** + * Returns the media types that can be produced: + *
    + *
  • The producible media types specified in the request mappings, or + *
  • Media types of configured converters that can write the specific return value, + * or + *
  • {@link MediaType#ALL} + *
+ * + * @param restMethodMetadata {@link RestMethodMetadata} from server side + * @param returnValueClass the class of return value + * @return non-null {@link List} + */ + private List getProducibleMediaTypes(RestMethodMetadata restMethodMetadata, + Class returnValueClass) { + RequestMetadata serverRequestMetadata = restMethodMetadata.getRequest(); + List mediaTypes = serverRequestMetadata.getProduceMediaTypes(); + if (!CollectionUtils.isEmpty(mediaTypes)) { // Empty + return mediaTypes; + } + else if (!this.allSupportedMediaTypes.isEmpty()) { + List result = new ArrayList<>(); + for (HttpMessageConverter converter : this.messageConverters) { + if (converter.canWrite(returnValueClass, null)) { + result.addAll(converter.getSupportedMediaTypes()); + } + } + return result; + } + else { + return Collections.singletonList(MediaType.ALL); + } + } + + /** + * Return the media types supported by all provided message converters sorted by + * specificity via {@link MediaType#sortBySpecificity(List)}. + * + * @param messageConverters + * @return + */ + private List getAllSupportedMediaTypes( + List> messageConverters) { + Set allSupportedMediaTypes = new LinkedHashSet(); + for (HttpMessageConverter messageConverter : messageConverters) { + allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); + } + List result = new ArrayList(allSupportedMediaTypes); + MediaType.sortBySpecificity(result); + return unmodifiableList(result); + } + + /** + * Return the more specific of the acceptable and the producible media types with the + * q-value of the former. + */ + private MediaType getMostSpecificMediaType(MediaType acceptType, + MediaType produceType) { + MediaType produceTypeToUse = produceType.copyQualityValue(acceptType); + return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, + produceTypeToUse) <= 0 ? acceptType : produceTypeToUse); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpUtils.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpUtils.java index 202509dcb..30620cc5c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpUtils.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/util/HttpUtils.java @@ -16,10 +16,9 @@ */ package com.alibaba.cloud.dubbo.http.util; -import org.springframework.http.HttpRequest; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.util.StringUtils; +import static org.springframework.util.StringUtils.delimitedListToStringArray; +import static org.springframework.util.StringUtils.hasText; +import static org.springframework.util.StringUtils.trimAllWhitespace; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -31,9 +30,10 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static org.springframework.util.StringUtils.delimitedListToStringArray; -import static org.springframework.util.StringUtils.hasText; -import static org.springframework.util.StringUtils.trimAllWhitespace; +import org.springframework.http.HttpRequest; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; /** * Http Utilities class @@ -42,198 +42,206 @@ import static org.springframework.util.StringUtils.trimAllWhitespace; */ public abstract class HttpUtils { - private static final String UTF_8 = "UTF-8"; - - private static final String EQUAL = "="; - - private static final String AND = "&"; - - private static final String SEMICOLON = ";"; - - private static final String QUESTION_MASK = "?"; - - /** - * The empty value - */ - private static final String EMPTY_VALUE = ""; - - /** - * Normalize path: - *
    - *
  1. To remove query string if presents
  2. - *
  3. To remove duplicated slash("/") if exists
  4. - *
- * - * @param path path to be normalized - * @return a normalized path if required - */ - public static String normalizePath(String path) { - if (!hasText(path)) { - return path; - } - String normalizedPath = path; - int index = normalizedPath.indexOf(QUESTION_MASK); - if (index > -1) { - normalizedPath = normalizedPath.substring(0, index); - } - return StringUtils.replace(normalizedPath, "//", "/"); - } - - - /** - * Get Parameters from the specified {@link HttpRequest request} - * - * @param request the specified {@link HttpRequest request} - * @return - */ - public static MultiValueMap getParameters(HttpRequest request) { - URI uri = request.getURI(); - return getParameters(uri.getQuery()); - } - - /** - * Get Parameters from the specified query string. - *

- * - * @param queryString The query string - * @return The query parameters - */ - public static MultiValueMap getParameters(String queryString) { - return getParameters(delimitedListToStringArray(queryString, AND)); - } - - /** - * Get Parameters from the specified pairs of name-value. - *

- * - * @param pairs The pairs of name-value - * @return The query parameters - */ - public static MultiValueMap getParameters(Iterable pairs) { - MultiValueMap parameters = new LinkedMultiValueMap<>(); - if (pairs != null) { - for (String pair : pairs) { - String[] nameAndValue = delimitedListToStringArray(pair, EQUAL); - String name = decode(nameAndValue[0]); - String value = nameAndValue.length < 2 ? null : nameAndValue[1]; - value = decode(value); - addParam(parameters, name, value); - } - } - return parameters; - } - - /** - * Get Parameters from the specified pairs of name-value. - *

- * - * @param pairs The pairs of name-value - * @return The query parameters - */ - public static MultiValueMap getParameters(String... pairs) { - return getParameters(Arrays.asList(pairs)); - } - -// /** -// * Parse a read-only {@link MultiValueMap} of {@link HttpCookie} from {@link HttpHeaders} -// * -// * @param httpHeaders {@link HttpHeaders} -// * @return non-null, the key is a cookie name , the value is {@link HttpCookie} -// */ -// public static MultiValueMap parseCookies(HttpHeaders httpHeaders) { -// -// String cookie = httpHeaders.getFirst(COOKIE); -// -// String[] cookieNameAndValues = StringUtils.delimitedListToStringArray(cookie, SEMICOLON); -// -// MultiValueMap cookies = new LinkedMultiValueMap<>(cookieNameAndValues.length); -// -// for (String cookeNameAndValue : cookieNameAndValues) { -// String[] nameAndValue = delimitedListToStringArray(trimWhitespace(cookeNameAndValue), EQUAL); -// String name = nameAndValue[0]; -// String value = nameAndValue.length < 2 ? null : nameAndValue[1]; -// HttpCookie httpCookie = new HttpCookie(name, value); -// cookies.add(name, httpCookie); -// } -// -// return cookies; -// } - - /** - * To the name and value line sets - * - * @param nameAndValuesMap {@link MultiValueMap} the map of name and values - * @return non-null - */ - public static Set toNameAndValuesSet(Map> nameAndValuesMap) { - Set nameAndValues = new LinkedHashSet<>(); - for (Map.Entry> entry : nameAndValuesMap.entrySet()) { - String name = entry.getKey(); - List values = entry.getValue(); - for (String value : values) { - String nameAndValue = name + EQUAL + value; - nameAndValues.add(nameAndValue); - } - } - return nameAndValues; - } - - public static String[] toNameAndValues(Map> nameAndValuesMap) { - return toNameAndValuesSet(nameAndValuesMap).toArray(new String[0]); - } - - /** - * Generate a string of query string from the specified request parameters {@link Map} - * - * @param params the specified request parameters {@link Map} - * @return non-null - */ - public static String toQueryString(Map> params) { - StringBuilder builder = new StringBuilder(); - for (String line : toNameAndValuesSet(params)) { - builder.append(line).append(AND); - } - return builder.toString(); - } - - /** - * Decode value - * - * @param value the value requires to decode - * @return the decoded value - */ - public static String decode(String value) { - if (value == null) { - return value; - } - String decodedValue = value; - try { - decodedValue = URLDecoder.decode(value, UTF_8); - } catch (UnsupportedEncodingException ex) { - } - return decodedValue; - } - - /** - * encode value - * - * @param value the value requires to encode - * @return the encoded value - */ - public static String encode(String value) { - String encodedValue = value; - try { - encodedValue = URLEncoder.encode(value, UTF_8); - } catch (UnsupportedEncodingException ex) { - } - return encodedValue; - } - - private static void addParam(MultiValueMap paramsMap, String name, String value) { - String paramValue = trimAllWhitespace(value); - if (!StringUtils.hasText(paramValue)) { - paramValue = EMPTY_VALUE; - } - paramsMap.add(trimAllWhitespace(name), paramValue); - } + private static final String UTF_8 = "UTF-8"; + + private static final String EQUAL = "="; + + private static final String AND = "&"; + + private static final String SEMICOLON = ";"; + + private static final String QUESTION_MASK = "?"; + + /** + * The empty value + */ + private static final String EMPTY_VALUE = ""; + + /** + * Normalize path: + *

    + *
  1. To remove query string if presents
  2. + *
  3. To remove duplicated slash("/") if exists
  4. + *
+ * + * @param path path to be normalized + * @return a normalized path if required + */ + public static String normalizePath(String path) { + if (!hasText(path)) { + return path; + } + String normalizedPath = path; + int index = normalizedPath.indexOf(QUESTION_MASK); + if (index > -1) { + normalizedPath = normalizedPath.substring(0, index); + } + return StringUtils.replace(normalizedPath, "//", "/"); + } + + /** + * Get Parameters from the specified {@link HttpRequest request} + * + * @param request the specified {@link HttpRequest request} + * @return + */ + public static MultiValueMap getParameters(HttpRequest request) { + URI uri = request.getURI(); + return getParameters(uri.getQuery()); + } + + /** + * Get Parameters from the specified query string. + *

+ * + * @param queryString The query string + * @return The query parameters + */ + public static MultiValueMap getParameters(String queryString) { + return getParameters(delimitedListToStringArray(queryString, AND)); + } + + /** + * Get Parameters from the specified pairs of name-value. + *

+ * + * @param pairs The pairs of name-value + * @return The query parameters + */ + public static MultiValueMap getParameters(Iterable pairs) { + MultiValueMap parameters = new LinkedMultiValueMap<>(); + if (pairs != null) { + for (String pair : pairs) { + String[] nameAndValue = delimitedListToStringArray(pair, EQUAL); + String name = decode(nameAndValue[0]); + String value = nameAndValue.length < 2 ? null : nameAndValue[1]; + value = decode(value); + addParam(parameters, name, value); + } + } + return parameters; + } + + /** + * Get Parameters from the specified pairs of name-value. + *

+ * + * @param pairs The pairs of name-value + * @return The query parameters + */ + public static MultiValueMap getParameters(String... pairs) { + return getParameters(Arrays.asList(pairs)); + } + + // /** + // * Parse a read-only {@link MultiValueMap} of {@link HttpCookie} from {@link + // HttpHeaders} + // * + // * @param httpHeaders {@link HttpHeaders} + // * @return non-null, the key is a cookie name , the value is {@link HttpCookie} + // */ + // public static MultiValueMap parseCookies(HttpHeaders + // httpHeaders) { + // + // String cookie = httpHeaders.getFirst(COOKIE); + // + // String[] cookieNameAndValues = StringUtils.delimitedListToStringArray(cookie, + // SEMICOLON); + // + // MultiValueMap cookies = new + // LinkedMultiValueMap<>(cookieNameAndValues.length); + // + // for (String cookeNameAndValue : cookieNameAndValues) { + // String[] nameAndValue = + // delimitedListToStringArray(trimWhitespace(cookeNameAndValue), EQUAL); + // String name = nameAndValue[0]; + // String value = nameAndValue.length < 2 ? null : nameAndValue[1]; + // HttpCookie httpCookie = new HttpCookie(name, value); + // cookies.add(name, httpCookie); + // } + // + // return cookies; + // } + + /** + * To the name and value line sets + * + * @param nameAndValuesMap {@link MultiValueMap} the map of name and values + * @return non-null + */ + public static Set toNameAndValuesSet( + Map> nameAndValuesMap) { + Set nameAndValues = new LinkedHashSet<>(); + for (Map.Entry> entry : nameAndValuesMap.entrySet()) { + String name = entry.getKey(); + List values = entry.getValue(); + for (String value : values) { + String nameAndValue = name + EQUAL + value; + nameAndValues.add(nameAndValue); + } + } + return nameAndValues; + } + + public static String[] toNameAndValues(Map> nameAndValuesMap) { + return toNameAndValuesSet(nameAndValuesMap).toArray(new String[0]); + } + + /** + * Generate a string of query string from the specified request parameters {@link Map} + * + * @param params the specified request parameters {@link Map} + * @return non-null + */ + public static String toQueryString(Map> params) { + StringBuilder builder = new StringBuilder(); + for (String line : toNameAndValuesSet(params)) { + builder.append(line).append(AND); + } + return builder.toString(); + } + + /** + * Decode value + * + * @param value the value requires to decode + * @return the decoded value + */ + public static String decode(String value) { + if (value == null) { + return value; + } + String decodedValue = value; + try { + decodedValue = URLDecoder.decode(value, UTF_8); + } + catch (UnsupportedEncodingException ex) { + } + return decodedValue; + } + + /** + * encode value + * + * @param value the value requires to encode + * @return the encoded value + */ + public static String encode(String value) { + String encodedValue = value; + try { + encodedValue = URLEncoder.encode(value, UTF_8); + } + catch (UnsupportedEncodingException ex) { + } + return encodedValue; + } + + private static void addParam(MultiValueMap paramsMap, String name, + String value) { + String paramValue = trimAllWhitespace(value); + if (!StringUtils.hasText(paramValue)) { + paramValue = EMPTY_VALUE; + } + paramsMap.add(trimAllWhitespace(name), paramValue); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java index adcc2468a..3b8257b12 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java @@ -16,16 +16,16 @@ */ package com.alibaba.cloud.dubbo.metadata; -import org.apache.dubbo.config.ProtocolConfig; - -import org.springframework.beans.factory.ObjectProvider; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL; +import static org.springframework.util.CollectionUtils.isEmpty; import java.util.Collection; import java.util.Iterator; import java.util.function.Supplier; -import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL; -import static org.springframework.util.CollectionUtils.isEmpty; +import org.apache.dubbo.config.ProtocolConfig; + +import org.springframework.beans.factory.ObjectProvider; /** * Dubbo's {@link ProtocolConfig} {@link Supplier} @@ -34,38 +34,40 @@ import static org.springframework.util.CollectionUtils.isEmpty; */ public class DubboProtocolConfigSupplier implements Supplier { - private final ObjectProvider> protocols; + private final ObjectProvider> protocols; - public DubboProtocolConfigSupplier(ObjectProvider> protocols) { - this.protocols = protocols; - } + public DubboProtocolConfigSupplier( + ObjectProvider> protocols) { + this.protocols = protocols; + } - @Override - public ProtocolConfig get() { - ProtocolConfig protocolConfig = null; - Collection protocols = this.protocols.getIfAvailable(); + @Override + public ProtocolConfig get() { + ProtocolConfig protocolConfig = null; + Collection protocols = this.protocols.getIfAvailable(); - if (!isEmpty(protocols)) { - for (ProtocolConfig protocol : protocols) { - String protocolName = protocol.getName(); - if (DEFAULT_PROTOCOL.equals(protocolName)) { - protocolConfig = protocol; - break; - } - } + if (!isEmpty(protocols)) { + for (ProtocolConfig protocol : protocols) { + String protocolName = protocol.getName(); + if (DEFAULT_PROTOCOL.equals(protocolName)) { + protocolConfig = protocol; + break; + } + } - if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them - Iterator iterator = protocols.iterator(); - protocolConfig = iterator.hasNext() ? iterator.next() : null; - } - } + if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is + // absent, take first one of them + Iterator iterator = protocols.iterator(); + protocolConfig = iterator.hasNext() ? iterator.next() : null; + } + } - if (protocolConfig == null) { - protocolConfig = new ProtocolConfig(); - protocolConfig.setName(DEFAULT_PROTOCOL); - protocolConfig.setPort(-1); - } + if (protocolConfig == null) { + protocolConfig = new ProtocolConfig(); + protocolConfig.setName(DEFAULT_PROTOCOL); + protocolConfig.setPort(-1); + } - return protocolConfig; - } + return protocolConfig; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java index f689a499b..b02094b9c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java @@ -25,38 +25,39 @@ import java.util.Objects; */ public class DubboRestServiceMetadata { - private final ServiceRestMetadata serviceRestMetadata; - - private final RestMethodMetadata restMethodMetadata; - - public DubboRestServiceMetadata(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 DubboRestServiceMetadata)) { - return false; - } - DubboRestServiceMetadata that = (DubboRestServiceMetadata) o; - return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) && - Objects.equals(restMethodMetadata, that.restMethodMetadata); - } - - @Override - public int hashCode() { - return Objects.hash(serviceRestMetadata, restMethodMetadata); - } + private final ServiceRestMetadata serviceRestMetadata; + + private final RestMethodMetadata restMethodMetadata; + + public DubboRestServiceMetadata(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 DubboRestServiceMetadata)) { + return false; + } + DubboRestServiceMetadata that = (DubboRestServiceMetadata) o; + return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) + && Objects.equals(restMethodMetadata, that.restMethodMetadata); + } + + @Override + public int hashCode() { + return Objects.hash(serviceRestMetadata, restMethodMetadata); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java index 22fdeb5ec..6ce0e24c8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.metadata; -import com.alibaba.cloud.dubbo.annotation.DubboTransported; - import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.Objects; +import com.alibaba.cloud.dubbo.annotation.DubboTransported; + /** * {@link MethodMetadata} annotated {@link DubboTransported @DubboTransported} * @@ -30,66 +30,66 @@ import java.util.Objects; */ public class DubboTransportedMethodMetadata { - private final MethodMetadata methodMetadata; - - private final Map attributes; - - public DubboTransportedMethodMetadata(Method method, Map attributes) { - this.methodMetadata = new MethodMetadata(method); - this.attributes = attributes; - } - - 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 getParams() { - return methodMetadata.getParams(); - } - - public void setParams(List params) { - methodMetadata.setParams(params); - } - - public Method getMethod() { - return methodMetadata.getMethod(); - } - - public MethodMetadata getMethodMetadata() { - return methodMetadata; - } - - public Map getAttributes() { - return attributes; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof DubboTransportedMethodMetadata)) { - return false; - } - DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o; - return Objects.equals(methodMetadata, that.methodMetadata) && - Objects.equals(attributes, that.attributes); - } - - @Override - public int hashCode() { - return Objects.hash(methodMetadata, attributes); - } + private final MethodMetadata methodMetadata; + + private final Map attributes; + + public DubboTransportedMethodMetadata(Method method, Map attributes) { + this.methodMetadata = new MethodMetadata(method); + this.attributes = attributes; + } + + 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 getParams() { + return methodMetadata.getParams(); + } + + public void setParams(List params) { + methodMetadata.setParams(params); + } + + public Method getMethod() { + return methodMetadata.getMethod(); + } + + public MethodMetadata getMethodMetadata() { + return methodMetadata; + } + + public Map getAttributes() { + return attributes; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DubboTransportedMethodMetadata)) { + return false; + } + DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o; + return Objects.equals(methodMetadata, that.methodMetadata) + && Objects.equals(attributes, that.attributes); + } + + @Override + public int hashCode() { + return Objects.hash(methodMetadata, attributes); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java index 34598677a..5fbc3d20f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java @@ -16,10 +16,6 @@ */ package com.alibaba.cloud.dubbo.metadata; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; @@ -28,6 +24,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * {@link Method} Metadata * @@ -36,104 +36,101 @@ import java.util.Objects; @JsonInclude(JsonInclude.Include.NON_NULL) public class MethodMetadata { - private String name; - - @JsonProperty("return-type") - private String returnType; - - private List params; - - @JsonIgnore - private Method method; - - public MethodMetadata() { - this.params = new LinkedList<>(); - } - - public MethodMetadata(Method method) { - this.name = method.getName(); - this.returnType = method.getReturnType().getName(); - this.params = initParameters(method); - this.method = method; - } - - private List initParameters(Method method) { - int parameterCount = method.getParameterCount(); - if (parameterCount < 1) { - return Collections.emptyList(); - } - List params = new ArrayList<>(parameterCount); - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < parameterCount; i++) { - Parameter parameter = parameters[i]; - MethodParameterMetadata param = toMethodParameterMetadata(i, parameter); - params.add(param); - } - return params; - } - - private MethodParameterMetadata toMethodParameterMetadata(int index, Parameter parameter) { - MethodParameterMetadata metadata = new MethodParameterMetadata(); - metadata.setIndex(index); - metadata.setName(parameter.getName()); - metadata.setType(parameter.getType().getTypeName()); - return metadata; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getReturnType() { - return returnType; - } - - public void setReturnType(String returnType) { - this.returnType = returnType; - } - - public List getParams() { - return params; - } - - public void setParams(List params) { - this.params = params; - } - - public Method getMethod() { - return method; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MethodMetadata that = (MethodMetadata) o; - return Objects.equals(name, that.name) && - Objects.equals(returnType, that.returnType) && - Objects.equals(params, that.params); - } - - @Override - public int hashCode() { - return Objects.hash(name, returnType, params); - } - - @Override - public String toString() { - return "MethodMetadata{" + - "name='" + name + '\'' + - ", returnType='" + returnType + '\'' + - ", params=" + params + - ", method=" + method + - '}'; - } + private String name; + + @JsonProperty("return-type") + private String returnType; + + private List params; + + @JsonIgnore + private Method method; + + public MethodMetadata() { + this.params = new LinkedList<>(); + } + + public MethodMetadata(Method method) { + this.name = method.getName(); + this.returnType = method.getReturnType().getName(); + this.params = initParameters(method); + this.method = method; + } + + private List initParameters(Method method) { + int parameterCount = method.getParameterCount(); + if (parameterCount < 1) { + return Collections.emptyList(); + } + List params = new ArrayList<>(parameterCount); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameterCount; i++) { + Parameter parameter = parameters[i]; + MethodParameterMetadata param = toMethodParameterMetadata(i, parameter); + params.add(param); + } + return params; + } + + private MethodParameterMetadata toMethodParameterMetadata(int index, + Parameter parameter) { + MethodParameterMetadata metadata = new MethodParameterMetadata(); + metadata.setIndex(index); + metadata.setName(parameter.getName()); + metadata.setType(parameter.getType().getTypeName()); + return metadata; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + + public Method getMethod() { + return method; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MethodMetadata that = (MethodMetadata) o; + return Objects.equals(name, that.name) + && Objects.equals(returnType, that.returnType) + && Objects.equals(params, that.params); + } + + @Override + public int hashCode() { + return Objects.hash(name, returnType, params); + } + + @Override + public String toString() { + return "MethodMetadata{" + "name='" + name + '\'' + ", returnType='" + returnType + + '\'' + ", params=" + params + ", method=" + method + '}'; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java index 39d4ac4a9..56b79b27e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java @@ -16,11 +16,11 @@ */ package com.alibaba.cloud.dubbo.metadata; -import com.fasterxml.jackson.annotation.JsonInclude; - import java.lang.reflect.Method; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; + /** * {@link Method} Parameter Metadata * @@ -29,61 +29,57 @@ import java.util.Objects; @JsonInclude(JsonInclude.Include.NON_NULL) public class MethodParameterMetadata { - private int index; + private int index; - private String name; + private String name; - private String type; + private String type; - public int getIndex() { - return index; - } + public int getIndex() { + return index; + } - public void setIndex(int index) { - this.index = index; - } + public void setIndex(int index) { + this.index = index; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MethodParameterMetadata that = (MethodParameterMetadata) o; - return index == that.index && - Objects.equals(name, that.name) && - Objects.equals(type, that.type); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MethodParameterMetadata that = (MethodParameterMetadata) o; + return index == that.index && Objects.equals(name, that.name) + && Objects.equals(type, that.type); + } - @Override - public int hashCode() { - return Objects.hash(index, name, type); - } + @Override + public int hashCode() { + return Objects.hash(index, name, type); + } - @Override - public String toString() { - return "MethodParameterMetadata{" + - "index=" + index + - ", name='" + name + '\'' + - ", type='" + type + '\'' + - '}'; - } + @Override + public String toString() { + return "MethodParameterMetadata{" + "index=" + index + ", name='" + name + '\'' + + ", type='" + type + '\'' + '}'; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java index a28b8084a..6f2a88f33 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java @@ -16,14 +16,8 @@ */ package com.alibaba.cloud.dubbo.metadata; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import feign.RequestTemplate; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.util.CollectionUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; +import static com.alibaba.cloud.dubbo.http.util.HttpUtils.normalizePath; +import static org.springframework.http.MediaType.parseMediaTypes; import java.util.ArrayList; import java.util.Collection; @@ -37,8 +31,16 @@ import java.util.Objects; import java.util.Set; import java.util.SortedMap; -import static com.alibaba.cloud.dubbo.http.util.HttpUtils.normalizePath; -import static org.springframework.http.MediaType.parseMediaTypes; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import feign.RequestTemplate; /** * Request Metadata @@ -47,226 +49,226 @@ import static org.springframework.http.MediaType.parseMediaTypes; */ public class RequestMetadata { - private String method; - - private String path; - - @JsonProperty("params") - private MultiValueMap params = new LinkedMultiValueMap<>(); - - @JsonProperty("headers") - private HttpHeaders headers = new HttpHeaders(); - - private Set consumes = new LinkedHashSet<>(); - - private Set produces = new LinkedHashSet<>(); - - public RequestMetadata() { - } - - public RequestMetadata(RequestTemplate requestTemplate) { - setMethod(requestTemplate.method()); - setPath(requestTemplate.url()); - params(requestTemplate.queries()); - headers(requestTemplate.headers()); - } - - /** - * Get the best matched {@link RequestMetadata} via specified {@link RequestMetadata} - * - * @param requestMetadataMap the source of {@link NavigableMap} - * @param requestMetadata the match object - * @return if not matched, return null - */ - public static RequestMetadata getBestMatch(NavigableMap requestMetadataMap, - RequestMetadata requestMetadata) { - - RequestMetadata key = requestMetadata; - - RequestMetadata result = requestMetadataMap.get(key); - - if (result == null) { - SortedMap headMap = requestMetadataMap.headMap(key, true); - result = headMap.isEmpty() ? null : requestMetadataMap.get(headMap.lastKey()); - } - - return result; - } - - private static void add(String key, String value, MultiValueMap destination) { - destination.add(key, value); - } - - private static > void addAll(Map source, - MultiValueMap destination) { - for (Map.Entry entry : source.entrySet()) { - String key = entry.getKey(); - for (String value : entry.getValue()) { - add(key, value, destination); - } - } - } - - private static void mediaTypes(HttpHeaders httpHeaders, String headerName, Collection destination) { - List value = httpHeaders.get(headerName); - List mediaTypes = parseMediaTypes(value); - destination.addAll(toMediaTypeValues(mediaTypes)); - } - - private static List toMediaTypeValues(List mediaTypes) { - List list = new ArrayList<>(mediaTypes.size()); - for (MediaType mediaType : mediaTypes) { - list.add(mediaType.toString()); - } - return list; - } - - private static List toMediaTypes(Collection mediaTypeValues) { - if (mediaTypeValues.isEmpty()) { - return Collections.singletonList(MediaType.ALL); - } - return parseMediaTypes(new LinkedList<>(mediaTypeValues)); - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method.toUpperCase(); - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = normalizePath(path); - } - - public MultiValueMap getParams() { - return params; - } - - public void setParams(Map> params) { - params(params); - } - - public Map> getHeaders() { - return headers; - } - - public void setHeaders(Map> headers) { - headers(headers); - } - - public Set getConsumes() { - return consumes; - } - - public void setConsumes(Set consumes) { - this.consumes = consumes; - } - - public Set getProduces() { - return produces; - } - - public void setProduces(Set produces) { - this.produces = produces; - } - - // @JsonIgnore properties - @JsonIgnore - public Set getParamNames() { - return params.keySet(); - } - - @JsonIgnore - public Set getHeaderNames() { - return headers.keySet(); - } - - @JsonIgnore - public List getConsumeMediaTypes() { - return toMediaTypes(consumes); - } - - @JsonIgnore - public List getProduceMediaTypes() { - return toMediaTypes(produces); - } - - public String getParameter(String name) { - return this.params.getFirst(name); - } - - public String getHeader(String name) { - return this.headers.getFirst(name); - } - - public RequestMetadata addParam(String name, String value) { - add(name, value, this.params); - return this; - } - - public RequestMetadata addHeader(String name, String value) { - add(name, value, this.headers); - return this; - } - - private > RequestMetadata params(Map params) { - addAll(params, this.params); - return this; - } - - private > RequestMetadata headers(Map headers) { - if (!CollectionUtils.isEmpty(headers)) { - HttpHeaders httpHeaders = new HttpHeaders(); - // Add all headers - addAll(headers, httpHeaders); - // Handles "Content-Type" and "Accept" headers if present - mediaTypes(httpHeaders, HttpHeaders.CONTENT_TYPE, this.consumes); - mediaTypes(httpHeaders, HttpHeaders.ACCEPT, this.produces); - this.headers.putAll(httpHeaders); - } - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof RequestMetadata)) { - return false; - } - RequestMetadata that = (RequestMetadata) o; - return Objects.equals(method, that.method) && - Objects.equals(path, that.path) && - Objects.equals(consumes, that.consumes) && - Objects.equals(produces, that.produces) && - // Metadata should not compare the values - Objects.equals(getParamNames(), that.getParamNames()) && - Objects.equals(getHeaderNames(), that.getHeaderNames()); - - } - - @Override - public int hashCode() { - // The values of metadata should not use for the hashCode() method - return Objects.hash(method, path, consumes, produces, getParamNames(), getHeaderNames()); - } - - @Override - public String toString() { - return "RequestMetadata{" + - "method='" + method + '\'' + - ", path='" + path + '\'' + - ", params=" + params + - ", headers=" + headers + - ", consumes=" + consumes + - ", produces=" + produces + - '}'; - } + private String method; + + private String path; + + @JsonProperty("params") + private MultiValueMap params = new LinkedMultiValueMap<>(); + + @JsonProperty("headers") + private HttpHeaders headers = new HttpHeaders(); + + private Set consumes = new LinkedHashSet<>(); + + private Set produces = new LinkedHashSet<>(); + + public RequestMetadata() { + } + + public RequestMetadata(RequestTemplate requestTemplate) { + setMethod(requestTemplate.method()); + setPath(requestTemplate.url()); + params(requestTemplate.queries()); + headers(requestTemplate.headers()); + } + + /** + * Get the best matched {@link RequestMetadata} via specified {@link RequestMetadata} + * + * @param requestMetadataMap the source of {@link NavigableMap} + * @param requestMetadata the match object + * @return if not matched, return null + */ + public static RequestMetadata getBestMatch( + NavigableMap requestMetadataMap, + RequestMetadata requestMetadata) { + + RequestMetadata key = requestMetadata; + + RequestMetadata result = requestMetadataMap.get(key); + + if (result == null) { + SortedMap headMap = requestMetadataMap + .headMap(key, true); + result = headMap.isEmpty() ? null : requestMetadataMap.get(headMap.lastKey()); + } + + return result; + } + + private static void add(String key, String value, + MultiValueMap destination) { + destination.add(key, value); + } + + private static > void addAll(Map source, + MultiValueMap destination) { + for (Map.Entry entry : source.entrySet()) { + String key = entry.getKey(); + for (String value : entry.getValue()) { + add(key, value, destination); + } + } + } + + private static void mediaTypes(HttpHeaders httpHeaders, String headerName, + Collection destination) { + List value = httpHeaders.get(headerName); + List mediaTypes = parseMediaTypes(value); + destination.addAll(toMediaTypeValues(mediaTypes)); + } + + private static List toMediaTypeValues(List mediaTypes) { + List list = new ArrayList<>(mediaTypes.size()); + for (MediaType mediaType : mediaTypes) { + list.add(mediaType.toString()); + } + return list; + } + + private static List toMediaTypes(Collection mediaTypeValues) { + if (mediaTypeValues.isEmpty()) { + return Collections.singletonList(MediaType.ALL); + } + return parseMediaTypes(new LinkedList<>(mediaTypeValues)); + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method.toUpperCase(); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = normalizePath(path); + } + + public MultiValueMap getParams() { + return params; + } + + public void setParams(Map> params) { + params(params); + } + + public Map> getHeaders() { + return headers; + } + + public void setHeaders(Map> headers) { + headers(headers); + } + + public Set getConsumes() { + return consumes; + } + + public void setConsumes(Set consumes) { + this.consumes = consumes; + } + + public Set getProduces() { + return produces; + } + + public void setProduces(Set produces) { + this.produces = produces; + } + + // @JsonIgnore properties + @JsonIgnore + public Set getParamNames() { + return params.keySet(); + } + + @JsonIgnore + public Set getHeaderNames() { + return headers.keySet(); + } + + @JsonIgnore + public List getConsumeMediaTypes() { + return toMediaTypes(consumes); + } + + @JsonIgnore + public List getProduceMediaTypes() { + return toMediaTypes(produces); + } + + public String getParameter(String name) { + return this.params.getFirst(name); + } + + public String getHeader(String name) { + return this.headers.getFirst(name); + } + + public RequestMetadata addParam(String name, String value) { + add(name, value, this.params); + return this; + } + + public RequestMetadata addHeader(String name, String value) { + add(name, value, this.headers); + return this; + } + + private > RequestMetadata params(Map params) { + addAll(params, this.params); + return this; + } + + private > RequestMetadata headers( + Map headers) { + if (!CollectionUtils.isEmpty(headers)) { + HttpHeaders httpHeaders = new HttpHeaders(); + // Add all headers + addAll(headers, httpHeaders); + // Handles "Content-Type" and "Accept" headers if present + mediaTypes(httpHeaders, HttpHeaders.CONTENT_TYPE, this.consumes); + mediaTypes(httpHeaders, HttpHeaders.ACCEPT, this.produces); + this.headers.putAll(httpHeaders); + } + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RequestMetadata)) { + return false; + } + RequestMetadata that = (RequestMetadata) o; + return Objects.equals(method, that.method) && Objects.equals(path, that.path) + && Objects.equals(consumes, that.consumes) + && Objects.equals(produces, that.produces) && + // Metadata should not compare the values + Objects.equals(getParamNames(), that.getParamNames()) + && Objects.equals(getHeaderNames(), that.getHeaderNames()); + + } + + @Override + public int hashCode() { + // The values of metadata should not use for the hashCode() method + return Objects.hash(method, path, consumes, produces, getParamNames(), + getHeaderNames()); + } + + @Override + public String toString() { + return "RequestMetadata{" + "method='" + method + '\'' + ", path='" + path + '\'' + + ", params=" + params + ", headers=" + headers + ", consumes=" + consumes + + ", produces=" + produces + '}'; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java index 7840d448c..fceec4e6b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java @@ -16,16 +16,17 @@ */ package com.alibaba.cloud.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; import java.util.Objects; +import org.springframework.core.ResolvableType; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * Method Request Metadata * @@ -34,205 +35,199 @@ import java.util.Objects; @JsonInclude(JsonInclude.Include.NON_NULL) public class RestMethodMetadata { - private MethodMetadata method; + private MethodMetadata method; - private RequestMetadata request; + private RequestMetadata request; - @JsonProperty("url-index") - private Integer urlIndex; + @JsonProperty("url-index") + private Integer urlIndex; - @JsonProperty("setBody-index") - private Integer bodyIndex; + @JsonProperty("setBody-index") + private Integer bodyIndex; - @JsonProperty("header-map-index") - private Integer headerMapIndex; + @JsonProperty("header-map-index") + private Integer headerMapIndex; - @JsonProperty("query-map-index") - private Integer queryMapIndex; + @JsonProperty("query-map-index") + private Integer queryMapIndex; - @JsonProperty("query-map-encoded") - private boolean queryMapEncoded; + @JsonProperty("query-map-encoded") + private boolean queryMapEncoded; - @JsonProperty("return-type") - private String returnType; + @JsonProperty("return-type") + private String returnType; - @JsonProperty("setBody-type") - private String bodyType; + @JsonProperty("setBody-type") + private String bodyType; - @JsonProperty("index-to-name") - private Map> indexToName; + @JsonProperty("index-to-name") + private Map> indexToName; - @JsonProperty("form-params") - private List formParams; + @JsonProperty("form-params") + private List formParams; - @JsonProperty("index-to-encoded") - private Map indexToEncoded; + @JsonProperty("index-to-encoded") + private Map indexToEncoded; - public RestMethodMetadata() { - } + public RestMethodMetadata() { + } - public RestMethodMetadata(feign.MethodMetadata methodMetadata) { - this.request = new RequestMetadata(methodMetadata.template()); - this.urlIndex = methodMetadata.urlIndex(); - this.bodyIndex = methodMetadata.bodyIndex(); - this.headerMapIndex = methodMetadata.headerMapIndex(); - this.queryMapEncoded = methodMetadata.queryMapEncoded(); - this.queryMapEncoded = methodMetadata.queryMapEncoded(); - this.returnType = getClassName(methodMetadata.returnType()); - this.bodyType = getClassName(methodMetadata.bodyType()); - this.indexToName = methodMetadata.indexToName(); - this.formParams = methodMetadata.formParams(); - this.indexToEncoded = methodMetadata.indexToEncoded(); - } + public RestMethodMetadata(feign.MethodMetadata methodMetadata) { + this.request = new RequestMetadata(methodMetadata.template()); + this.urlIndex = methodMetadata.urlIndex(); + this.bodyIndex = methodMetadata.bodyIndex(); + this.headerMapIndex = methodMetadata.headerMapIndex(); + this.queryMapEncoded = methodMetadata.queryMapEncoded(); + this.queryMapEncoded = methodMetadata.queryMapEncoded(); + this.returnType = getClassName(methodMetadata.returnType()); + this.bodyType = getClassName(methodMetadata.bodyType()); + this.indexToName = methodMetadata.indexToName(); + this.formParams = methodMetadata.formParams(); + this.indexToEncoded = methodMetadata.indexToEncoded(); + } - public MethodMetadata getMethod() { - return method; - } + public MethodMetadata getMethod() { + return method; + } - public void setMethod(MethodMetadata method) { - this.method = method; - } - - public RequestMetadata getRequest() { - return request; - } - - public void setRequest(RequestMetadata request) { - this.request = request; - } - - public Map> getIndexToName() { - return indexToName; - } - - public void setIndexToName(Map> indexToName) { - this.indexToName = indexToName; - } - - public Integer getUrlIndex() { - return urlIndex; - } - - public void setUrlIndex(Integer urlIndex) { - this.urlIndex = urlIndex; - } - - public Integer getBodyIndex() { - return bodyIndex; - } - - public void setBodyIndex(Integer bodyIndex) { - this.bodyIndex = bodyIndex; - } - - public Integer getHeaderMapIndex() { - return headerMapIndex; - } - - public void setHeaderMapIndex(Integer headerMapIndex) { - this.headerMapIndex = headerMapIndex; - } - - public Integer getQueryMapIndex() { - return queryMapIndex; - } - - public void setQueryMapIndex(Integer queryMapIndex) { - this.queryMapIndex = queryMapIndex; - } - - public boolean isQueryMapEncoded() { - return queryMapEncoded; - } - - public void setQueryMapEncoded(boolean queryMapEncoded) { - this.queryMapEncoded = queryMapEncoded; - } - - public String getReturnType() { - return returnType; - } - - public void setReturnType(String returnType) { - this.returnType = returnType; - } - - public String getBodyType() { - return bodyType; - } - - public void setBodyType(String bodyType) { - this.bodyType = bodyType; - } - - public List getFormParams() { - return formParams; - } - - public void setFormParams(List formParams) { - this.formParams = formParams; - } - - public Map getIndexToEncoded() { - return indexToEncoded; - } - - public void setIndexToEncoded(Map indexToEncoded) { - this.indexToEncoded = indexToEncoded; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof RestMethodMetadata)) { - return false; - } - RestMethodMetadata that = (RestMethodMetadata) o; - return queryMapEncoded == that.queryMapEncoded && - Objects.equals(method, that.method) && - Objects.equals(request, that.request) && - Objects.equals(urlIndex, that.urlIndex) && - Objects.equals(bodyIndex, that.bodyIndex) && - Objects.equals(headerMapIndex, that.headerMapIndex) && - Objects.equals(queryMapIndex, that.queryMapIndex) && - Objects.equals(returnType, that.returnType) && - Objects.equals(bodyType, that.bodyType) && - Objects.equals(indexToName, that.indexToName) && - Objects.equals(formParams, that.formParams) && - Objects.equals(indexToEncoded, that.indexToEncoded); - } - - @Override - public int hashCode() { - 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(); - } - - @Override - public String toString() { - return "RestMethodMetadata{" + - "method=" + method + - ", request=" + request + - ", urlIndex=" + urlIndex + - ", bodyIndex=" + bodyIndex + - ", headerMapIndex=" + headerMapIndex + - ", queryMapIndex=" + queryMapIndex + - ", queryMapEncoded=" + queryMapEncoded + - ", returnType='" + returnType + '\'' + - ", bodyType='" + bodyType + '\'' + - ", indexToName=" + indexToName + - ", formParams=" + formParams + - ", indexToEncoded=" + indexToEncoded + - '}'; - } + public void setMethod(MethodMetadata method) { + this.method = method; + } + + public RequestMetadata getRequest() { + return request; + } + + public void setRequest(RequestMetadata request) { + this.request = request; + } + + public Map> getIndexToName() { + return indexToName; + } + + public void setIndexToName(Map> indexToName) { + this.indexToName = indexToName; + } + + public Integer getUrlIndex() { + return urlIndex; + } + + public void setUrlIndex(Integer urlIndex) { + this.urlIndex = urlIndex; + } + + public Integer getBodyIndex() { + return bodyIndex; + } + + public void setBodyIndex(Integer bodyIndex) { + this.bodyIndex = bodyIndex; + } + + public Integer getHeaderMapIndex() { + return headerMapIndex; + } + + public void setHeaderMapIndex(Integer headerMapIndex) { + this.headerMapIndex = headerMapIndex; + } + + public Integer getQueryMapIndex() { + return queryMapIndex; + } + + public void setQueryMapIndex(Integer queryMapIndex) { + this.queryMapIndex = queryMapIndex; + } + + public boolean isQueryMapEncoded() { + return queryMapEncoded; + } + + public void setQueryMapEncoded(boolean queryMapEncoded) { + this.queryMapEncoded = queryMapEncoded; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public String getBodyType() { + return bodyType; + } + + public void setBodyType(String bodyType) { + this.bodyType = bodyType; + } + + public List getFormParams() { + return formParams; + } + + public void setFormParams(List formParams) { + this.formParams = formParams; + } + + public Map getIndexToEncoded() { + return indexToEncoded; + } + + public void setIndexToEncoded(Map indexToEncoded) { + this.indexToEncoded = indexToEncoded; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RestMethodMetadata)) { + return false; + } + RestMethodMetadata that = (RestMethodMetadata) o; + return queryMapEncoded == that.queryMapEncoded + && Objects.equals(method, that.method) + && Objects.equals(request, that.request) + && Objects.equals(urlIndex, that.urlIndex) + && Objects.equals(bodyIndex, that.bodyIndex) + && Objects.equals(headerMapIndex, that.headerMapIndex) + && Objects.equals(queryMapIndex, that.queryMapIndex) + && Objects.equals(returnType, that.returnType) + && Objects.equals(bodyType, that.bodyType) + && Objects.equals(indexToName, that.indexToName) + && Objects.equals(formParams, that.formParams) + && Objects.equals(indexToEncoded, that.indexToEncoded); + } + + @Override + public int hashCode() { + 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(); + } + + @Override + public String toString() { + return "RestMethodMetadata{" + "method=" + method + ", request=" + request + + ", urlIndex=" + urlIndex + ", bodyIndex=" + bodyIndex + + ", headerMapIndex=" + headerMapIndex + ", queryMapIndex=" + + queryMapIndex + ", queryMapEncoded=" + queryMapEncoded + + ", returnType='" + returnType + '\'' + ", bodyType='" + bodyType + '\'' + + ", indexToName=" + indexToName + ", formParams=" + formParams + + ", indexToEncoded=" + indexToEncoded + '}'; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java index 3a871b211..e0c93d697 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java @@ -16,11 +16,11 @@ */ package com.alibaba.cloud.dubbo.metadata; -import com.fasterxml.jackson.annotation.JsonInclude; - import java.util.Objects; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonInclude; + /** * Service Rest Metadata * @@ -30,41 +30,40 @@ import java.util.Set; @JsonInclude(JsonInclude.Include.NON_NULL) public class ServiceRestMetadata { - private String url; + private String url; - private Set meta; + private Set meta; - public String getUrl() { - return url; - } + public String getUrl() { + return url; + } - public void setUrl(String url) { - this.url = url; - } + public void setUrl(String url) { + this.url = url; + } - public Set getMeta() { - return meta; - } + public Set getMeta() { + return meta; + } - public void setMeta(Set meta) { - this.meta = meta; - } + public void setMeta(Set meta) { + this.meta = meta; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ServiceRestMetadata)) { - return false; - } - ServiceRestMetadata that = (ServiceRestMetadata) o; - return Objects.equals(url, that.url) && - Objects.equals(meta, that.meta); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ServiceRestMetadata)) { + return false; + } + ServiceRestMetadata that = (ServiceRestMetadata) o; + return Objects.equals(url, that.url) && Objects.equals(meta, that.meta); + } - @Override - public int hashCode() { - return Objects.hash(url, meta); - } + @Override + public int hashCode() { + return Objects.hash(url, meta); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java index 548280fb6..2c48be6df 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java @@ -16,20 +16,34 @@ */ package com.alibaba.cloud.dubbo.metadata.repository; +import static com.alibaba.cloud.dubbo.env.DubboCloudProperties.ALL_DUBBO_SERVICES; +import static com.alibaba.cloud.dubbo.http.DefaultHttpRequest.builder; +import static java.lang.String.format; +import static java.lang.String.valueOf; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableMap; +import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.springframework.util.CollectionUtils.isEmpty; +import static org.springframework.util.StringUtils.hasText; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.annotation.PostConstruct; + import org.apache.dubbo.common.URL; -import com.alibaba.cloud.dubbo.env.DubboCloudProperties; -import com.alibaba.cloud.dubbo.http.matcher.RequestMetadataMatcher; -import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; -import com.alibaba.cloud.dubbo.metadata.RequestMetadata; -import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; -import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; -import com.alibaba.cloud.dubbo.service.DubboMetadataService; -import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter; -import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; -import com.alibaba.cloud.dubbo.util.JSONUtils; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.type.TypeFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.SmartInitializingSingleton; @@ -46,30 +60,18 @@ import org.springframework.stereotype.Repository; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import javax.annotation.PostConstruct; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static com.alibaba.cloud.dubbo.env.DubboCloudProperties.ALL_DUBBO_SERVICES; -import static com.alibaba.cloud.dubbo.http.DefaultHttpRequest.builder; -import static java.lang.String.format; -import static java.lang.String.valueOf; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptySet; -import static java.util.Collections.unmodifiableList; -import static java.util.Collections.unmodifiableMap; -import static java.util.Collections.unmodifiableSet; -import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; -import static org.springframework.util.CollectionUtils.isEmpty; -import static org.springframework.util.StringUtils.hasText; +import com.alibaba.cloud.dubbo.env.DubboCloudProperties; +import com.alibaba.cloud.dubbo.http.matcher.RequestMetadataMatcher; +import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; +import com.alibaba.cloud.dubbo.metadata.RequestMetadata; +import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; +import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; +import com.alibaba.cloud.dubbo.service.DubboMetadataService; +import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter; +import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; +import com.alibaba.cloud.dubbo.util.JSONUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; /** * Dubbo Service Metadata {@link Repository} @@ -77,533 +79,570 @@ import static org.springframework.util.StringUtils.hasText; * @author Mercy */ @Repository -public class DubboServiceMetadataRepository implements SmartInitializingSingleton, ApplicationEventPublisherAware { - - /** - * The prefix of {@link DubboMetadataService} : "dubbo.metadata-service." - */ - public static final String DUBBO_METADATA_SERVICE_PREFIX = "dubbo.metadata-service."; - - /** - * The {@link URL URLs} property name of {@link DubboMetadataService} : "dubbo.metadata-service.urls" - */ - public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = DUBBO_METADATA_SERVICE_PREFIX + "urls"; - - /** - * The {@link String#format(String, Object...) pattern} of dubbo protocols port - */ - public static final String DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN = "dubbo.protocols.%s.port"; - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Monitor object for synchronization - */ - private final Object monitor = new Object(); - /** - * A {@link Set} of service names that had been initialized - */ - private final Set initializedServices = new LinkedHashSet<>(); - /** - * All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method - * and value is the {@link List} of {@link URL URLs} - */ - private final MultiValueMap allExportedURLs = new LinkedMultiValueMap<>(); - - // =================================== Registration =================================== // - /** - * The subscribed {@link URL urls} {@link Map} of {@link DubboMetadataService}, - * whose key is the return value of {@link URL#getServiceKey()} method and value is the {@link List} of - * {@link URL URLs} - */ - private final MultiValueMap subscribedDubboMetadataServiceURLs = new LinkedMultiValueMap<>(); - - // ==================================================================================== // - - - // =================================== Subscription =================================== // - /** - * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, - * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods. - */ - private final Set serviceRestMetadata = new LinkedHashSet<>(); - private ApplicationEventPublisher applicationEventPublisher; - - // ==================================================================================== // - - - // =================================== REST Metadata ================================== // - private volatile Set subscribedServices = emptySet(); - /** - * Key is application name - * Value is Map - */ - private Map> dubboRestServiceMetadataRepository = newHashMap(); - - // ==================================================================================== // - - - // =================================== Dependencies =================================== // - - @Autowired - private DubboCloudProperties dubboCloudProperties; - - @Autowired - private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; - - @Autowired - private DiscoveryClient discoveryClient; - - @Autowired - private JSONUtils jsonUtils; - - @Autowired - private InetUtils inetUtils; - - @Value("${spring.application.name}") - private String currentApplicationName; - - @Autowired - private DubboMetadataServiceExporter dubboMetadataServiceExporter; - - - // ==================================================================================== // - - private static Map getMap(Map> repository, String key) { - return getOrDefault(repository, key, newHashMap()); - } - - private static V getOrDefault(Map source, K key, V defaultValue) { - V value = source.get(key); - if (value == null) { - value = defaultValue; - source.put(key, value); - } - return value; - } - - private static Map newHashMap() { - return new LinkedHashMap<>(); - } - - /** - * Initialize {@link #subscribedServices the subscribed services} - * - * @return - */ - @PostConstruct - public Stream initSubscribedServices() { - Set newSubscribedServices = new LinkedHashSet<>(); - - // If subscribes all services - if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) { - List services = discoveryClient.getServices(); - newSubscribedServices.addAll(services); - if (logger.isWarnEnabled()) { - logger.warn("Current application will subscribe all services(size:{}) in registry, " + - "a lot of memory and CPU cycles may be used, " + - "thus it's strongly recommend you using the externalized property '{}' " + - "to specify the services", - newSubscribedServices.size(), "dubbo.cloud.subscribed-services"); - } - } else { - newSubscribedServices.addAll(dubboCloudProperties.subscribedServices()); - } - - // exclude current application name - excludeSelf(newSubscribedServices); - - // copy from subscribedServices - Set oldSubscribedServices = this.subscribedServices; - - // volatile update subscribedServices to be new one - this.subscribedServices = newSubscribedServices; - - // dispatch SubscribedServicesChangedEvent - dispatchEvent(new SubscribedServicesChangedEvent(this, oldSubscribedServices, newSubscribedServices)); - - // clear old one, help GC - oldSubscribedServices.clear(); - - return newSubscribedServices.stream(); - } - - private void dispatchEvent(ApplicationEvent event) { - applicationEventPublisher.publishEvent(event); - } - - @Override - public void afterSingletonsInstantiated() { - initializeMetadata(); - } - - /** - * Initialize the metadata - */ - private void initializeMetadata() { - doGetSubscribedServices().forEach(this::initializeMetadata); - if (logger.isInfoEnabled()) { - logger.info("The metadata of Dubbo services has been initialized"); - } - } - - /** - * Initialize the metadata of Dubbo Services - */ - public void initializeMetadata(String serviceName) { - synchronized (monitor) { - if (initializedServices.contains(serviceName)) { - if (logger.isDebugEnabled()) { - logger.debug("The metadata of Dubbo service[name : {}] has been initialized", serviceName); - } - } else { - if (logger.isInfoEnabled()) { - logger.info("The metadata of Dubbo service[name : {}] is about to be initialized", serviceName); - } - - // Keep the order in following invocations - initSubscribedDubboMetadataService(serviceName); - initDubboRestServiceMetadataRepository(serviceName); - // mark this service name having been initialized - initializedServices.add(serviceName); - } - } - } - - /** - * Get the metadata {@link Map} of {@link DubboMetadataService} - * - * @return non-null read-only {@link Map} - */ - public Map getDubboMetadataServiceMetadata() { - - List dubboMetadataServiceURLs = dubboMetadataServiceExporter.export(); - - // remove the exported URLs of DubboMetadataService - removeDubboMetadataServiceURLs(dubboMetadataServiceURLs); - - Map metadata = newHashMap(); - - addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs); - addDubboProtocolsPortMetadata(metadata); - - return Collections.unmodifiableMap(metadata); - } - - private void removeDubboMetadataServiceURLs(List dubboMetadataServiceURLs) { - dubboMetadataServiceURLs.forEach(this::unexportURL); - } - - private void addDubboMetadataServiceURLsMetadata(Map metadata, List dubboMetadataServiceURLs) { - String dubboMetadataServiceURLsJSON = jsonUtils.toJSON(dubboMetadataServiceURLs); - metadata.put(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME, dubboMetadataServiceURLsJSON); - } - - private void addDubboProtocolsPortMetadata(Map metadata) { - - allExportedURLs.values() - .stream() - .flatMap(v -> v.stream()) - .forEach(url -> { - String protocol = url.getProtocol(); - String propertyName = getDubboProtocolPropertyName(protocol); - String propertyValue = valueOf(url.getPort()); - metadata.put(propertyName, propertyValue); - }); - } - - /** - * Get the property name of Dubbo Protocol - * - * @param protocol Dubbo Protocol - * @return non-null - */ - public String getDubboProtocolPropertyName(String protocol) { - return format(DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN, protocol); - } - - /** - * Publish the {@link Set} of {@link ServiceRestMetadata} - * - * @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata} - */ - public void publishServiceRestMetadata(Set serviceRestMetadataSet) { - for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { - if (!isEmpty(serviceRestMetadata.getMeta())) { - this.serviceRestMetadata.add(serviceRestMetadata); - } - } - } - - /** - * Get the {@link Set} of {@link ServiceRestMetadata} - * - * @return non-null read-only {@link Set} - */ - public Set getServiceRestMetadata() { - return unmodifiableSet(serviceRestMetadata); - } - - public List findSubscribedDubboMetadataServiceURLs(String serviceName, String group, String version, - String protocol) { - String serviceKey = URL.buildKey(serviceName, group, version); - - List urls = null; - - synchronized (monitor) { - urls = subscribedDubboMetadataServiceURLs.get(serviceKey); - } - - if (isEmpty(urls)) { - return emptyList(); - } - - return hasText(protocol) ? - urls.stream().filter(url -> url.getProtocol().equalsIgnoreCase(protocol)).collect(Collectors.toList()) : - unmodifiableList(urls) - ; - } - - /** - * The specified service is subscribe or not - * - * @param serviceName the service name - * @return - */ - public boolean isSubscribedService(String serviceName) { - return doGetSubscribedServices().contains(serviceName); - } - - public void exportURL(URL url) { - URL actualURL = url; - InetUtils.HostInfo hostInfo = inetUtils.findFirstNonLoopbackHostInfo(); - String ipAddress = hostInfo.getIpAddress(); - // To use InetUtils to set IP if they are different - // issue : https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/589 - if (!Objects.equals(url.getHost(), ipAddress)) { - actualURL = url.setHost(ipAddress); - } - this.allExportedURLs.add(actualURL.getServiceKey(), actualURL); - } - - public void unexportURL(URL url) { - String key = url.getServiceKey(); - // NPE issue : https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/591 - List urls = allExportedURLs.get(key); - if (!isEmpty(urls)) { - urls.remove(url); - allExportedURLs.addAll(key, urls); - } - } - - /** - * Get all exported {@link URL urls}. - * - * @return non-null read-only - */ - public Map> getAllExportedUrls() { - return unmodifiableMap(allExportedURLs); - } - - /** - * Get all exported {@link URL#getServiceKey() service keys} - * - * @return non-null read-only - */ - public Set getAllServiceKeys() { - return allExportedURLs.keySet(); - } - - /** - * Get the {@link URL urls} that {@link DubboMetadataService} exported by the specified {@link ServiceInstance} - * - * @param serviceInstance {@link ServiceInstance} - * @return the mutable {@link URL urls} - */ - public List getDubboMetadataServiceURLs(ServiceInstance serviceInstance) { - Map metadata = serviceInstance.getMetadata(); - String dubboURLsJSON = metadata.get(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME); - return jsonUtils.toURLs(dubboURLsJSON); - } - - public Integer getDubboProtocolPort(ServiceInstance serviceInstance, String protocol) { - String protocolProperty = getDubboProtocolPropertyName(protocol); - Map metadata = serviceInstance.getMetadata(); - String protocolPort = metadata.get(protocolProperty); - return hasText(protocolPort) ? Integer.valueOf(protocolPort) : null; - } - - public List getExportedURLs(String serviceInterface, String group, String version) { - String serviceKey = URL.buildKey(serviceInterface, group, version); - return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList()); - } - - /** - * Initialize the specified service's {@link ServiceRestMetadata} - * - * @param serviceName the service name - */ - protected void initDubboRestServiceMetadataRepository(String serviceName) { - - if (dubboRestServiceMetadataRepository.containsKey(serviceName)) { - return; - } - - Set serviceRestMetadataSet = getServiceRestMetadataSet(serviceName); - - if (isEmpty(serviceRestMetadataSet)) { - if (logger.isWarnEnabled()) { - logger.warn("The Spring application[name : {}] does not expose The REST metadata in the Dubbo services." - , serviceName); - } - return; - } - - Map metadataMap = getMetadataMap(serviceName); - - for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { - - serviceRestMetadata.getMeta().forEach(restMethodMetadata -> { - RequestMetadata requestMetadata = restMethodMetadata.getRequest(); - RequestMetadataMatcher matcher = new RequestMetadataMatcher(requestMetadata); - DubboRestServiceMetadata metadata = new DubboRestServiceMetadata(serviceRestMetadata, restMethodMetadata); - metadataMap.put(matcher, metadata); - }); - } - - if (logger.isInfoEnabled()) { - logger.info("The REST metadata in the dubbo services has been loaded in the Spring application[name : {}]", serviceName); - } - } - - /** - * Get a {@link DubboRestServiceMetadata} by the specified service name if {@link RequestMetadata} matched - * - * @param serviceName service name - * @param requestMetadata {@link RequestMetadata} to be matched - * @return {@link DubboRestServiceMetadata} if matched, or null - */ - public DubboRestServiceMetadata get(String serviceName, RequestMetadata requestMetadata) { - return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata); - } - - /** - * @return not-null - */ - protected Set doGetSubscribedServices() { - Set subscribedServices = this.subscribedServices; - return subscribedServices == null ? emptySet() : subscribedServices; - } - - public Set getSubscribedServices() { - return unmodifiableSet(doGetSubscribedServices()); - } - - private T match(Map> repository, String serviceName, - RequestMetadata requestMetadata) { - - Map map = repository.get(serviceName); - - T object = null; - - if (!isEmpty(map)) { - RequestMetadataMatcher matcher = new RequestMetadataMatcher(requestMetadata); - object = map.get(matcher); - if (object == null) { // Can't match exactly - // Require to match one by one - HttpRequest request = builder() - .method(requestMetadata.getMethod()) - .path(requestMetadata.getPath()) - .params(requestMetadata.getParams()) - .headers(requestMetadata.getHeaders()) - .build(); - - for (Map.Entry entry : map.entrySet()) { - RequestMetadataMatcher possibleMatcher = entry.getKey(); - if (possibleMatcher.match(request)) { - object = entry.getValue(); - break; - } - } - } - } - - if (object == null) { - if (logger.isWarnEnabled()) { - logger.warn("DubboServiceMetadata can't be found in the Spring application [%s] and %s", - serviceName, requestMetadata); - } - } - - return object; - } - - private Map getMetadataMap(String serviceName) { - return getMap(dubboRestServiceMetadataRepository, serviceName); - } - - private Set getServiceRestMetadataSet(String serviceName) { - - Set metadata = emptySet(); - - DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName); - - if (dubboMetadataService != null) { - try { - String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata(); - if (hasText(serviceRestMetadataJsonConfig)) { - metadata = objectMapper.readValue(serviceRestMetadataJsonConfig, - TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class)); - } - } catch (Exception e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); - } - } - } - return metadata; - } - - private void excludeSelf(Set subscribedServices) { - subscribedServices.remove(currentApplicationName); - } - - protected void initSubscribedDubboMetadataService(String serviceName) { - discoveryClient.getInstances(serviceName) - .stream() - .findAny() - .map(this::getDubboMetadataServiceURLs) - .ifPresent(dubboMetadataServiceURLs -> { - dubboMetadataServiceURLs.forEach(dubboMetadataServiceURL -> { - try { - initSubscribedDubboMetadataServiceURL(dubboMetadataServiceURL); - initDubboMetadataServiceProxy(dubboMetadataServiceURL); - } catch (Throwable e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); - } - } - }); - }); - } - - private void initSubscribedDubboMetadataServiceURL(URL dubboMetadataServiceURL) { - // add subscriptions - String serviceKey = dubboMetadataServiceURL.getServiceKey(); - subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL); - } - - private void initDubboMetadataServiceProxy(URL dubboMetadataServiceURL) { - String serviceName = dubboMetadataServiceURL.getParameter(APPLICATION_KEY); - String version = dubboMetadataServiceURL.getParameter(VERSION_KEY); - // Initialize DubboMetadataService with right version - dubboMetadataConfigServiceProxy.initProxy(serviceName, version); - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.applicationEventPublisher = applicationEventPublisher; - } +public class DubboServiceMetadataRepository + implements SmartInitializingSingleton, ApplicationEventPublisherAware { + + /** + * The prefix of {@link DubboMetadataService} : "dubbo.metadata-service." + */ + public static final String DUBBO_METADATA_SERVICE_PREFIX = "dubbo.metadata-service."; + + /** + * The {@link URL URLs} property name of {@link DubboMetadataService} : + * "dubbo.metadata-service.urls" + */ + public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = DUBBO_METADATA_SERVICE_PREFIX + + "urls"; + + /** + * The {@link String#format(String, Object...) pattern} of dubbo protocols port + */ + public static final String DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN = "dubbo.protocols.%s.port"; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * Monitor object for synchronization + */ + private final Object monitor = new Object(); + /** + * A {@link Set} of service names that had been initialized + */ + private final Set initializedServices = new LinkedHashSet<>(); + /** + * All exported {@link URL urls} {@link Map} whose key is the return value of + * {@link URL#getServiceKey()} method and value is the {@link List} of {@link URL + * URLs} + */ + private final MultiValueMap allExportedURLs = new LinkedMultiValueMap<>(); + + // =================================== Registration + // =================================== // + /** + * The subscribed {@link URL urls} {@link Map} of {@link DubboMetadataService}, whose + * key is the return value of {@link URL#getServiceKey()} method and value is the + * {@link List} of {@link URL URLs} + */ + private final MultiValueMap subscribedDubboMetadataServiceURLs = new LinkedMultiValueMap<>(); + + // ==================================================================================== + // // + + // =================================== Subscription + // =================================== // + /** + * A Map to store REST metadata temporary, its' key is the special service name for a + * Dubbo service, the value is a JSON content of JAX-RS or Spring MVC REST metadata + * from the annotated methods. + */ + private final Set serviceRestMetadata = new LinkedHashSet<>(); + private ApplicationEventPublisher applicationEventPublisher; + + // ==================================================================================== + // // + + // =================================== REST Metadata + // ================================== // + private volatile Set subscribedServices = emptySet(); + /** + * Key is application name Value is Map + */ + private Map> dubboRestServiceMetadataRepository = newHashMap(); + + // ==================================================================================== + // // + + // =================================== Dependencies + // =================================== // + + @Autowired + private DubboCloudProperties dubboCloudProperties; + + @Autowired + private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; + + @Autowired + private DiscoveryClient discoveryClient; + + @Autowired + private JSONUtils jsonUtils; + + @Autowired + private InetUtils inetUtils; + + @Value("${spring.application.name}") + private String currentApplicationName; + + @Autowired + private DubboMetadataServiceExporter dubboMetadataServiceExporter; + + // ==================================================================================== + // // + + private static Map getMap(Map> repository, + String key) { + return getOrDefault(repository, key, newHashMap()); + } + + private static V getOrDefault(Map source, K key, V defaultValue) { + V value = source.get(key); + if (value == null) { + value = defaultValue; + source.put(key, value); + } + return value; + } + + private static Map newHashMap() { + return new LinkedHashMap<>(); + } + + /** + * Initialize {@link #subscribedServices the subscribed services} + * + * @return + */ + @PostConstruct + public Stream initSubscribedServices() { + Set newSubscribedServices = new LinkedHashSet<>(); + + // If subscribes all services + if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) { + List services = discoveryClient.getServices(); + newSubscribedServices.addAll(services); + if (logger.isWarnEnabled()) { + logger.warn( + "Current application will subscribe all services(size:{}) in registry, " + + "a lot of memory and CPU cycles may be used, " + + "thus it's strongly recommend you using the externalized property '{}' " + + "to specify the services", + newSubscribedServices.size(), "dubbo.cloud.subscribed-services"); + } + } + else { + newSubscribedServices.addAll(dubboCloudProperties.subscribedServices()); + } + + // exclude current application name + excludeSelf(newSubscribedServices); + + // copy from subscribedServices + Set oldSubscribedServices = this.subscribedServices; + + // volatile update subscribedServices to be new one + this.subscribedServices = newSubscribedServices; + + // dispatch SubscribedServicesChangedEvent + dispatchEvent(new SubscribedServicesChangedEvent(this, oldSubscribedServices, + newSubscribedServices)); + + // clear old one, help GC + oldSubscribedServices.clear(); + + return newSubscribedServices.stream(); + } + + private void dispatchEvent(ApplicationEvent event) { + applicationEventPublisher.publishEvent(event); + } + + @Override + public void afterSingletonsInstantiated() { + initializeMetadata(); + } + + /** + * Initialize the metadata + */ + private void initializeMetadata() { + doGetSubscribedServices().forEach(this::initializeMetadata); + if (logger.isInfoEnabled()) { + logger.info("The metadata of Dubbo services has been initialized"); + } + } + + /** + * Initialize the metadata of Dubbo Services + */ + public void initializeMetadata(String serviceName) { + synchronized (monitor) { + if (initializedServices.contains(serviceName)) { + if (logger.isDebugEnabled()) { + logger.debug( + "The metadata of Dubbo service[name : {}] has been initialized", + serviceName); + } + } + else { + if (logger.isInfoEnabled()) { + logger.info( + "The metadata of Dubbo service[name : {}] is about to be initialized", + serviceName); + } + + // Keep the order in following invocations + initSubscribedDubboMetadataService(serviceName); + initDubboRestServiceMetadataRepository(serviceName); + // mark this service name having been initialized + initializedServices.add(serviceName); + } + } + } + + /** + * Get the metadata {@link Map} of {@link DubboMetadataService} + * + * @return non-null read-only {@link Map} + */ + public Map getDubboMetadataServiceMetadata() { + + List dubboMetadataServiceURLs = dubboMetadataServiceExporter.export(); + + // remove the exported URLs of DubboMetadataService + removeDubboMetadataServiceURLs(dubboMetadataServiceURLs); + + Map metadata = newHashMap(); + + addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs); + addDubboProtocolsPortMetadata(metadata); + + return Collections.unmodifiableMap(metadata); + } + + private void removeDubboMetadataServiceURLs(List dubboMetadataServiceURLs) { + dubboMetadataServiceURLs.forEach(this::unexportURL); + } + + private void addDubboMetadataServiceURLsMetadata(Map metadata, + List dubboMetadataServiceURLs) { + String dubboMetadataServiceURLsJSON = jsonUtils.toJSON(dubboMetadataServiceURLs); + metadata.put(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME, + dubboMetadataServiceURLsJSON); + } + + private void addDubboProtocolsPortMetadata(Map metadata) { + + allExportedURLs.values().stream().flatMap(v -> v.stream()).forEach(url -> { + String protocol = url.getProtocol(); + String propertyName = getDubboProtocolPropertyName(protocol); + String propertyValue = valueOf(url.getPort()); + metadata.put(propertyName, propertyValue); + }); + } + + /** + * Get the property name of Dubbo Protocol + * + * @param protocol Dubbo Protocol + * @return non-null + */ + public String getDubboProtocolPropertyName(String protocol) { + return format(DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN, protocol); + } + + /** + * Publish the {@link Set} of {@link ServiceRestMetadata} + * + * @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata} + */ + public void publishServiceRestMetadata( + Set serviceRestMetadataSet) { + for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { + if (!isEmpty(serviceRestMetadata.getMeta())) { + this.serviceRestMetadata.add(serviceRestMetadata); + } + } + } + + /** + * Get the {@link Set} of {@link ServiceRestMetadata} + * + * @return non-null read-only {@link Set} + */ + public Set getServiceRestMetadata() { + return unmodifiableSet(serviceRestMetadata); + } + + public List findSubscribedDubboMetadataServiceURLs(String serviceName, + String group, String version, String protocol) { + String serviceKey = URL.buildKey(serviceName, group, version); + + List urls = null; + + synchronized (monitor) { + urls = subscribedDubboMetadataServiceURLs.get(serviceKey); + } + + if (isEmpty(urls)) { + return emptyList(); + } + + return hasText(protocol) + ? urls.stream() + .filter(url -> url.getProtocol().equalsIgnoreCase(protocol)) + .collect(Collectors.toList()) + : unmodifiableList(urls); + } + + /** + * The specified service is subscribe or not + * + * @param serviceName the service name + * @return + */ + public boolean isSubscribedService(String serviceName) { + return doGetSubscribedServices().contains(serviceName); + } + + public void exportURL(URL url) { + URL actualURL = url; + InetUtils.HostInfo hostInfo = inetUtils.findFirstNonLoopbackHostInfo(); + String ipAddress = hostInfo.getIpAddress(); + // To use InetUtils to set IP if they are different + // issue : + // https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/589 + if (!Objects.equals(url.getHost(), ipAddress)) { + actualURL = url.setHost(ipAddress); + } + this.allExportedURLs.add(actualURL.getServiceKey(), actualURL); + } + + public void unexportURL(URL url) { + String key = url.getServiceKey(); + // NPE issue : + // https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/591 + List urls = allExportedURLs.get(key); + if (!isEmpty(urls)) { + urls.remove(url); + allExportedURLs.addAll(key, urls); + } + } + + /** + * Get all exported {@link URL urls}. + * + * @return non-null read-only + */ + public Map> getAllExportedUrls() { + return unmodifiableMap(allExportedURLs); + } + + /** + * Get all exported {@link URL#getServiceKey() service keys} + * + * @return non-null read-only + */ + public Set getAllServiceKeys() { + return allExportedURLs.keySet(); + } + + /** + * Get the {@link URL urls} that {@link DubboMetadataService} exported by the + * specified {@link ServiceInstance} + * + * @param serviceInstance {@link ServiceInstance} + * @return the mutable {@link URL urls} + */ + public List getDubboMetadataServiceURLs(ServiceInstance serviceInstance) { + Map metadata = serviceInstance.getMetadata(); + String dubboURLsJSON = metadata.get(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME); + return jsonUtils.toURLs(dubboURLsJSON); + } + + public Integer getDubboProtocolPort(ServiceInstance serviceInstance, + String protocol) { + String protocolProperty = getDubboProtocolPropertyName(protocol); + Map metadata = serviceInstance.getMetadata(); + String protocolPort = metadata.get(protocolProperty); + return hasText(protocolPort) ? Integer.valueOf(protocolPort) : null; + } + + public List getExportedURLs(String serviceInterface, String group, + String version) { + String serviceKey = URL.buildKey(serviceInterface, group, version); + return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList()); + } + + /** + * Initialize the specified service's {@link ServiceRestMetadata} + * + * @param serviceName the service name + */ + protected void initDubboRestServiceMetadataRepository(String serviceName) { + + if (dubboRestServiceMetadataRepository.containsKey(serviceName)) { + return; + } + + Set serviceRestMetadataSet = getServiceRestMetadataSet( + serviceName); + + if (isEmpty(serviceRestMetadataSet)) { + if (logger.isWarnEnabled()) { + logger.warn( + "The Spring application[name : {}] does not expose The REST metadata in the Dubbo services.", + serviceName); + } + return; + } + + Map metadataMap = getMetadataMap( + serviceName); + + for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { + + serviceRestMetadata.getMeta().forEach(restMethodMetadata -> { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + RequestMetadataMatcher matcher = new RequestMetadataMatcher( + requestMetadata); + DubboRestServiceMetadata metadata = new DubboRestServiceMetadata( + serviceRestMetadata, restMethodMetadata); + metadataMap.put(matcher, metadata); + }); + } + + if (logger.isInfoEnabled()) { + logger.info( + "The REST metadata in the dubbo services has been loaded in the Spring application[name : {}]", + serviceName); + } + } + + /** + * Get a {@link DubboRestServiceMetadata} by the specified service name if + * {@link RequestMetadata} matched + * + * @param serviceName service name + * @param requestMetadata {@link RequestMetadata} to be matched + * @return {@link DubboRestServiceMetadata} if matched, or null + */ + public DubboRestServiceMetadata get(String serviceName, + RequestMetadata requestMetadata) { + return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata); + } + + /** + * @return not-null + */ + protected Set doGetSubscribedServices() { + Set subscribedServices = this.subscribedServices; + return subscribedServices == null ? emptySet() : subscribedServices; + } + + public Set getSubscribedServices() { + return unmodifiableSet(doGetSubscribedServices()); + } + + private T match(Map> repository, + String serviceName, RequestMetadata requestMetadata) { + + Map map = repository.get(serviceName); + + T object = null; + + if (!isEmpty(map)) { + RequestMetadataMatcher matcher = new RequestMetadataMatcher(requestMetadata); + object = map.get(matcher); + if (object == null) { // Can't match exactly + // Require to match one by one + HttpRequest request = builder().method(requestMetadata.getMethod()) + .path(requestMetadata.getPath()) + .params(requestMetadata.getParams()) + .headers(requestMetadata.getHeaders()).build(); + + for (Map.Entry entry : map.entrySet()) { + RequestMetadataMatcher possibleMatcher = entry.getKey(); + if (possibleMatcher.match(request)) { + object = entry.getValue(); + break; + } + } + } + } + + if (object == null) { + if (logger.isWarnEnabled()) { + logger.warn( + "DubboServiceMetadata can't be found in the Spring application [%s] and %s", + serviceName, requestMetadata); + } + } + + return object; + } + + private Map getMetadataMap( + String serviceName) { + return getMap(dubboRestServiceMetadataRepository, serviceName); + } + + private Set getServiceRestMetadataSet(String serviceName) { + + Set metadata = emptySet(); + + DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy + .getProxy(serviceName); + + if (dubboMetadataService != null) { + try { + String serviceRestMetadataJsonConfig = dubboMetadataService + .getServiceRestMetadata(); + if (hasText(serviceRestMetadataJsonConfig)) { + metadata = objectMapper.readValue(serviceRestMetadataJsonConfig, + TypeFactory.defaultInstance().constructCollectionType( + LinkedHashSet.class, ServiceRestMetadata.class)); + } + } + catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + } + return metadata; + } + + private void excludeSelf(Set subscribedServices) { + subscribedServices.remove(currentApplicationName); + } + + protected void initSubscribedDubboMetadataService(String serviceName) { + discoveryClient.getInstances(serviceName).stream().findAny() + .map(this::getDubboMetadataServiceURLs) + .ifPresent(dubboMetadataServiceURLs -> { + dubboMetadataServiceURLs.forEach(dubboMetadataServiceURL -> { + try { + initSubscribedDubboMetadataServiceURL( + dubboMetadataServiceURL); + initDubboMetadataServiceProxy(dubboMetadataServiceURL); + } + catch (Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + }); + }); + } + + private void initSubscribedDubboMetadataServiceURL(URL dubboMetadataServiceURL) { + // add subscriptions + String serviceKey = dubboMetadataServiceURL.getServiceKey(); + subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL); + } + + private void initDubboMetadataServiceProxy(URL dubboMetadataServiceURL) { + String serviceName = dubboMetadataServiceURL.getParameter(APPLICATION_KEY); + String version = dubboMetadataServiceURL.getParameter(VERSION_KEY); + // Initialize DubboMetadataService with right version + dubboMetadataConfigServiceProxy.initProxy(serviceName, version); + } + + @Override + public void setApplicationEventPublisher( + ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java index 1a1f1eb8c..ce5c0d303 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java @@ -16,21 +16,6 @@ */ package com.alibaba.cloud.dubbo.metadata.resolver; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.config.spring.ServiceBean; - -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; -import feign.Contract; -import feign.Feign; -import feign.MethodMetadata; -import feign.Util; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.util.ClassUtils; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; @@ -42,155 +27,179 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.spring.ServiceBean; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.util.ClassUtils; + +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; +import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; + +import feign.Contract; +import feign.Feign; +import feign.MethodMetadata; +import feign.Util; + /** - * The metadata resolver for {@link Feign} for {@link ServiceBean Dubbo Service Bean} in the provider side. + * The metadata resolver for {@link Feign} for {@link ServiceBean Dubbo Service Bean} in + * the provider side. * * @author Mercy */ -public class DubboServiceBeanMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton, - MetadataResolver { +public class DubboServiceBeanMetadataResolver + implements BeanClassLoaderAware, SmartInitializingSingleton, MetadataResolver { - private static final String[] CONTRACT_CLASS_NAMES = { - "feign.jaxrs2.JAXRS2Contract", - "org.springframework.cloud.openfeign.support.SpringMvcContract", - }; - - private final ObjectProvider contractObjectProvider; - - private ClassLoader classLoader; - - /** - * Feign Contracts - */ - private Collection contracts; - - public DubboServiceBeanMetadataResolver(ObjectProvider contractObjectProvider) { - this.contractObjectProvider = contractObjectProvider; - } - - @Override - public void afterSingletonsInstantiated() { - - LinkedList contracts = new LinkedList<>(); - - // Add injected Contract if available, for example SpringMvcContract Bean under Spring Cloud Open Feign - Contract contract = contractObjectProvider.getIfAvailable(); - - if (contract != null) { - contracts.add(contract); - } - - Stream.of(CONTRACT_CLASS_NAMES) - .filter(this::isClassPresent) // filter the existed classes - .map(this::loadContractClass) // load Contract Class - .map(this::createContract) // createServiceInstance instance by the specified class - .forEach(contracts::add); // add the Contract instance into contracts - - this.contracts = Collections.unmodifiableCollection(contracts); - } - - private Contract createContract(Class contractClassName) { - return (Contract) BeanUtils.instantiateClass(contractClassName); - } - - private Class loadContractClass(String contractClassName) { - return ClassUtils.resolveClassName(contractClassName, classLoader); - } - - private boolean isClassPresent(String className) { - return ClassUtils.isPresent(className, classLoader); - } - - @Override - public Set resolveServiceRestMetadata(ServiceBean serviceBean) { - - Object bean = serviceBean.getRef(); - - Class beanType = bean.getClass(); - - Set serviceRestMetadata = new LinkedHashSet<>(); - - Set methodRestMetadata = resolveMethodRestMetadata(beanType); - - List urls = serviceBean.getExportedUrls(); - - urls.stream() - .map(URL::toString) - .forEach(url -> { - ServiceRestMetadata metadata = new ServiceRestMetadata(); - metadata.setUrl(url); - metadata.setMeta(methodRestMetadata); - serviceRestMetadata.add(metadata); - }); - - return serviceRestMetadata; - } - - @Override - public Set resolveMethodRestMetadata(Class targetType) { - List feignContractMethods = selectFeignContractMethods(targetType); - return contracts.stream() - .map(contract -> parseAndValidateMetadata(contract, targetType)) - .flatMap(v -> v.stream()) - .map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetType, feignContractMethods)) - .collect(Collectors.toSet()); - } - - private List parseAndValidateMetadata(Contract contract, Class targetType) { - List methodMetadataList = Collections.emptyList(); - try { - methodMetadataList = contract.parseAndValidatateMetadata(targetType); - } catch (Throwable ignored) { - // ignore - } - return methodMetadataList; - } - - /** - * Select feign contract methods - *

- * extract some code from {@link Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class)} - * - * @param targetType - * @return non-null - */ - private List selectFeignContractMethods(Class targetType) { - List methods = new LinkedList<>(); - for (Method method : targetType.getMethods()) { - if (method.getDeclaringClass() == Object.class || - (method.getModifiers() & Modifier.STATIC) != 0 || - Util.isDefault(method)) { - continue; - } - methods.add(method); - } - return methods; - } - - protected RestMethodMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class targetType, - List feignContractMethods) { - String configKey = methodMetadata.configKey(); - Method feignContractMethod = getMatchedFeignContractMethod(targetType, feignContractMethods, configKey); - RestMethodMetadata metadata = new RestMethodMetadata(methodMetadata); - metadata.setMethod(new com.alibaba.cloud.dubbo.metadata.MethodMetadata(feignContractMethod)); - return metadata; - } - - private Method getMatchedFeignContractMethod(Class targetType, List methods, String expectedConfigKey) { - Method matchedMethod = null; - for (Method method : methods) { - String configKey = Feign.configKey(targetType, method); - if (expectedConfigKey.equals(configKey)) { - matchedMethod = method; - break; - } - } - return matchedMethod; - } - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } + private static final String[] CONTRACT_CLASS_NAMES = { "feign.jaxrs2.JAXRS2Contract", + "org.springframework.cloud.openfeign.support.SpringMvcContract", }; + + private final ObjectProvider contractObjectProvider; + + private ClassLoader classLoader; + + /** + * Feign Contracts + */ + private Collection contracts; + + public DubboServiceBeanMetadataResolver( + ObjectProvider contractObjectProvider) { + this.contractObjectProvider = contractObjectProvider; + } + + @Override + public void afterSingletonsInstantiated() { + + LinkedList contracts = new LinkedList<>(); + + // Add injected Contract if available, for example SpringMvcContract Bean under + // Spring Cloud Open Feign + Contract contract = contractObjectProvider.getIfAvailable(); + + if (contract != null) { + contracts.add(contract); + } + + Stream.of(CONTRACT_CLASS_NAMES).filter(this::isClassPresent) // filter the existed + // classes + .map(this::loadContractClass) // load Contract Class + .map(this::createContract) // createServiceInstance instance by the + // specified class + .forEach(contracts::add); // add the Contract instance into contracts + + this.contracts = Collections.unmodifiableCollection(contracts); + } + + private Contract createContract(Class contractClassName) { + return (Contract) BeanUtils.instantiateClass(contractClassName); + } + + private Class loadContractClass(String contractClassName) { + return ClassUtils.resolveClassName(contractClassName, classLoader); + } + + private boolean isClassPresent(String className) { + return ClassUtils.isPresent(className, classLoader); + } + + @Override + public Set resolveServiceRestMetadata(ServiceBean serviceBean) { + + Object bean = serviceBean.getRef(); + + Class beanType = bean.getClass(); + + Set serviceRestMetadata = new LinkedHashSet<>(); + + Set methodRestMetadata = resolveMethodRestMetadata(beanType); + + List urls = serviceBean.getExportedUrls(); + + urls.stream().map(URL::toString).forEach(url -> { + ServiceRestMetadata metadata = new ServiceRestMetadata(); + metadata.setUrl(url); + metadata.setMeta(methodRestMetadata); + serviceRestMetadata.add(metadata); + }); + + return serviceRestMetadata; + } + + @Override + public Set resolveMethodRestMetadata(Class targetType) { + List feignContractMethods = selectFeignContractMethods(targetType); + return contracts.stream() + .map(contract -> parseAndValidateMetadata(contract, targetType)) + .flatMap(v -> v.stream()) + .map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, + targetType, feignContractMethods)) + .collect(Collectors.toSet()); + } + + private List parseAndValidateMetadata(Contract contract, + Class targetType) { + List methodMetadataList = Collections.emptyList(); + try { + methodMetadataList = contract.parseAndValidatateMetadata(targetType); + } + catch (Throwable ignored) { + // ignore + } + return methodMetadataList; + } + + /** + * Select feign contract methods + *

+ * extract some code from + * {@link Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class)} + * + * @param targetType + * @return non-null + */ + private List selectFeignContractMethods(Class targetType) { + List methods = new LinkedList<>(); + for (Method method : targetType.getMethods()) { + if (method.getDeclaringClass() == Object.class + || (method.getModifiers() & Modifier.STATIC) != 0 + || Util.isDefault(method)) { + continue; + } + methods.add(method); + } + return methods; + } + + protected RestMethodMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, + Class targetType, List feignContractMethods) { + String configKey = methodMetadata.configKey(); + Method feignContractMethod = getMatchedFeignContractMethod(targetType, + feignContractMethods, configKey); + RestMethodMetadata metadata = new RestMethodMetadata(methodMetadata); + metadata.setMethod( + new com.alibaba.cloud.dubbo.metadata.MethodMetadata(feignContractMethod)); + return metadata; + } + + private Method getMatchedFeignContractMethod(Class targetType, + List methods, String expectedConfigKey) { + Method matchedMethod = null; + for (Method method : methods) { + String configKey = Feign.configKey(targetType, method); + if (expectedConfigKey.equals(configKey)) { + matchedMethod = method; + break; + } + } + return matchedMethod; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedAttributesResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedAttributesResolver.java index 213576610..aafd94ca4 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedAttributesResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedAttributesResolver.java @@ -16,13 +16,14 @@ */ package com.alibaba.cloud.dubbo.metadata.resolver; -import com.alibaba.cloud.dubbo.annotation.DubboTransported; -import org.springframework.core.env.PropertyResolver; +import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; import java.util.LinkedHashMap; import java.util.Map; -import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; +import org.springframework.core.env.PropertyResolver; + +import com.alibaba.cloud.dubbo.annotation.DubboTransported; /** * {@link DubboTransported} annotation attributes resolver @@ -31,26 +32,26 @@ import static org.springframework.core.annotation.AnnotationUtils.getAnnotationA */ public class DubboTransportedAttributesResolver { - private final PropertyResolver propertyResolver; - - public DubboTransportedAttributesResolver(PropertyResolver propertyResolver) { - this.propertyResolver = propertyResolver; - } - - public Map resolve(DubboTransported dubboTransported) { - Map attributes = getAnnotationAttributes(dubboTransported); - return resolve(attributes); - } - - public Map resolve(Map attributes) { - Map resolvedAttributes = new LinkedHashMap<>(); - for (Map.Entry entry : attributes.entrySet()) { - Object value = entry.getValue(); - if (value instanceof String) { - value = propertyResolver.resolvePlaceholders(value.toString()); - } - resolvedAttributes.put(entry.getKey(), value); - } - return resolvedAttributes; - } + private final PropertyResolver propertyResolver; + + public DubboTransportedAttributesResolver(PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + } + + public Map resolve(DubboTransported dubboTransported) { + Map attributes = getAnnotationAttributes(dubboTransported); + return resolve(attributes); + } + + public Map resolve(Map attributes) { + Map resolvedAttributes = new LinkedHashMap<>(); + for (Map.Entry entry : attributes.entrySet()) { + Object value = entry.getValue(); + if (value instanceof String) { + value = propertyResolver.resolvePlaceholders(value.toString()); + } + resolvedAttributes.put(entry.getKey(), value); + } + return resolvedAttributes; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolver.java index c5fda32f5..8ef053795 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolver.java @@ -16,13 +16,7 @@ */ package com.alibaba.cloud.dubbo.metadata.resolver; -import com.alibaba.cloud.dubbo.annotation.DubboTransported; -import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata; -import com.alibaba.cloud.dubbo.metadata.MethodMetadata; -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import feign.Contract; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.env.PropertyResolver; +import static feign.Feign.configKey; import java.lang.reflect.Method; import java.util.LinkedHashSet; @@ -30,79 +24,96 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import static feign.Feign.configKey; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.env.PropertyResolver; + +import com.alibaba.cloud.dubbo.annotation.DubboTransported; +import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata; +import com.alibaba.cloud.dubbo.metadata.MethodMetadata; +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; + +import feign.Contract; /** - * {@link MethodMetadata} Resolver for the {@link DubboTransported} annotated classes or methods in client side. + * {@link MethodMetadata} Resolver for the {@link DubboTransported} annotated classes or + * methods in client side. * * @author Mercy * @see DubboTransportedMethodMetadata */ public class DubboTransportedMethodMetadataResolver { - private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class; - - private final DubboTransportedAttributesResolver attributesResolver; - - private final Contract contract; - - public DubboTransportedMethodMetadataResolver(PropertyResolver propertyResolver, Contract contract) { - this.attributesResolver = new DubboTransportedAttributesResolver(propertyResolver); - this.contract = contract; - } - - public Map resolve(Class targetType) { - Set dubboTransportedMethodMetadataSet = - resolveDubboTransportedMethodMetadataSet(targetType); - Map restMethodMetadataMap = resolveRestRequestMetadataMap(targetType); - return dubboTransportedMethodMetadataSet - .stream() - .collect(Collectors.toMap(methodMetadata -> methodMetadata, methodMetadata -> { - RestMethodMetadata restMethodMetadata = restMethodMetadataMap.get(configKey(targetType, methodMetadata.getMethod())); - restMethodMetadata.setMethod(methodMetadata.getMethodMetadata()); - return restMethodMetadata; - } - )); - } - - protected Set resolveDubboTransportedMethodMetadataSet(Class targetType) { - // The public methods of target interface - Method[] methods = targetType.getMethods(); - - Set methodMetadataSet = new LinkedHashSet<>(); - - for (Method method : methods) { - DubboTransported dubboTransported = resolveDubboTransported(method); - if (dubboTransported != null) { - DubboTransportedMethodMetadata methodMetadata = createDubboTransportedMethodMetadata(method, dubboTransported); - methodMetadataSet.add(methodMetadata); - } - } - return methodMetadataSet; - } - - - private Map resolveRestRequestMetadataMap(Class targetType) { - return contract.parseAndValidatateMetadata(targetType) - .stream().collect(Collectors.toMap(feign.MethodMetadata::configKey, this::restMethodMetadata)); - } - - private RestMethodMetadata restMethodMetadata(feign.MethodMetadata methodMetadata) { - return new RestMethodMetadata(methodMetadata); - } - - private DubboTransportedMethodMetadata createDubboTransportedMethodMetadata(Method method, - DubboTransported dubboTransported) { - Map attributes = attributesResolver.resolve(dubboTransported); - return new DubboTransportedMethodMetadata(method, attributes); - } - - private DubboTransported resolveDubboTransported(Method method) { - DubboTransported dubboTransported = AnnotationUtils.findAnnotation(method, DUBBO_TRANSPORTED_CLASS); - if (dubboTransported == null) { // Attempt to find @DubboTransported in the declaring class - Class declaringClass = method.getDeclaringClass(); - dubboTransported = AnnotationUtils.findAnnotation(declaringClass, DUBBO_TRANSPORTED_CLASS); - } - return dubboTransported; - } + private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class; + + private final DubboTransportedAttributesResolver attributesResolver; + + private final Contract contract; + + public DubboTransportedMethodMetadataResolver(PropertyResolver propertyResolver, + Contract contract) { + this.attributesResolver = new DubboTransportedAttributesResolver( + propertyResolver); + this.contract = contract; + } + + public Map resolve( + Class targetType) { + Set dubboTransportedMethodMetadataSet = resolveDubboTransportedMethodMetadataSet( + targetType); + Map restMethodMetadataMap = resolveRestRequestMetadataMap( + targetType); + return dubboTransportedMethodMetadataSet.stream().collect( + Collectors.toMap(methodMetadata -> methodMetadata, methodMetadata -> { + RestMethodMetadata restMethodMetadata = restMethodMetadataMap + .get(configKey(targetType, methodMetadata.getMethod())); + restMethodMetadata.setMethod(methodMetadata.getMethodMetadata()); + return restMethodMetadata; + })); + } + + protected Set resolveDubboTransportedMethodMetadataSet( + Class targetType) { + // The public methods of target interface + Method[] methods = targetType.getMethods(); + + Set methodMetadataSet = new LinkedHashSet<>(); + + for (Method method : methods) { + DubboTransported dubboTransported = resolveDubboTransported(method); + if (dubboTransported != null) { + DubboTransportedMethodMetadata methodMetadata = createDubboTransportedMethodMetadata( + method, dubboTransported); + methodMetadataSet.add(methodMetadata); + } + } + return methodMetadataSet; + } + + private Map resolveRestRequestMetadataMap( + Class targetType) { + return contract.parseAndValidatateMetadata(targetType).stream().collect(Collectors + .toMap(feign.MethodMetadata::configKey, this::restMethodMetadata)); + } + + private RestMethodMetadata restMethodMetadata(feign.MethodMetadata methodMetadata) { + return new RestMethodMetadata(methodMetadata); + } + + private DubboTransportedMethodMetadata createDubboTransportedMethodMetadata( + Method method, DubboTransported dubboTransported) { + Map attributes = attributesResolver.resolve(dubboTransported); + return new DubboTransportedMethodMetadata(method, attributes); + } + + private DubboTransported resolveDubboTransported(Method method) { + DubboTransported dubboTransported = AnnotationUtils.findAnnotation(method, + DUBBO_TRANSPORTED_CLASS); + if (dubboTransported == null) { // Attempt to find @DubboTransported in the + // declaring class + Class declaringClass = method.getDeclaringClass(); + dubboTransported = AnnotationUtils.findAnnotation(declaringClass, + DUBBO_TRANSPORTED_CLASS); + } + return dubboTransported; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/MetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/MetadataResolver.java index fa7cbb0b7..3938d8b8d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/MetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/MetadataResolver.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.metadata.resolver; +import java.util.Set; + import org.apache.dubbo.config.spring.ServiceBean; import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; -import java.util.Set; - /** * The REST metadata resolver * @@ -30,19 +30,19 @@ import java.util.Set; */ public interface MetadataResolver { - /** - * Resolve the {@link ServiceRestMetadata} {@link Set set} from {@link ServiceBean} - * - * @param serviceBean {@link ServiceBean} - * @return non-null {@link Set} - */ - Set resolveServiceRestMetadata(ServiceBean serviceBean); + /** + * Resolve the {@link ServiceRestMetadata} {@link Set set} from {@link ServiceBean} + * + * @param serviceBean {@link ServiceBean} + * @return non-null {@link Set} + */ + Set resolveServiceRestMetadata(ServiceBean serviceBean); - /** - * Resolve {@link RestMethodMetadata} {@link Set set} from {@link Class target type} - * - * @param targetType {@link Class target type} - * @return non-null {@link Set} - */ - Set resolveMethodRestMetadata(Class targetType); + /** + * Resolve {@link RestMethodMetadata} {@link Set set} from {@link Class target type} + * + * @param targetType {@link Class target type} + * @return non-null {@link Set} + */ + Set resolveMethodRestMetadata(Class targetType); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java index 6bd21d066..3242dc850 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java @@ -16,18 +16,19 @@ */ package com.alibaba.cloud.dubbo.openfeign; -import org.apache.dubbo.rpc.service.GenericService; - -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContext; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; -import org.springframework.util.ClassUtils; +import static org.apache.dubbo.common.utils.PojoUtils.realize; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map; -import static org.apache.dubbo.common.utils.PojoUtils.realize; +import org.apache.dubbo.rpc.service.GenericService; + +import org.springframework.util.ClassUtils; + +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContext; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; /** * Dubbo {@link GenericService} for {@link InvocationHandler} @@ -36,52 +37,56 @@ import static org.apache.dubbo.common.utils.PojoUtils.realize; */ public class DubboInvocationHandler implements InvocationHandler { - private final Map feignMethodMetadataMap; + private final Map feignMethodMetadataMap; - private final InvocationHandler defaultInvocationHandler; + private final InvocationHandler defaultInvocationHandler; - private final DubboGenericServiceExecutionContextFactory contextFactory; + private final DubboGenericServiceExecutionContextFactory contextFactory; - private final ClassLoader classLoader; + private final ClassLoader classLoader; - public DubboInvocationHandler(Map feignMethodMetadataMap, - InvocationHandler defaultInvocationHandler, - ClassLoader classLoader, - DubboGenericServiceExecutionContextFactory contextFactory) { - this.feignMethodMetadataMap = feignMethodMetadataMap; - this.defaultInvocationHandler = defaultInvocationHandler; - this.classLoader = classLoader; - this.contextFactory = contextFactory; - } + public DubboInvocationHandler(Map feignMethodMetadataMap, + InvocationHandler defaultInvocationHandler, ClassLoader classLoader, + DubboGenericServiceExecutionContextFactory contextFactory) { + this.feignMethodMetadataMap = feignMethodMetadataMap; + this.defaultInvocationHandler = defaultInvocationHandler; + this.classLoader = classLoader; + this.contextFactory = contextFactory; + } - @Override - public Object invoke(Object proxy, Method feignMethod, Object[] args) throws Throwable { + @Override + public Object invoke(Object proxy, Method feignMethod, Object[] args) + throws Throwable { - FeignMethodMetadata feignMethodMetadata = feignMethodMetadataMap.get(feignMethod); + FeignMethodMetadata feignMethodMetadata = feignMethodMetadataMap.get(feignMethod); - if (feignMethodMetadata == null) { - return defaultInvocationHandler.invoke(proxy, feignMethod, args); - } + if (feignMethodMetadata == null) { + return defaultInvocationHandler.invoke(proxy, feignMethod, args); + } - GenericService dubboGenericService = feignMethodMetadata.getDubboGenericService(); - RestMethodMetadata dubboRestMethodMetadata = feignMethodMetadata.getDubboRestMethodMetadata(); - RestMethodMetadata feignRestMethodMetadata = feignMethodMetadata.getFeignMethodMetadata(); + GenericService dubboGenericService = feignMethodMetadata.getDubboGenericService(); + RestMethodMetadata dubboRestMethodMetadata = feignMethodMetadata + .getDubboRestMethodMetadata(); + RestMethodMetadata feignRestMethodMetadata = feignMethodMetadata + .getFeignMethodMetadata(); - DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, feignRestMethodMetadata, args); + DubboGenericServiceExecutionContext context = contextFactory + .create(dubboRestMethodMetadata, feignRestMethodMetadata, args); - String methodName = context.getMethodName(); - String[] parameterTypes = context.getParameterTypes(); - Object[] parameters = context.getParameters(); + String methodName = context.getMethodName(); + String[] parameterTypes = context.getParameterTypes(); + Object[] parameters = context.getParameters(); - Object result = dubboGenericService.$invoke(methodName, parameterTypes, parameters); + Object result = dubboGenericService.$invoke(methodName, parameterTypes, + parameters); - Class returnType = getReturnType(dubboRestMethodMetadata); + Class returnType = getReturnType(dubboRestMethodMetadata); - return realize(result, returnType); - } + return realize(result, returnType); + } - private Class getReturnType(RestMethodMetadata dubboRestMethodMetadata) { - String returnType = dubboRestMethodMetadata.getReturnType(); - return ClassUtils.resolveClassName(returnType, classLoader); - } + private Class getReturnType(RestMethodMetadata dubboRestMethodMetadata) { + String returnType = dubboRestMethodMetadata.getReturnType(); + return ClassUtils.resolveClassName(returnType, classLoader); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/FeignMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/FeignMethodMetadata.java index f646c133c..e2fb23bf9 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/FeignMethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/FeignMethodMetadata.java @@ -16,12 +16,12 @@ */ package com.alibaba.cloud.dubbo.openfeign; +import java.lang.reflect.Method; + import org.apache.dubbo.rpc.service.GenericService; import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import java.lang.reflect.Method; - /** * Feign {@link Method} Metadata * @@ -29,29 +29,29 @@ import java.lang.reflect.Method; */ class FeignMethodMetadata { - private final GenericService dubboGenericService; - - private final RestMethodMetadata dubboRestMethodMetadata; + private final GenericService dubboGenericService; - private final RestMethodMetadata feignMethodMetadata; + private final RestMethodMetadata dubboRestMethodMetadata; + private final RestMethodMetadata feignMethodMetadata; - FeignMethodMetadata(GenericService dubboGenericService, RestMethodMetadata dubboRestMethodMetadata, - RestMethodMetadata feignMethodMetadata) { - this.dubboGenericService = dubboGenericService; - this.dubboRestMethodMetadata = dubboRestMethodMetadata; - this.feignMethodMetadata = feignMethodMetadata; - } + FeignMethodMetadata(GenericService dubboGenericService, + RestMethodMetadata dubboRestMethodMetadata, + RestMethodMetadata feignMethodMetadata) { + this.dubboGenericService = dubboGenericService; + this.dubboRestMethodMetadata = dubboRestMethodMetadata; + this.feignMethodMetadata = feignMethodMetadata; + } - GenericService getDubboGenericService() { - return dubboGenericService; - } + GenericService getDubboGenericService() { + return dubboGenericService; + } - RestMethodMetadata getDubboRestMethodMetadata() { - return dubboRestMethodMetadata; - } + RestMethodMetadata getDubboRestMethodMetadata() { + return dubboRestMethodMetadata; + } - RestMethodMetadata getFeignMethodMetadata() { - return feignMethodMetadata; - } + RestMethodMetadata getFeignMethodMetadata() { + return feignMethodMetadata; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterBeanPostProcessor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterBeanPostProcessor.java index 222c2a799..e1d0c9d90 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterBeanPostProcessor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterBeanPostProcessor.java @@ -16,68 +16,73 @@ */ package com.alibaba.cloud.dubbo.openfeign; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; -import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.core.env.Environment; - import static com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.TARGETER_CLASS_NAME; import static java.lang.reflect.Proxy.newProxyInstance; import static org.springframework.util.ClassUtils.getUserClass; import static org.springframework.util.ClassUtils.isPresent; import static org.springframework.util.ClassUtils.resolveClassName; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.env.Environment; + +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; +import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; + /** * org.springframework.cloud.openfeign.Targeter {@link BeanPostProcessor} * * @author Mercy */ -public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLoaderAware { +public class TargeterBeanPostProcessor + implements BeanPostProcessor, BeanClassLoaderAware { - private final Environment environment; + private final Environment environment; - private final DubboServiceMetadataRepository dubboServiceMetadataRepository; + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; - private final DubboGenericServiceFactory dubboGenericServiceFactory; + private final DubboGenericServiceFactory dubboGenericServiceFactory; - private final DubboGenericServiceExecutionContextFactory contextFactory; + private final DubboGenericServiceExecutionContextFactory contextFactory; - private ClassLoader classLoader; + private ClassLoader classLoader; - public TargeterBeanPostProcessor(Environment environment, - DubboServiceMetadataRepository dubboServiceMetadataRepository, - DubboGenericServiceFactory dubboGenericServiceFactory, - DubboGenericServiceExecutionContextFactory contextFactory) { - this.environment = environment; - this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; - this.dubboGenericServiceFactory = dubboGenericServiceFactory; - this.contextFactory = contextFactory; - } + public TargeterBeanPostProcessor(Environment environment, + DubboServiceMetadataRepository dubboServiceMetadataRepository, + DubboGenericServiceFactory dubboGenericServiceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { + this.environment = environment; + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + this.dubboGenericServiceFactory = dubboGenericServiceFactory; + this.contextFactory = contextFactory; + } - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } - @Override - public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { - if (isPresent(TARGETER_CLASS_NAME, classLoader)) { - Class beanClass = getUserClass(bean.getClass()); - Class targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader); - if (targetClass.isAssignableFrom(beanClass)) { - return newProxyInstance(classLoader, new Class[]{targetClass}, - new TargeterInvocationHandler(bean, environment, classLoader, dubboServiceMetadataRepository, - dubboGenericServiceFactory, contextFactory)); - } - } - return bean; - } + @Override + public Object postProcessAfterInitialization(final Object bean, String beanName) + throws BeansException { + if (isPresent(TARGETER_CLASS_NAME, classLoader)) { + Class beanClass = getUserClass(bean.getClass()); + Class targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader); + if (targetClass.isAssignableFrom(beanClass)) { + return newProxyInstance(classLoader, new Class[] { targetClass }, + new TargeterInvocationHandler(bean, environment, classLoader, + dubboServiceMetadataRepository, + dubboGenericServiceFactory, contextFactory)); + } + } + return bean; + } - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java index 7b1bc5063..c2b335d58 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java @@ -16,9 +16,21 @@ */ package com.alibaba.cloud.dubbo.openfeign; +import static java.lang.reflect.Proxy.newProxyInstance; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; import org.apache.dubbo.rpc.service.GenericService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.openfeign.FeignContext; +import org.springframework.core.env.Environment; + import com.alibaba.cloud.dubbo.annotation.DubboTransported; import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata; @@ -29,20 +41,9 @@ import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepositor import com.alibaba.cloud.dubbo.metadata.resolver.DubboTransportedMethodMetadataResolver; import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory; import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; + import feign.Contract; import feign.Target; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.openfeign.FeignContext; -import org.springframework.core.env.Environment; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.HashMap; -import java.util.Map; - -import static java.lang.reflect.Proxy.newProxyInstance; /** * org.springframework.cloud.openfeign.Targeter {@link InvocationHandler} @@ -51,125 +52,137 @@ import static java.lang.reflect.Proxy.newProxyInstance; */ class TargeterInvocationHandler implements InvocationHandler { - private final Logger logger = LoggerFactory.getLogger(getClass()); + private final Logger logger = LoggerFactory.getLogger(getClass()); - private final Object bean; + private final Object bean; - private final Environment environment; + private final Environment environment; - private final ClassLoader classLoader; + private final ClassLoader classLoader; - private final DubboServiceMetadataRepository repository; + private final DubboServiceMetadataRepository repository; - private final DubboGenericServiceFactory dubboGenericServiceFactory; + private final DubboGenericServiceFactory dubboGenericServiceFactory; - private final DubboGenericServiceExecutionContextFactory contextFactory; + private final DubboGenericServiceExecutionContextFactory contextFactory; - TargeterInvocationHandler(Object bean, Environment environment, - ClassLoader classLoader, - DubboServiceMetadataRepository repository, - DubboGenericServiceFactory dubboGenericServiceFactory, - DubboGenericServiceExecutionContextFactory contextFactory) { - this.bean = bean; - this.environment = environment; - this.classLoader = classLoader; - this.repository = repository; - this.dubboGenericServiceFactory = dubboGenericServiceFactory; - this.contextFactory = contextFactory; - } - - private static T cast(Object object) { - return (T) object; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - /** - * args[0]: FeignClientFactoryBean factory - * args[1]: Feign.Builder feign - * args[2]: FeignContext context - * args[3]: Target.HardCodedTarget target - */ - FeignContext feignContext = cast(args[2]); - Target.HardCodedTarget target = cast(args[3]); - - // Execute Targeter#target method first - method.setAccessible(true); - // Get the default proxy object - Object defaultProxy = method.invoke(bean, args); - // Create Dubbo Proxy if required - return createDubboProxyIfRequired(feignContext, target, defaultProxy); - } - - private Object createDubboProxyIfRequired(FeignContext feignContext, Target target, Object defaultProxy) { - - DubboInvocationHandler dubboInvocationHandler = createDubboInvocationHandler(feignContext, target, defaultProxy); - - if (dubboInvocationHandler == null) { - return defaultProxy; - } - - return newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, dubboInvocationHandler); - } - - private DubboInvocationHandler createDubboInvocationHandler(FeignContext feignContext, Target target, - Object defaultFeignClientProxy) { - - // Service name equals @FeignClient.name() - String serviceName = target.name(); - Class targetType = target.type(); - - // Get Contract Bean from FeignContext - Contract contract = feignContext.getInstance(serviceName, Contract.class); - - DubboTransportedMethodMetadataResolver resolver = - new DubboTransportedMethodMetadataResolver(environment, contract); - - Map feignRestMethodMetadataMap = resolver.resolve(targetType); - - if (feignRestMethodMetadataMap.isEmpty()) { // @DubboTransported method was not found from the Client interface - if (logger.isDebugEnabled()) { - logger.debug("@{} method was not found in the Feign target type[{}]", - DubboTransported.class.getSimpleName(), targetType.getName()); - } - return null; - } - - // Update Metadata - repository.initializeMetadata(serviceName); - - Map feignMethodMetadataMap = getFeignMethodMetadataMap(serviceName, feignRestMethodMetadataMap); - - InvocationHandler defaultFeignClientInvocationHandler = Proxy.getInvocationHandler(defaultFeignClientProxy); - - DubboInvocationHandler dubboInvocationHandler = new DubboInvocationHandler(feignMethodMetadataMap, - defaultFeignClientInvocationHandler, classLoader, contextFactory); - - return dubboInvocationHandler; - } - - private Map getFeignMethodMetadataMap(String serviceName, - Map - feignRestMethodMetadataMap) { - Map feignMethodMetadataMap = new HashMap<>(); - - for (Map.Entry entry : feignRestMethodMetadataMap.entrySet()) { - RestMethodMetadata feignRestMethodMetadata = entry.getValue(); - RequestMetadata feignRequestMetadata = feignRestMethodMetadata.getRequest(); - DubboRestServiceMetadata metadata = repository.get(serviceName, feignRequestMetadata); - if (metadata != null) { - DubboTransportedMethodMetadata dubboTransportedMethodMetadata = entry.getKey(); - Map dubboTranslatedAttributes = dubboTransportedMethodMetadata.getAttributes(); - Method method = dubboTransportedMethodMetadata.getMethod(); - GenericService dubboGenericService = dubboGenericServiceFactory.create(metadata, dubboTranslatedAttributes); - RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata(); - MethodMetadata methodMetadata = dubboTransportedMethodMetadata.getMethodMetadata(); - FeignMethodMetadata feignMethodMetadata = new FeignMethodMetadata(dubboGenericService, - dubboRestMethodMetadata, feignRestMethodMetadata); - feignMethodMetadataMap.put(method, feignMethodMetadata); - } - } - - return feignMethodMetadataMap; - } + TargeterInvocationHandler(Object bean, Environment environment, + ClassLoader classLoader, DubboServiceMetadataRepository repository, + DubboGenericServiceFactory dubboGenericServiceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { + this.bean = bean; + this.environment = environment; + this.classLoader = classLoader; + this.repository = repository; + this.dubboGenericServiceFactory = dubboGenericServiceFactory; + this.contextFactory = contextFactory; + } + + private static T cast(Object object) { + return (T) object; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + /** + * args[0]: FeignClientFactoryBean factory args[1]: Feign.Builder feign args[2]: + * FeignContext context args[3]: Target.HardCodedTarget target + */ + FeignContext feignContext = cast(args[2]); + Target.HardCodedTarget target = cast(args[3]); + + // Execute Targeter#target method first + method.setAccessible(true); + // Get the default proxy object + Object defaultProxy = method.invoke(bean, args); + // Create Dubbo Proxy if required + return createDubboProxyIfRequired(feignContext, target, defaultProxy); + } + + private Object createDubboProxyIfRequired(FeignContext feignContext, Target target, + Object defaultProxy) { + + DubboInvocationHandler dubboInvocationHandler = createDubboInvocationHandler( + feignContext, target, defaultProxy); + + if (dubboInvocationHandler == null) { + return defaultProxy; + } + + return newProxyInstance(target.type().getClassLoader(), + new Class[] { target.type() }, dubboInvocationHandler); + } + + private DubboInvocationHandler createDubboInvocationHandler(FeignContext feignContext, + Target target, Object defaultFeignClientProxy) { + + // Service name equals @FeignClient.name() + String serviceName = target.name(); + Class targetType = target.type(); + + // Get Contract Bean from FeignContext + Contract contract = feignContext.getInstance(serviceName, Contract.class); + + DubboTransportedMethodMetadataResolver resolver = new DubboTransportedMethodMetadataResolver( + environment, contract); + + Map feignRestMethodMetadataMap = resolver + .resolve(targetType); + + if (feignRestMethodMetadataMap.isEmpty()) { // @DubboTransported method was not + // found from the Client interface + if (logger.isDebugEnabled()) { + logger.debug("@{} method was not found in the Feign target type[{}]", + DubboTransported.class.getSimpleName(), targetType.getName()); + } + return null; + } + + // Update Metadata + repository.initializeMetadata(serviceName); + + Map feignMethodMetadataMap = getFeignMethodMetadataMap( + serviceName, feignRestMethodMetadataMap); + + InvocationHandler defaultFeignClientInvocationHandler = Proxy + .getInvocationHandler(defaultFeignClientProxy); + + DubboInvocationHandler dubboInvocationHandler = new DubboInvocationHandler( + feignMethodMetadataMap, defaultFeignClientInvocationHandler, classLoader, + contextFactory); + + return dubboInvocationHandler; + } + + private Map getFeignMethodMetadataMap(String serviceName, + Map feignRestMethodMetadataMap) { + Map feignMethodMetadataMap = new HashMap<>(); + + for (Map.Entry entry : feignRestMethodMetadataMap + .entrySet()) { + RestMethodMetadata feignRestMethodMetadata = entry.getValue(); + RequestMetadata feignRequestMetadata = feignRestMethodMetadata.getRequest(); + DubboRestServiceMetadata metadata = repository.get(serviceName, + feignRequestMetadata); + if (metadata != null) { + DubboTransportedMethodMetadata dubboTransportedMethodMetadata = entry + .getKey(); + Map dubboTranslatedAttributes = dubboTransportedMethodMetadata + .getAttributes(); + Method method = dubboTransportedMethodMetadata.getMethod(); + GenericService dubboGenericService = dubboGenericServiceFactory + .create(metadata, dubboTranslatedAttributes); + RestMethodMetadata dubboRestMethodMetadata = metadata + .getRestMethodMetadata(); + MethodMetadata methodMetadata = dubboTransportedMethodMetadata + .getMethodMetadata(); + FeignMethodMetadata feignMethodMetadata = new FeignMethodMetadata( + dubboGenericService, dubboRestMethodMetadata, + feignRestMethodMetadata); + feignMethodMetadataMap.put(method, feignMethodMetadata); + } + } + + return feignMethodMetadataMap; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java index 615f9d444..922553ab8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java @@ -16,16 +16,31 @@ */ package com.alibaba.cloud.dubbo.registry; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.apache.dubbo.common.URLBuilder.from; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; +import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL; +import static org.springframework.util.StringUtils.hasText; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.RegistryFactory; import org.apache.dubbo.registry.support.FailbackRegistry; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; -import com.alibaba.cloud.dubbo.service.DubboMetadataService; -import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; -import com.alibaba.cloud.dubbo.util.JSONUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.ServiceInstance; @@ -34,301 +49,316 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.CollectionUtils; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.apache.dubbo.common.URLBuilder.from; -import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; -import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; -import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; -import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL; -import static org.springframework.util.StringUtils.hasText; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; +import com.alibaba.cloud.dubbo.service.DubboMetadataService; +import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; +import com.alibaba.cloud.dubbo.util.JSONUtils; /** - * Abstract Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * Abstract Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration + * abstraction, whose protocol is "spring-cloud" * * @author Mercy */ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { - /** - * The parameter name of {@link #servicesLookupInterval} - */ - public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval"; - - protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName(); - /** - * Caches the IDs of {@link ApplicationListener} - */ - private static final Set registerListeners = new HashSet<>(); - - protected final Logger logger = LoggerFactory.getLogger(getClass()); - - /** - * The interval in second of lookup service names(only for Dubbo-OPS) - */ - private final long servicesLookupInterval; - - private final DiscoveryClient discoveryClient; - - private final DubboServiceMetadataRepository repository; - - private final DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; - - private final JSONUtils jsonUtils; - - private final ConfigurableApplicationContext applicationContext; - - public AbstractSpringCloudRegistry(URL url, - DiscoveryClient discoveryClient, - DubboServiceMetadataRepository dubboServiceMetadataRepository, - DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, - JSONUtils jsonUtils, - ConfigurableApplicationContext applicationContext) { - super(url); - this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L); - this.discoveryClient = discoveryClient; - this.repository = dubboServiceMetadataRepository; - this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy; - this.jsonUtils = jsonUtils; - this.applicationContext = applicationContext; - } - - protected boolean shouldRegister(URL url) { - String side = url.getParameter(SIDE_KEY); - - boolean should = PROVIDER_SIDE.equals(side); // Only register the Provider. - - if (!should) { - if (logger.isDebugEnabled()) { - logger.debug("The URL[{}] should not be registered.", url.toString()); - } - } - - return should; - } - - @Override - public final void doRegister(URL url) { - if (!shouldRegister(url)) { - return; - } - doRegister0(url); - } - - /** - * The sub-type should implement to register - * - * @param url {@link URL} - */ - protected abstract void doRegister0(URL url); - - @Override - public final void doUnregister(URL url) { - if (!shouldRegister(url)) { - return; - } - doUnregister0(url); - } - - /** - * The sub-type should implement to unregister - * - * @param url {@link URL} - */ - protected abstract void doUnregister0(URL url); - - @Override - public final void doSubscribe(URL url, NotifyListener listener) { - - if (isAdminURL(url)) { - // TODO in future - } else if (isDubboMetadataServiceURL(url)) { // for DubboMetadataService - subscribeDubboMetadataServiceURLs(url, listener); - } else { // for general Dubbo Services - subscribeDubboServiceURLs(url, listener); - } - } - - protected void subscribeDubboServiceURLs(URL url, NotifyListener listener) { - - doSubscribeDubboServiceURLs(url, listener); - - registerServiceInstancesChangedEventListener(url, listener); - } - - /** - * Register a {@link ApplicationListener listener} for {@link ServiceInstancesChangedEvent} - * - * @param url {@link URL} - * @param listener {@link NotifyListener} - */ - private void registerServiceInstancesChangedEventListener(URL url, NotifyListener listener) { - String listenerId = generateId(url); - if (registerListeners.add(listenerId)) { - applicationContext.addApplicationListener(new ApplicationListener() { - @Override - public void onApplicationEvent(ServiceInstancesChangedEvent event) { - String serviceName = event.getServiceName(); - Collection serviceInstances = event.getServiceInstances(); - subscribeDubboServiceURL(url, listener, serviceName, s -> serviceInstances); - } - }); - } - } - - private void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { - - Set subscribedServices = repository.getSubscribedServices(); - // Sync - subscribedServices.forEach(service -> subscribeDubboServiceURL(url, listener, service, this::getServiceInstances)); - } - - protected void subscribeDubboServiceURL(URL url, NotifyListener listener, String serviceName, - Function> serviceInstancesFunction) { - - if (logger.isInfoEnabled()) { - logger.info("The Dubbo Service URL[ID : {}] is being subscribed for service[name : {}]", - generateId(url), serviceName); - } - - DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName); - - if (dubboMetadataService == null) { // If not found, try to initialize - if (logger.isInfoEnabled()) { - logger.info("The metadata of Dubbo service[key : {}] can't be found when the subscribed service[name : {}], " + - "and then try to initialize it", url.getServiceKey(), serviceName); - } - repository.initializeMetadata(serviceName); - dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName); - } - - if (dubboMetadataService == null) { // It makes sure not-found, return immediately - if (logger.isWarnEnabled()) { - logger.warn("The metadata of Dubbo service[key : {}] still can't be found, it could effect the further " + - "Dubbo service invocation", url.getServiceKey()); - } - return; - } - - Collection serviceInstances = serviceInstancesFunction.apply(serviceName); - - List allSubscribedURLs = new LinkedList<>(); - - if (CollectionUtils.isEmpty(serviceInstances)) { - if (logger.isWarnEnabled()) { - logger.warn("There is no instance from service[name : {}], and then Dubbo Service[key : {}] will not be " + - "available , please make sure the further impact", serviceName, url.getServiceKey()); - } - /** - * URLs with {@link RegistryConstants#EMPTY_PROTOCOL} - */ - allSubscribedURLs.addAll(emptyURLs(url)); - } else { - List exportedURLs = getExportedURLs(dubboMetadataService, url); - - for (URL exportedURL : exportedURLs) { - String protocol = exportedURL.getProtocol(); - List subscribedURLs = new LinkedList<>(); - serviceInstances.forEach(serviceInstance -> { - Integer port = repository.getDubboProtocolPort(serviceInstance, protocol); - String host = serviceInstance.getHost(); - if (port == null) { - if (logger.isWarnEnabled()) { - logger.warn("The protocol[{}] port of Dubbo service instance[host : {}] " + - "can't be resolved", protocol, host); - } - } else { - URL subscribedURL = new URL(protocol, host, port, exportedURL.getParameters()); - subscribedURLs.add(subscribedURL); - } - }); - - allSubscribedURLs.addAll(subscribedURLs); - } - } - - if (logger.isDebugEnabled()) { - logger.debug("The subscribed URL[{}] will notify all URLs : {}", url, allSubscribedURLs); - } - - listener.notify(allSubscribedURLs); - } - - private String generateId(URL url) { - return url.toString(VERSION_KEY, GROUP_KEY, PROTOCOL_KEY); - } - - private List emptyURLs(URL url) { - return asList(from(url).setProtocol(EMPTY_PROTOCOL).build()); - } - - private List getServiceInstances(String serviceName) { - return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList(); - } - - private List doGetServiceInstances(String serviceName) { - List serviceInstances = emptyList(); - try { - serviceInstances = discoveryClient.getInstances(serviceName); - } catch (Exception e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); - } - } - return serviceInstances; - } - - private List getExportedURLs(DubboMetadataService dubboMetadataService, URL url) { - String serviceInterface = url.getServiceInterface(); - String group = url.getParameter(GROUP_KEY); - String version = url.getParameter(VERSION_KEY); - // The subscribed protocol may be null - String subscribedProtocol = url.getParameter(PROTOCOL_KEY); - String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface, group, version); - return jsonUtils - .toURLs(exportedURLsJSON) - .stream() - .filter(exportedURL -> - subscribedProtocol == null || subscribedProtocol.equalsIgnoreCase(exportedURL.getProtocol()) - ).collect(Collectors.toList()); - } - - private void subscribeDubboMetadataServiceURLs(URL url, NotifyListener listener) { - String serviceInterface = url.getServiceInterface(); - String group = url.getParameter(GROUP_KEY); - String version = url.getParameter(VERSION_KEY); - String protocol = url.getParameter(PROTOCOL_KEY); - List urls = repository.findSubscribedDubboMetadataServiceURLs(serviceInterface, group, version, protocol); - listener.notify(urls); - } - - @Override - public final void doUnsubscribe(URL url, NotifyListener listener) { - if (isAdminURL(url)) { - } - } - - @Override - public boolean isAvailable() { - return !discoveryClient.getServices().isEmpty(); - } - - protected boolean isAdminURL(URL url) { - return ADMIN_PROTOCOL.equals(url.getProtocol()); - } - - protected boolean isDubboMetadataServiceURL(URL url) { - return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); - } + /** + * The parameter name of {@link #servicesLookupInterval} + */ + public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval"; + + protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class + .getName(); + /** + * Caches the IDs of {@link ApplicationListener} + */ + private static final Set registerListeners = new HashSet<>(); + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * The interval in second of lookup service names(only for Dubbo-OPS) + */ + private final long servicesLookupInterval; + + private final DiscoveryClient discoveryClient; + + private final DubboServiceMetadataRepository repository; + + private final DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; + + private final JSONUtils jsonUtils; + + private final ConfigurableApplicationContext applicationContext; + + public AbstractSpringCloudRegistry(URL url, DiscoveryClient discoveryClient, + DubboServiceMetadataRepository dubboServiceMetadataRepository, + DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, + JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) { + super(url); + this.servicesLookupInterval = url + .getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L); + this.discoveryClient = discoveryClient; + this.repository = dubboServiceMetadataRepository; + this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy; + this.jsonUtils = jsonUtils; + this.applicationContext = applicationContext; + } + + protected boolean shouldRegister(URL url) { + String side = url.getParameter(SIDE_KEY); + + boolean should = PROVIDER_SIDE.equals(side); // Only register the Provider. + + if (!should) { + if (logger.isDebugEnabled()) { + logger.debug("The URL[{}] should not be registered.", url.toString()); + } + } + + return should; + } + + @Override + public final void doRegister(URL url) { + if (!shouldRegister(url)) { + return; + } + doRegister0(url); + } + + /** + * The sub-type should implement to register + * + * @param url {@link URL} + */ + protected abstract void doRegister0(URL url); + + @Override + public final void doUnregister(URL url) { + if (!shouldRegister(url)) { + return; + } + doUnregister0(url); + } + + /** + * The sub-type should implement to unregister + * + * @param url {@link URL} + */ + protected abstract void doUnregister0(URL url); + + @Override + public final void doSubscribe(URL url, NotifyListener listener) { + + if (isAdminURL(url)) { + // TODO in future + } + else if (isDubboMetadataServiceURL(url)) { // for DubboMetadataService + subscribeDubboMetadataServiceURLs(url, listener); + } + else { // for general Dubbo Services + subscribeDubboServiceURLs(url, listener); + } + } + + protected void subscribeDubboServiceURLs(URL url, NotifyListener listener) { + + doSubscribeDubboServiceURLs(url, listener); + + registerServiceInstancesChangedEventListener(url, listener); + } + + /** + * Register a {@link ApplicationListener listener} for + * {@link ServiceInstancesChangedEvent} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + */ + private void registerServiceInstancesChangedEventListener(URL url, + NotifyListener listener) { + String listenerId = generateId(url); + if (registerListeners.add(listenerId)) { + applicationContext.addApplicationListener( + new ApplicationListener() { + @Override + public void onApplicationEvent( + ServiceInstancesChangedEvent event) { + String serviceName = event.getServiceName(); + Collection serviceInstances = event + .getServiceInstances(); + subscribeDubboServiceURL(url, listener, serviceName, + s -> serviceInstances); + } + }); + } + } + + private void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { + + Set subscribedServices = repository.getSubscribedServices(); + // Sync + subscribedServices.forEach(service -> subscribeDubboServiceURL(url, listener, + service, this::getServiceInstances)); + } + + protected void subscribeDubboServiceURL(URL url, NotifyListener listener, + String serviceName, + Function> serviceInstancesFunction) { + + if (logger.isInfoEnabled()) { + logger.info( + "The Dubbo Service URL[ID : {}] is being subscribed for service[name : {}]", + generateId(url), serviceName); + } + + DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy + .getProxy(serviceName); + + if (dubboMetadataService == null) { // If not found, try to initialize + if (logger.isInfoEnabled()) { + logger.info( + "The metadata of Dubbo service[key : {}] can't be found when the subscribed service[name : {}], " + + "and then try to initialize it", + url.getServiceKey(), serviceName); + } + repository.initializeMetadata(serviceName); + dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName); + } + + if (dubboMetadataService == null) { // It makes sure not-found, return immediately + if (logger.isWarnEnabled()) { + logger.warn( + "The metadata of Dubbo service[key : {}] still can't be found, it could effect the further " + + "Dubbo service invocation", + url.getServiceKey()); + } + return; + } + + Collection serviceInstances = serviceInstancesFunction + .apply(serviceName); + + List allSubscribedURLs = new LinkedList<>(); + + if (CollectionUtils.isEmpty(serviceInstances)) { + if (logger.isWarnEnabled()) { + logger.warn( + "There is no instance from service[name : {}], and then Dubbo Service[key : {}] will not be " + + "available , please make sure the further impact", + serviceName, url.getServiceKey()); + } + /** + * URLs with {@link RegistryConstants#EMPTY_PROTOCOL} + */ + allSubscribedURLs.addAll(emptyURLs(url)); + } + else { + List exportedURLs = getExportedURLs(dubboMetadataService, url); + + for (URL exportedURL : exportedURLs) { + String protocol = exportedURL.getProtocol(); + List subscribedURLs = new LinkedList<>(); + serviceInstances.forEach(serviceInstance -> { + Integer port = repository.getDubboProtocolPort(serviceInstance, + protocol); + String host = serviceInstance.getHost(); + if (port == null) { + if (logger.isWarnEnabled()) { + logger.warn( + "The protocol[{}] port of Dubbo service instance[host : {}] " + + "can't be resolved", + protocol, host); + } + } + else { + URL subscribedURL = new URL(protocol, host, port, + exportedURL.getParameters()); + subscribedURLs.add(subscribedURL); + } + }); + + allSubscribedURLs.addAll(subscribedURLs); + } + } + + if (logger.isDebugEnabled()) { + logger.debug("The subscribed URL[{}] will notify all URLs : {}", url, + allSubscribedURLs); + } + + listener.notify(allSubscribedURLs); + } + + private String generateId(URL url) { + return url.toString(VERSION_KEY, GROUP_KEY, PROTOCOL_KEY); + } + + private List emptyURLs(URL url) { + return asList(from(url).setProtocol(EMPTY_PROTOCOL).build()); + } + + private List getServiceInstances(String serviceName) { + return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList(); + } + + private List doGetServiceInstances(String serviceName) { + List serviceInstances = emptyList(); + try { + serviceInstances = discoveryClient.getInstances(serviceName); + } + catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return serviceInstances; + } + + private List getExportedURLs(DubboMetadataService dubboMetadataService, + URL url) { + String serviceInterface = url.getServiceInterface(); + String group = url.getParameter(GROUP_KEY); + String version = url.getParameter(VERSION_KEY); + // The subscribed protocol may be null + String subscribedProtocol = url.getParameter(PROTOCOL_KEY); + String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface, + group, version); + return jsonUtils.toURLs(exportedURLsJSON).stream() + .filter(exportedURL -> subscribedProtocol == null + || subscribedProtocol.equalsIgnoreCase(exportedURL.getProtocol())) + .collect(Collectors.toList()); + } + + private void subscribeDubboMetadataServiceURLs(URL url, NotifyListener listener) { + String serviceInterface = url.getServiceInterface(); + String group = url.getParameter(GROUP_KEY); + String version = url.getParameter(VERSION_KEY); + String protocol = url.getParameter(PROTOCOL_KEY); + List urls = repository.findSubscribedDubboMetadataServiceURLs( + serviceInterface, group, version, protocol); + listener.notify(urls); + } + + @Override + public final void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminURL(url)) { + } + } + + @Override + public boolean isAvailable() { + return !discoveryClient.getServices().isEmpty(); + } + + protected boolean isAdminURL(URL url) { + return ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + protected boolean isDubboMetadataServiceURL(URL url) { + return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DelegatingRegistration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DelegatingRegistration.java index 94491b48b..8789e80fd 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DelegatingRegistration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DelegatingRegistration.java @@ -16,57 +16,58 @@ */ package com.alibaba.cloud.dubbo.registry; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.serviceregistry.Registration; - import java.net.URI; import java.util.Map; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; + /** - * The {@link Registration} of Dubbo uses an external of {@link ServiceInstance} instance as the delegate. + * The {@link Registration} of Dubbo uses an external of {@link ServiceInstance} instance + * as the delegate. * * @author Mercy */ class DelegatingRegistration implements Registration { - private final ServiceInstance delegate; + private final ServiceInstance delegate; - public DelegatingRegistration(ServiceInstance delegate) { - this.delegate = delegate; - } + public DelegatingRegistration(ServiceInstance delegate) { + this.delegate = delegate; + } - @Override - public String getServiceId() { - return delegate.getServiceId(); - } + @Override + public String getServiceId() { + return delegate.getServiceId(); + } - @Override - public String getHost() { - return delegate.getHost(); - } + @Override + public String getHost() { + return delegate.getHost(); + } - @Override - public int getPort() { - return delegate.getPort(); - } + @Override + public int getPort() { + return delegate.getPort(); + } - @Override - public boolean isSecure() { - return delegate.isSecure(); - } + @Override + public boolean isSecure() { + return delegate.isSecure(); + } - @Override - public URI getUri() { - return delegate.getUri(); - } + @Override + public URI getUri() { + return delegate.getUri(); + } - @Override - public Map getMetadata() { - return delegate.getMetadata(); - } + @Override + public Map getMetadata() { + return delegate.getMetadata(); + } - @Override - public String getScheme() { - return delegate.getScheme(); - } + @Override + public String getScheme() { + return delegate.getScheme(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java index 790b5e2e1..33ed52d54 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java @@ -16,8 +16,6 @@ */ package com.alibaba.cloud.dubbo.registry; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstanceRegisteredEvent; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @@ -26,6 +24,9 @@ import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstanceRegisteredEvent; + /** * Dubbo Service Registration Event-Publishing Aspect * @@ -34,28 +35,31 @@ import org.springframework.context.ApplicationEventPublisherAware; * @see ServiceInstanceRegisteredEvent */ @Aspect -public class DubboServiceRegistrationEventPublishingAspect implements ApplicationEventPublisherAware { - - /** - * The pointcut expression for {@link ServiceRegistry#register(Registration)} - */ - public static final String REGISTER_POINTCUT_EXPRESSION = - "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && args(registration)"; - - private ApplicationEventPublisher applicationEventPublisher; - - @Before(REGISTER_POINTCUT_EXPRESSION) - public void beforeRegister(Registration registration) { - applicationEventPublisher.publishEvent(new ServiceInstancePreRegisteredEvent(registration)); - } - - @After(REGISTER_POINTCUT_EXPRESSION) - public void afterRegister(Registration registration) { - applicationEventPublisher.publishEvent(new ServiceInstanceRegisteredEvent(registration)); - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.applicationEventPublisher = applicationEventPublisher; - } +public class DubboServiceRegistrationEventPublishingAspect + implements ApplicationEventPublisherAware { + + /** + * The pointcut expression for {@link ServiceRegistry#register(Registration)} + */ + public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && args(registration)"; + + private ApplicationEventPublisher applicationEventPublisher; + + @Before(REGISTER_POINTCUT_EXPRESSION) + public void beforeRegister(Registration registration) { + applicationEventPublisher + .publishEvent(new ServiceInstancePreRegisteredEvent(registration)); + } + + @After(REGISTER_POINTCUT_EXPRESSION) + public void afterRegister(Registration registration) { + applicationEventPublisher + .publishEvent(new ServiceInstanceRegisteredEvent(registration)); + } + + @Override + public void setApplicationEventPublisher( + ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java index e7afca62c..be9039aec 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java @@ -19,37 +19,39 @@ package com.alibaba.cloud.dubbo.registry; import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.RegistryFactory; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.ConfigurableApplicationContext; + import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; import com.alibaba.cloud.dubbo.util.JSONUtils; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.context.ConfigurableApplicationContext; /** - * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose + * protocol is "spring-cloud" * * @author Mercy */ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { - private final DubboServiceMetadataRepository dubboServiceMetadataRepository; - - public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient, - DubboServiceMetadataRepository dubboServiceMetadataRepository, - DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, - JSONUtils jsonUtils, - ConfigurableApplicationContext applicationContext) { - super(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, jsonUtils, applicationContext); - this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; - } - - @Override - protected void doRegister0(URL url) { - dubboServiceMetadataRepository.exportURL(url); - } - - @Override - protected void doUnregister0(URL url) { - dubboServiceMetadataRepository.unexportURL(url); - } + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; + + public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient, + DubboServiceMetadataRepository dubboServiceMetadataRepository, + DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, + JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) { + super(url, discoveryClient, dubboServiceMetadataRepository, + dubboMetadataConfigServiceProxy, jsonUtils, applicationContext); + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + } + + @Override + protected void doRegister0(URL url) { + dubboServiceMetadataRepository.exportURL(url); + } + + @Override + protected void doUnregister0(URL url) { + dubboServiceMetadataRepository.unexportURL(url); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java index c6fb757d5..ca0e1dc13 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java @@ -16,20 +16,22 @@ */ package com.alibaba.cloud.dubbo.registry; +import static java.lang.System.getProperty; + import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; -import com.alibaba.cloud.dubbo.util.JSONUtils; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.ConfigurableApplicationContext; -import static java.lang.System.getProperty; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; +import com.alibaba.cloud.dubbo.util.JSONUtils; /** - * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose + * protocol is "spring-cloud" * * @author Mercy * @see RegistryFactory @@ -37,46 +39,51 @@ import static java.lang.System.getProperty; */ public class SpringCloudRegistryFactory implements RegistryFactory { - public static String PROTOCOL = "spring-cloud"; + public static String PROTOCOL = "spring-cloud"; - public static String ADDRESS = "localhost"; + public static String ADDRESS = "localhost"; - private static String SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX = - getProperty("dubbo.services.lookup.scheduler.thread.name.prefix ", "dubbo-services-lookup-"); + private static String SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX = getProperty( + "dubbo.services.lookup.scheduler.thread.name.prefix ", + "dubbo-services-lookup-"); - private static ConfigurableApplicationContext applicationContext; + private static ConfigurableApplicationContext applicationContext; - private DiscoveryClient discoveryClient; + private DiscoveryClient discoveryClient; - private DubboServiceMetadataRepository dubboServiceMetadataRepository; + private DubboServiceMetadataRepository dubboServiceMetadataRepository; - private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; + private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; - private JSONUtils jsonUtils; + private JSONUtils jsonUtils; - private volatile boolean initialized = false; + private volatile boolean initialized = false; - public SpringCloudRegistryFactory() { - } + public SpringCloudRegistryFactory() { + } - public static void setApplicationContext(ConfigurableApplicationContext applicationContext) { - SpringCloudRegistryFactory.applicationContext = applicationContext; - } + public static void setApplicationContext( + ConfigurableApplicationContext applicationContext) { + SpringCloudRegistryFactory.applicationContext = applicationContext; + } - protected void init() { - if (initialized || applicationContext == null) { - return; - } - this.discoveryClient = applicationContext.getBean(DiscoveryClient.class); - this.dubboServiceMetadataRepository = applicationContext.getBean(DubboServiceMetadataRepository.class); - this.dubboMetadataConfigServiceProxy = applicationContext.getBean(DubboMetadataServiceProxy.class); - this.jsonUtils = applicationContext.getBean(JSONUtils.class); - } + protected void init() { + if (initialized || applicationContext == null) { + return; + } + this.discoveryClient = applicationContext.getBean(DiscoveryClient.class); + this.dubboServiceMetadataRepository = applicationContext + .getBean(DubboServiceMetadataRepository.class); + this.dubboMetadataConfigServiceProxy = applicationContext + .getBean(DubboMetadataServiceProxy.class); + this.jsonUtils = applicationContext.getBean(JSONUtils.class); + } - @Override - public Registry getRegistry(URL url) { - init(); - return new SpringCloudRegistry(url, discoveryClient, dubboServiceMetadataRepository, - dubboMetadataConfigServiceProxy, jsonUtils, applicationContext); - } + @Override + public Registry getRegistry(URL url) { + init(); + return new SpringCloudRegistry(url, discoveryClient, + dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, + jsonUtils, applicationContext); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java index 08389694c..1821ebdae 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java @@ -22,18 +22,19 @@ import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.context.ApplicationEvent; /** - * The before-{@link ServiceRegistry#register(Registration) register} event for {@link ServiceInstance} + * The before-{@link ServiceRegistry#register(Registration) register} event for + * {@link ServiceInstance} * * @author Mercy */ public class ServiceInstancePreRegisteredEvent extends ApplicationEvent { - public ServiceInstancePreRegisteredEvent(Registration source) { - super(source); - } + public ServiceInstancePreRegisteredEvent(Registration source) { + super(source); + } - @Override - public Registration getSource() { - return (Registration) super.getSource(); - } + @Override + public Registration getSource() { + return (Registration) super.getSource(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java index c51e86ab6..0e5a0a2a0 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java @@ -21,18 +21,19 @@ import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.context.ApplicationEvent; /** - * The after-{@link ServiceRegistry#register(Registration) register} event for {@link Registration} + * The after-{@link ServiceRegistry#register(Registration) register} event for + * {@link Registration} * * @author Mercy */ public class ServiceInstanceRegisteredEvent extends ApplicationEvent { - public ServiceInstanceRegisteredEvent(Registration source) { - super(source); - } + public ServiceInstanceRegisteredEvent(Registration source) { + super(source); + } - @Override - public Registration getSource() { - return (Registration) super.getSource(); - } + @Override + public Registration getSource() { + return (Registration) super.getSource(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java index 62229626d..2123b4851 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java @@ -16,72 +16,74 @@ */ package com.alibaba.cloud.dubbo.registry.event; +import static java.util.Collections.unmodifiableCollection; + +import java.util.Collection; + import org.springframework.cloud.client.ServiceInstance; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster; -import java.util.Collection; - -import static java.util.Collections.unmodifiableCollection; - /** - * An event raised after the {@link ServiceInstance instances} of one service has been changed. + * An event raised after the {@link ServiceInstance instances} of one service has been + * changed. * * @author Mercy */ public class ServiceInstancesChangedEvent extends ApplicationEvent { - private final String serviceName; + private final String serviceName; - private final Collection serviceInstances; + private final Collection serviceInstances; - /** - * Current event has been processed or not. - * Typically, Spring Event was based on sync {@link ApplicationEventMulticaster} - * - * @see SimpleApplicationEventMulticaster - */ - private boolean processed = false; + /** + * Current event has been processed or not. Typically, Spring Event was based on sync + * {@link ApplicationEventMulticaster} + * + * @see SimpleApplicationEventMulticaster + */ + private boolean processed = false; - /** - * @param serviceName The name of service that was changed - * @param serviceInstances all {@link ServiceInstance service instances} - * @throws IllegalArgumentException if source is null. - */ - public ServiceInstancesChangedEvent(String serviceName, Collection serviceInstances) { - super(serviceName); - this.serviceName = serviceName; - this.serviceInstances = unmodifiableCollection(serviceInstances); - } + /** + * @param serviceName The name of service that was changed + * @param serviceInstances all {@link ServiceInstance service instances} + * @throws IllegalArgumentException if source is null. + */ + public ServiceInstancesChangedEvent(String serviceName, + Collection serviceInstances) { + super(serviceName); + this.serviceName = serviceName; + this.serviceInstances = unmodifiableCollection(serviceInstances); + } - /** - * @return The name of service that was changed - */ - public String getServiceName() { - return serviceName; - } + /** + * @return The name of service that was changed + */ + public String getServiceName() { + return serviceName; + } - /** - * @return all {@link ServiceInstance service instances} - */ - public Collection getServiceInstances() { - return serviceInstances; - } + /** + * @return all {@link ServiceInstance service instances} + */ + public Collection getServiceInstances() { + return serviceInstances; + } - /** - * Mark current event being processed - */ - public void processed() { - processed = true; - } + /** + * Mark current event being processed + */ + public void processed() { + processed = true; + } - /** - * Current event has been processed or not - * - * @return if processed, return true, or false - */ - public boolean isProcessed() { - return processed; - } + /** + * Current event has been processed or not + * + * @return if processed, return true, or false + */ + public boolean isProcessed() { + return processed; + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java index 7ed8bce6f..384d8a1cd 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java @@ -16,12 +16,12 @@ */ package com.alibaba.cloud.dubbo.registry.event; -import org.springframework.context.ApplicationEvent; - import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; +import org.springframework.context.ApplicationEvent; + /** * {@link ApplicationEvent Event} raised when the subscribed services are changed *

@@ -31,35 +31,36 @@ import java.util.Set; */ public class SubscribedServicesChangedEvent extends ApplicationEvent { - private final Set oldSubscribedServices; + private final Set oldSubscribedServices; - private final Set newSubscribedServices; + private final Set newSubscribedServices; - private final boolean changed; + private final boolean changed; - /** - * Create a new ApplicationEvent. - * - * @param source the object on which the event initially occurred (never {@code null}) - * @param oldSubscribedServices the subscribed services before changed - * @param newSubscribedServices the subscribed services after changed - */ - public SubscribedServicesChangedEvent(Object source, Set oldSubscribedServices, Set newSubscribedServices) { - super(source); - this.oldSubscribedServices = new LinkedHashSet<>(oldSubscribedServices); - this.newSubscribedServices = new LinkedHashSet<>(newSubscribedServices); - this.changed = !Objects.equals(oldSubscribedServices, newSubscribedServices); - } + /** + * Create a new ApplicationEvent. + * + * @param source the object on which the event initially occurred (never {@code null}) + * @param oldSubscribedServices the subscribed services before changed + * @param newSubscribedServices the subscribed services after changed + */ + public SubscribedServicesChangedEvent(Object source, + Set oldSubscribedServices, Set newSubscribedServices) { + super(source); + this.oldSubscribedServices = new LinkedHashSet<>(oldSubscribedServices); + this.newSubscribedServices = new LinkedHashSet<>(newSubscribedServices); + this.changed = !Objects.equals(oldSubscribedServices, newSubscribedServices); + } - public Set getOldSubscribedServices() { - return oldSubscribedServices; - } + public Set getOldSubscribedServices() { + return oldSubscribedServices; + } - public Set getNewSubscribedServices() { - return newSubscribedServices; - } + public Set getNewSubscribedServices() { + return newSubscribedServices; + } - public boolean isChanged() { - return changed; - } + public boolean isChanged() { + return changed; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContext.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContext.java index d85869339..53c7fd6d0 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContext.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContext.java @@ -25,27 +25,28 @@ import org.apache.dubbo.rpc.service.GenericService; */ public class DubboGenericServiceExecutionContext { - private final String methodName; + private final String methodName; - private final String[] parameterTypes; + private final String[] parameterTypes; - private final Object[] parameters; + private final Object[] parameters; - public DubboGenericServiceExecutionContext(String methodName, String[] parameterTypes, Object[] parameters) { - this.methodName = methodName; - this.parameterTypes = parameterTypes; - this.parameters = 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 getMethodName() { + return methodName; + } - public String[] getParameterTypes() { - return parameterTypes; - } + public String[] getParameterTypes() { + return parameterTypes; + } - public Object[] getParameters() { - return parameters; - } + public Object[] getParameters() { + return parameters; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContextFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContextFactory.java index 32591bf31..8d61b2fd6 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContextFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceExecutionContextFactory.java @@ -16,19 +16,21 @@ */ package com.alibaba.cloud.dubbo.service; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; + import com.alibaba.cloud.dubbo.http.HttpServerRequest; import com.alibaba.cloud.dubbo.metadata.MethodMetadata; import com.alibaba.cloud.dubbo.metadata.MethodParameterMetadata; import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; import com.alibaba.cloud.dubbo.service.parameter.DubboGenericServiceParameterResolver; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; - -import javax.annotation.PostConstruct; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; /** * {@link DubboGenericServiceExecutionContext} Factory @@ -38,110 +40,119 @@ import java.util.Map; */ public class DubboGenericServiceExecutionContextFactory { - @Autowired(required = false) - private final List resolvers = Collections.emptyList(); + @Autowired(required = false) + private final List resolvers = Collections + .emptyList(); - @PostConstruct - public void init() { - AnnotationAwareOrderComparator.sort(resolvers); - } + @PostConstruct + public void init() { + AnnotationAwareOrderComparator.sort(resolvers); + } - public DubboGenericServiceExecutionContext create(RestMethodMetadata dubboRestMethodMetadata, - RestMethodMetadata clientMethodMetadata, Object[] arguments) { + public DubboGenericServiceExecutionContext create( + RestMethodMetadata dubboRestMethodMetadata, + RestMethodMetadata clientMethodMetadata, Object[] arguments) { - MethodMetadata dubboMethodMetadata = dubboRestMethodMetadata.getMethod(); + MethodMetadata dubboMethodMetadata = dubboRestMethodMetadata.getMethod(); - String methodName = dubboMethodMetadata.getName(); + String methodName = dubboMethodMetadata.getName(); - String[] parameterTypes = resolveParameterTypes(dubboMethodMetadata); + String[] parameterTypes = resolveParameterTypes(dubboMethodMetadata); - Object[] parameters = resolveParameters(dubboRestMethodMetadata, clientMethodMetadata, arguments); + Object[] parameters = resolveParameters(dubboRestMethodMetadata, + clientMethodMetadata, arguments); - return new DubboGenericServiceExecutionContext(methodName, parameterTypes, parameters); - } + return new DubboGenericServiceExecutionContext(methodName, parameterTypes, + parameters); + } - public DubboGenericServiceExecutionContext create(RestMethodMetadata dubboRestMethodMetadata, - HttpServerRequest request) { - MethodMetadata methodMetadata = dubboRestMethodMetadata.getMethod(); + public DubboGenericServiceExecutionContext create( + RestMethodMetadata dubboRestMethodMetadata, HttpServerRequest request) { + MethodMetadata methodMetadata = dubboRestMethodMetadata.getMethod(); - String methodName = methodMetadata.getName(); + String methodName = methodMetadata.getName(); - String[] parameterTypes = resolveParameterTypes(methodMetadata); + String[] parameterTypes = resolveParameterTypes(methodMetadata); - Object[] parameters = resolveParameters(dubboRestMethodMetadata, request); + Object[] parameters = resolveParameters(dubboRestMethodMetadata, request); - return new DubboGenericServiceExecutionContext(methodName, parameterTypes, parameters); - } + return new DubboGenericServiceExecutionContext(methodName, parameterTypes, + parameters); + } - private Map buildParamNameToIndex(List params) { - Map paramNameToIndex = new LinkedHashMap<>(); - for (MethodParameterMetadata param : params) { - paramNameToIndex.put(param.getName(), param.getIndex()); - } - return paramNameToIndex; - } + private Map buildParamNameToIndex( + List params) { + Map paramNameToIndex = new LinkedHashMap<>(); + for (MethodParameterMetadata param : params) { + paramNameToIndex.put(param.getName(), param.getIndex()); + } + return paramNameToIndex; + } - protected String[] resolveParameterTypes(MethodMetadata methodMetadata) { + protected String[] resolveParameterTypes(MethodMetadata methodMetadata) { - List params = methodMetadata.getParams(); + List params = methodMetadata.getParams(); - String[] parameterTypes = new String[params.size()]; + String[] parameterTypes = new String[params.size()]; - for (MethodParameterMetadata parameterMetadata : params) { - int index = parameterMetadata.getIndex(); - String parameterType = parameterMetadata.getType(); - parameterTypes[index] = parameterType; - } + for (MethodParameterMetadata parameterMetadata : params) { + int index = parameterMetadata.getIndex(); + String parameterType = parameterMetadata.getType(); + parameterTypes[index] = parameterType; + } - return parameterTypes; - } + return parameterTypes; + } - protected Object[] resolveParameters(RestMethodMetadata dubboRestMethodMetadata, HttpServerRequest request) { + protected Object[] resolveParameters(RestMethodMetadata dubboRestMethodMetadata, + HttpServerRequest request) { - MethodMetadata dubboMethodMetadata = dubboRestMethodMetadata.getMethod(); + MethodMetadata dubboMethodMetadata = dubboRestMethodMetadata.getMethod(); - List params = dubboMethodMetadata.getParams(); + List params = dubboMethodMetadata.getParams(); - Object[] parameters = new Object[params.size()]; + Object[] parameters = new Object[params.size()]; - for (MethodParameterMetadata parameterMetadata : params) { + for (MethodParameterMetadata parameterMetadata : params) { - int index = parameterMetadata.getIndex(); + int index = parameterMetadata.getIndex(); - for (DubboGenericServiceParameterResolver resolver : resolvers) { - Object parameter = resolver.resolve(dubboRestMethodMetadata, parameterMetadata, request); - if (parameter != null) { - parameters[index] = parameter; - break; - } - } - } + for (DubboGenericServiceParameterResolver resolver : resolvers) { + Object parameter = resolver.resolve(dubboRestMethodMetadata, + parameterMetadata, request); + if (parameter != null) { + parameters[index] = parameter; + break; + } + } + } - return parameters; - } + return parameters; + } - protected Object[] resolveParameters(RestMethodMetadata dubboRestMethodMetadata, - RestMethodMetadata clientRestMethodMetadata, Object[] arguments) { + protected Object[] resolveParameters(RestMethodMetadata dubboRestMethodMetadata, + RestMethodMetadata clientRestMethodMetadata, Object[] arguments) { - MethodMetadata dubboMethodMetadata = dubboRestMethodMetadata.getMethod(); + MethodMetadata dubboMethodMetadata = dubboRestMethodMetadata.getMethod(); - List params = dubboMethodMetadata.getParams(); + List params = dubboMethodMetadata.getParams(); - Object[] parameters = new Object[params.size()]; + Object[] parameters = new Object[params.size()]; - for (MethodParameterMetadata parameterMetadata : params) { + for (MethodParameterMetadata parameterMetadata : params) { - int index = parameterMetadata.getIndex(); + int index = parameterMetadata.getIndex(); - for (DubboGenericServiceParameterResolver resolver : resolvers) { - Object parameter = resolver.resolve(dubboRestMethodMetadata, parameterMetadata, clientRestMethodMetadata, arguments); - if (parameter != null) { - parameters[index] = parameter; - break; - } - } - } + for (DubboGenericServiceParameterResolver resolver : resolvers) { + Object parameter = resolver.resolve(dubboRestMethodMetadata, + parameterMetadata, clientRestMethodMetadata, arguments); + if (parameter != null) { + parameters[index] = parameter; + break; + } + } + } - return parameters; - } + return parameters; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java index ebbe5913b..b96ce36cc 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java @@ -16,14 +16,27 @@ */ package com.alibaba.cloud.dubbo.service; +import static java.util.Collections.emptyMap; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; + +import java.beans.PropertyEditorSupport; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.annotation.PreDestroy; + import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.rpc.service.GenericService; -import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; -import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.MutablePropertyValues; @@ -33,19 +46,8 @@ import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.util.StringUtils; import org.springframework.validation.DataBinder; -import javax.annotation.PreDestroy; -import java.beans.PropertyEditorSupport; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static java.util.Collections.emptyMap; -import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; -import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; +import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; +import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; /** * Dubbo {@link GenericService} Factory @@ -54,104 +56,114 @@ import static org.springframework.util.StringUtils.commaDelimitedListToStringArr */ public class DubboGenericServiceFactory { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final ConcurrentMap> cache = new ConcurrentHashMap<>(); - - @Autowired - private ObjectProvider> registryConfigs; - - public GenericService create(DubboRestServiceMetadata dubboServiceMetadata, - Map dubboTranslatedAttributes) { - - ReferenceBean referenceBean = build(dubboServiceMetadata.getServiceRestMetadata(), dubboTranslatedAttributes); - - return referenceBean == null ? null : referenceBean.get(); - } - - public GenericService create(String serviceName, Class serviceClass, String version) { - String interfaceName = serviceClass.getName(); - ReferenceBean referenceBean = build(interfaceName, version, serviceName, emptyMap()); - return referenceBean.get(); - } - - - private ReferenceBean build(ServiceRestMetadata serviceRestMetadata, - Map dubboTranslatedAttributes) { - String urlValue = serviceRestMetadata.getUrl(); - URL url = URL.valueOf(urlValue); - String interfaceName = url.getServiceInterface(); - String version = url.getParameter(VERSION_KEY); - String group = url.getParameter(GROUP_KEY); - - return build(interfaceName, version, group, dubboTranslatedAttributes); - } - - private ReferenceBean build(String interfaceName, String version, String group, - Map dubboTranslatedAttributes) { - - Integer key = Objects.hash(interfaceName, version, group, dubboTranslatedAttributes); - - return cache.computeIfAbsent(key, k -> { - ReferenceBean referenceBean = new ReferenceBean<>(); - referenceBean.setGeneric(true); - referenceBean.setInterface(interfaceName); - referenceBean.setVersion(version); - referenceBean.setGroup(group); - bindReferenceBean(referenceBean, dubboTranslatedAttributes); - return referenceBean; - }); - } - - private void bindReferenceBean(ReferenceBean referenceBean, Map dubboTranslatedAttributes) { - DataBinder dataBinder = new DataBinder(referenceBean); - // Register CustomEditors for special fields - dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true)); - dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true)); - dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() { - - @Override - public void setAsText(String text) throws java.lang.IllegalArgumentException { - // Trim all whitespace - String content = StringUtils.trimAllWhitespace(text); - if (!StringUtils.hasText(content)) { // No content , ignore directly - return; - } - // replace "=" to "," - content = StringUtils.replace(content, "=", ","); - // replace ":" to "," - content = StringUtils.replace(content, ":", ","); - // String[] to Map - Map parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content)); - setValue(parameters); - } - }); - - // ignore "registries" field and then use RegistryConfig beans - dataBinder.setDisallowedFields("registries"); - - dataBinder.bind(new MutablePropertyValues(dubboTranslatedAttributes)); - - registryConfigs.ifAvailable(referenceBean::setRegistries); - } - - @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); - } - } - } + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ConcurrentMap> cache = new ConcurrentHashMap<>(); + + @Autowired + private ObjectProvider> registryConfigs; + + public GenericService create(DubboRestServiceMetadata dubboServiceMetadata, + Map dubboTranslatedAttributes) { + + ReferenceBean referenceBean = build( + dubboServiceMetadata.getServiceRestMetadata(), dubboTranslatedAttributes); + + return referenceBean == null ? null : referenceBean.get(); + } + + public GenericService create(String serviceName, Class serviceClass, + String version) { + String interfaceName = serviceClass.getName(); + ReferenceBean referenceBean = build(interfaceName, version, + serviceName, emptyMap()); + return referenceBean.get(); + } + + private ReferenceBean build(ServiceRestMetadata serviceRestMetadata, + Map dubboTranslatedAttributes) { + String urlValue = serviceRestMetadata.getUrl(); + URL url = URL.valueOf(urlValue); + String interfaceName = url.getServiceInterface(); + String version = url.getParameter(VERSION_KEY); + String group = url.getParameter(GROUP_KEY); + + return build(interfaceName, version, group, dubboTranslatedAttributes); + } + + private ReferenceBean build(String interfaceName, String version, + String group, Map dubboTranslatedAttributes) { + + Integer key = Objects.hash(interfaceName, version, group, + dubboTranslatedAttributes); + + return cache.computeIfAbsent(key, k -> { + ReferenceBean referenceBean = new ReferenceBean<>(); + referenceBean.setGeneric(true); + referenceBean.setInterface(interfaceName); + referenceBean.setVersion(version); + referenceBean.setGroup(group); + bindReferenceBean(referenceBean, dubboTranslatedAttributes); + return referenceBean; + }); + } + + private void bindReferenceBean(ReferenceBean referenceBean, + Map dubboTranslatedAttributes) { + DataBinder dataBinder = new DataBinder(referenceBean); + // Register CustomEditors for special fields + dataBinder.registerCustomEditor(String.class, "filter", + new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(String.class, "listener", + new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(Map.class, "parameters", + new PropertyEditorSupport() { + + @Override + public void setAsText(String text) + throws java.lang.IllegalArgumentException { + // Trim all whitespace + String content = StringUtils.trimAllWhitespace(text); + if (!StringUtils.hasText(content)) { // No content , ignore + // directly + return; + } + // replace "=" to "," + content = StringUtils.replace(content, "=", ","); + // replace ":" to "," + content = StringUtils.replace(content, ":", ","); + // String[] to Map + Map parameters = CollectionUtils + .toStringMap(commaDelimitedListToStringArray(content)); + setValue(parameters); + } + }); + + // ignore "registries" field and then use RegistryConfig beans + dataBinder.setDisallowedFields("registries"); + + dataBinder.bind(new MutablePropertyValues(dubboTranslatedAttributes)); + + registryConfigs.ifAvailable(referenceBean::setRegistries); + } + + @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/com/alibaba/cloud/dubbo/service/DubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataService.java index a8ef08b03..134bb0280 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataService.java @@ -16,61 +16,63 @@ */ package com.alibaba.cloud.dubbo.service; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.dubbo.common.URL; import org.apache.dubbo.config.annotation.Service; import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** - * Dubbo Metadata Service is a core interface for service subscribers, - * it must keep the stable of structure in every evolution , makes sure all subscribers' compatibility. + * Dubbo Metadata Service is a core interface for service subscribers, it must keep the + * stable of structure in every evolution , makes sure all subscribers' compatibility. *

- * The interface contract's version must be {@link #VERSION} constant and group must be current Dubbo application name + * The interface contract's version must be {@link #VERSION} constant and group must be + * current Dubbo application name * * @author Mercy */ public interface DubboMetadataService { - /** - * Current version of the interface contract - */ - String VERSION = "1.0.0"; - - /** - * Get the json content of {@link ServiceRestMetadata} {@link Set} - * - * @return null if present - */ - String getServiceRestMetadata(); + /** + * Current version of the interface contract + */ + String VERSION = "1.0.0"; + /** + * Get the json content of {@link ServiceRestMetadata} {@link Set} + * + * @return null if present + */ + String getServiceRestMetadata(); - /** - * Get all exported {@link URL#getServiceKey() service keys} - * - * @return non-null read-only {@link Set} - */ - Set getAllServiceKeys(); + /** + * Get all exported {@link URL#getServiceKey() service keys} + * + * @return non-null read-only {@link Set} + */ + Set getAllServiceKeys(); - /** - * Get all exported Dubbo's {@link URL URLs} {@link Map} whose key is the return value of - * {@link URL#getServiceKey()} method and value is the json content of List of {@link URL URLs} - * - * @return non-null read-only {@link Map} - */ - Map getAllExportedURLs(); + /** + * Get all exported Dubbo's {@link URL URLs} {@link Map} whose key is the return value + * of {@link URL#getServiceKey()} method and value is the json content of List of + * {@link URL URLs} + * + * @return non-null read-only {@link Map} + */ + Map getAllExportedURLs(); - /** - * Get the json content of an exported List of {@link URL URLs} by the serviceInterface , group and version - * - * @param serviceInterface The class name of service interface - * @param group {@link Service#group() the service group} (optional) - * @param version {@link Service#version() the service version} (optional) - * @return non-null read-only {@link List} - * @see URL - */ - String getExportedURLs(String serviceInterface, String group, String version); + /** + * Get the json content of an exported List of {@link URL URLs} by the + * serviceInterface , group and version + * + * @param serviceInterface The class name of service interface + * @param group {@link Service#group() the service group} (optional) + * @param version {@link Service#version() the service version} (optional) + * @return non-null read-only {@link List} + * @see URL + */ + String getExportedURLs(String serviceInterface, String group, String version); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java index 7c04abd71..d8a248e27 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java @@ -16,6 +16,11 @@ */ package com.alibaba.cloud.dubbo.service; +import java.util.List; +import java.util.function.Supplier; + +import javax.annotation.PreDestroy; + import org.apache.dubbo.common.URL; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; @@ -28,10 +33,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import javax.annotation.PreDestroy; -import java.util.List; -import java.util.function.Supplier; - /** * {@link DubboMetadataService} exporter * @@ -40,70 +41,71 @@ import java.util.function.Supplier; @Component public class DubboMetadataServiceExporter { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private ApplicationConfig applicationConfig; + private final Logger logger = LoggerFactory.getLogger(getClass()); - @Autowired - private ObjectProvider dubboMetadataService; + @Autowired + private ApplicationConfig applicationConfig; - @Autowired - private Supplier protocolConfigSupplier; + @Autowired + private ObjectProvider dubboMetadataService; - @Value("${spring.application.name:${dubbo.application.name:application}}") - private String currentApplicationName; + @Autowired + private Supplier protocolConfigSupplier; - /** - * The ServiceConfig of DubboMetadataConfigService to be exported, can be nullable. - */ - private ServiceConfig serviceConfig; + @Value("${spring.application.name:${dubbo.application.name:application}}") + private String currentApplicationName; - /** - * export {@link DubboMetadataService} as Dubbo service - * - * @return the exported {@link URL URLs} - */ - public List export() { + /** + * The ServiceConfig of DubboMetadataConfigService to be exported, can be nullable. + */ + private ServiceConfig serviceConfig; - if (serviceConfig == null || !serviceConfig.isExported()) { + /** + * export {@link DubboMetadataService} as Dubbo service + * + * @return the exported {@link URL URLs} + */ + public List export() { - serviceConfig = new ServiceConfig<>(); + if (serviceConfig == null || !serviceConfig.isExported()) { - serviceConfig.setInterface(DubboMetadataService.class); - // Use DubboMetadataService.VERSION as the Dubbo Service version - serviceConfig.setVersion(DubboMetadataService.VERSION); - // Use current Spring application name as the Dubbo Service group - serviceConfig.setGroup(currentApplicationName); - serviceConfig.setRef(dubboMetadataService.getIfAvailable()); - serviceConfig.setApplication(applicationConfig); - serviceConfig.setProtocol(protocolConfigSupplier.get()); + serviceConfig = new ServiceConfig<>(); - serviceConfig.export(); + serviceConfig.setInterface(DubboMetadataService.class); + // Use DubboMetadataService.VERSION as the Dubbo Service version + serviceConfig.setVersion(DubboMetadataService.VERSION); + // Use current Spring application name as the Dubbo Service group + serviceConfig.setGroup(currentApplicationName); + serviceConfig.setRef(dubboMetadataService.getIfAvailable()); + serviceConfig.setApplication(applicationConfig); + serviceConfig.setProtocol(protocolConfigSupplier.get()); - if (logger.isInfoEnabled()) { - logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString()); - } - } + serviceConfig.export(); - return serviceConfig.getExportedUrls(); - } + if (logger.isInfoEnabled()) { + logger.info("The Dubbo service[{}] has been exported.", + serviceConfig.toString()); + } + } + return serviceConfig.getExportedUrls(); + } - /** - * unexport {@link DubboMetadataService} - */ - @PreDestroy - public void unexport() { + /** + * unexport {@link DubboMetadataService} + */ + @PreDestroy + public void unexport() { - if (serviceConfig == null || serviceConfig.isUnexported()) { - return; - } + if (serviceConfig == null || serviceConfig.isUnexported()) { + return; + } - serviceConfig.unexport(); + serviceConfig.unexport(); - if (logger.isInfoEnabled()) { - logger.info("The Dubbo service[{}] has been unexported.", serviceConfig.toString()); - } - } + if (logger.isInfoEnabled()) { + logger.info("The Dubbo service[{}] has been unexported.", + serviceConfig.toString()); + } + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java index 9312581f1..ca4b05f63 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java @@ -16,15 +16,15 @@ */ package com.alibaba.cloud.dubbo.service; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.stream.Stream; + import org.apache.dubbo.rpc.service.GenericService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.util.stream.Stream; - /** * {@link DubboMetadataService} {@link InvocationHandler} * @@ -32,29 +32,34 @@ import java.util.stream.Stream; */ class DubboMetadataServiceInvocationHandler implements InvocationHandler { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final GenericService genericService; - - public DubboMetadataServiceInvocationHandler(String serviceName, String version, DubboGenericServiceFactory dubboGenericServiceFactory) { - this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class, version); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object returnValue = null; - try { - returnValue = genericService.$invoke(method.getName(), getParameterTypes(method), args); - } catch (Throwable e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); - } - } - return returnValue; - } - - private String[] getParameterTypes(Method method) { - Class[] parameterTypes = method.getParameterTypes(); - return Stream.of(parameterTypes).map(Class::getName).toArray(length -> new String[length]); - } + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final GenericService genericService; + + public DubboMetadataServiceInvocationHandler(String serviceName, String version, + DubboGenericServiceFactory dubboGenericServiceFactory) { + this.genericService = dubboGenericServiceFactory.create(serviceName, + DubboMetadataService.class, version); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object returnValue = null; + try { + returnValue = genericService.$invoke(method.getName(), + getParameterTypes(method), args); + } + catch (Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return returnValue; + } + + private String[] getParameterTypes(Method method) { + Class[] parameterTypes = method.getParameterTypes(); + return Stream.of(parameterTypes).map(Class::getName) + .toArray(length -> new String[length]); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java index 6eb7ef1cf..21c019c23 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.service; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.DisposableBean; +import static java.lang.reflect.Proxy.newProxyInstance; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import static java.lang.reflect.Proxy.newProxyInstance; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.DisposableBean; /** * The proxy of {@link DubboMetadataService} @@ -31,54 +31,58 @@ import static java.lang.reflect.Proxy.newProxyInstance; */ public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean { - private final DubboGenericServiceFactory dubboGenericServiceFactory; - private final Map dubboMetadataServiceCache = new ConcurrentHashMap<>(); - private ClassLoader classLoader; + private final DubboGenericServiceFactory dubboGenericServiceFactory; + private final Map dubboMetadataServiceCache = new ConcurrentHashMap<>(); + private ClassLoader classLoader; - public DubboMetadataServiceProxy(DubboGenericServiceFactory dubboGenericServiceFactory) { - this.dubboGenericServiceFactory = dubboGenericServiceFactory; - } + public DubboMetadataServiceProxy( + DubboGenericServiceFactory dubboGenericServiceFactory) { + this.dubboGenericServiceFactory = dubboGenericServiceFactory; + } - /** - * Initializes {@link DubboMetadataService}'s Proxy - * - * @param serviceName the service name - * @param version the service version - * @return a {@link DubboMetadataService} proxy - */ - public DubboMetadataService initProxy(String serviceName, String version) { - return dubboMetadataServiceCache.computeIfAbsent(serviceName, name -> newProxy(name, version)); - } + /** + * Initializes {@link DubboMetadataService}'s Proxy + * + * @param serviceName the service name + * @param version the service version + * @return a {@link DubboMetadataService} proxy + */ + public DubboMetadataService initProxy(String serviceName, String version) { + return dubboMetadataServiceCache.computeIfAbsent(serviceName, + name -> newProxy(name, version)); + } - /** - * Get a proxy instance of {@link DubboMetadataService} via the specified service name - * - * @param serviceName the service name - * @return a {@link DubboMetadataService} proxy - */ - public DubboMetadataService getProxy(String serviceName) { - return dubboMetadataServiceCache.get(serviceName); - } + /** + * Get a proxy instance of {@link DubboMetadataService} via the specified service name + * + * @param serviceName the service name + * @return a {@link DubboMetadataService} proxy + */ + public DubboMetadataService getProxy(String serviceName) { + return dubboMetadataServiceCache.get(serviceName); + } - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } - @Override - public void destroy() throws Exception { - dubboMetadataServiceCache.clear(); - } + @Override + public void destroy() throws Exception { + dubboMetadataServiceCache.clear(); + } - /** - * New a proxy instance of {@link DubboMetadataService} via the specified service name - * - * @param serviceName the service name - * @param version the service version - * @return a {@link DubboMetadataService} proxy - */ - protected DubboMetadataService newProxy(String serviceName, String version) { - return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class}, - new DubboMetadataServiceInvocationHandler(serviceName, version, dubboGenericServiceFactory)); - } + /** + * New a proxy instance of {@link DubboMetadataService} via the specified service name + * + * @param serviceName the service name + * @param version the service version + * @return a {@link DubboMetadataService} proxy + */ + protected DubboMetadataService newProxy(String serviceName, String version) { + return (DubboMetadataService) newProxyInstance(classLoader, + new Class[] { DubboMetadataService.class }, + new DubboMetadataServiceInvocationHandler(serviceName, version, + dubboGenericServiceFactory)); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java index 79ef1bf9f..b4d8cc20d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java @@ -16,15 +16,8 @@ */ package com.alibaba.cloud.dubbo.service; -import org.apache.dubbo.common.URL; - -import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.util.JSONUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; +import static java.util.Collections.unmodifiableMap; +import static org.springframework.util.CollectionUtils.isEmpty; import java.util.Collections; import java.util.HashMap; @@ -32,8 +25,16 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static java.util.Collections.unmodifiableMap; -import static org.springframework.util.CollectionUtils.isEmpty; +import org.apache.dubbo.common.URL; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; + +import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.util.JSONUtils; /** * Introspective {@link DubboMetadataService} implementation @@ -42,55 +43,57 @@ import static org.springframework.util.CollectionUtils.isEmpty; */ public class IntrospectiveDubboMetadataService implements DubboMetadataService { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private ObjectProvider dubboServiceMetadataRepository; - - @Autowired - private JSONUtils jsonUtils; - - @Override - public String getServiceRestMetadata() { - Set serviceRestMetadata = getRepository().getServiceRestMetadata(); - String serviceRestMetadataJsonConfig = null; - if (!isEmpty(serviceRestMetadata)) { - serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata); - } - return serviceRestMetadataJsonConfig; - } - - @Override - public Set getAllServiceKeys() { - return getRepository().getAllServiceKeys(); - } - - @Override - public Map getAllExportedURLs() { - Map> allExportedUrls = getRepository().getAllExportedUrls(); - if (isEmpty(allExportedUrls)) { - if (logger.isDebugEnabled()) { - logger.debug("There is no registered URL."); - } - return Collections.emptyMap(); - } - - Map result = new HashMap<>(); - - allExportedUrls.forEach((serviceKey, urls) -> { - result.put(serviceKey, jsonUtils.toJSON(urls)); - }); - - return unmodifiableMap(result); - } - - @Override - public String getExportedURLs(String serviceInterface, String group, String version) { - List urls = getRepository().getExportedURLs(serviceInterface, group, version); - return jsonUtils.toJSON(urls); - } - - private DubboServiceMetadataRepository getRepository() { - return dubboServiceMetadataRepository.getIfAvailable(); - } + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ObjectProvider dubboServiceMetadataRepository; + + @Autowired + private JSONUtils jsonUtils; + + @Override + public String getServiceRestMetadata() { + Set serviceRestMetadata = getRepository() + .getServiceRestMetadata(); + String serviceRestMetadataJsonConfig = null; + if (!isEmpty(serviceRestMetadata)) { + serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata); + } + return serviceRestMetadataJsonConfig; + } + + @Override + public Set getAllServiceKeys() { + return getRepository().getAllServiceKeys(); + } + + @Override + public Map getAllExportedURLs() { + Map> allExportedUrls = getRepository().getAllExportedUrls(); + if (isEmpty(allExportedUrls)) { + if (logger.isDebugEnabled()) { + logger.debug("There is no registered URL."); + } + return Collections.emptyMap(); + } + + Map result = new HashMap<>(); + + allExportedUrls.forEach((serviceKey, urls) -> { + result.put(serviceKey, jsonUtils.toJSON(urls)); + }); + + return unmodifiableMap(result); + } + + @Override + public String getExportedURLs(String serviceInterface, String group, String version) { + List urls = getRepository().getExportedURLs(serviceInterface, group, + version); + return jsonUtils.toJSON(urls); + } + + private DubboServiceMetadataRepository getRepository() { + return dubboServiceMetadataRepository.getIfAvailable(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java index c646e7684..4d63363ef 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java @@ -16,67 +16,67 @@ */ package com.alibaba.cloud.dubbo.service.parameter; +import static org.springframework.context.ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME; +import static org.springframework.util.ClassUtils.resolveClassName; + 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.DefaultFormattingConversionService; -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 { + implements DubboGenericServiceParameterResolver, BeanClassLoaderAware { - private int order; + private int order; - @Autowired(required = false) - @Qualifier(CONVERSION_SERVICE_BEAN_NAME) - private ConversionService conversionService = new DefaultFormattingConversionService(); + @Autowired(required = false) + @Qualifier(CONVERSION_SERVICE_BEAN_NAME) + private ConversionService conversionService = new DefaultFormattingConversionService(); - private ClassLoader classLoader; + private ClassLoader classLoader; - public ConversionService getConversionService() { - return conversionService; - } + public ConversionService getConversionService() { + return conversionService; + } - public void setConversionService(ConversionService conversionService) { - this.conversionService = conversionService; - } + public void setConversionService(ConversionService conversionService) { + this.conversionService = conversionService; + } - public ClassLoader getClassLoader() { - return classLoader; - } + public ClassLoader getClassLoader() { + return classLoader; + } - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } - @Override - public int getOrder() { - return order; - } + @Override + public int getOrder() { + return order; + } - public void setOrder(int order) { - this.order = order; - } + public void setOrder(int order) { + this.order = order; + } - protected Class resolveClass(String className) { - return resolveClassName(className, classLoader); - } + 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, String parameterType) { + Class targetType = resolveClass(parameterType); + return resolveValue(parameterValue, targetType); + } - protected Object resolveValue(Object parameterValue, Class parameterType) { - return conversionService.convert(parameterValue, parameterType); - } + protected Object resolveValue(Object parameterValue, Class parameterType) { + return conversionService.convert(parameterValue, parameterType); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractNamedValueServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractNamedValueServiceParameterResolver.java index 721109f35..50fc7b76a 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractNamedValueServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractNamedValueServiceParameterResolver.java @@ -16,107 +16,117 @@ */ package com.alibaba.cloud.dubbo.service.parameter; -import com.alibaba.cloud.dubbo.http.HttpServerRequest; -import com.alibaba.cloud.dubbo.metadata.MethodParameterMetadata; -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import org.springframework.util.CollectionUtils; -import org.springframework.util.MultiValueMap; +import static org.springframework.util.ObjectUtils.isEmpty; import java.util.Collection; import java.util.Collections; import java.util.Map; -import static org.springframework.util.ObjectUtils.isEmpty; +import org.springframework.util.CollectionUtils; +import org.springframework.util.MultiValueMap; + +import com.alibaba.cloud.dubbo.http.HttpServerRequest; +import com.alibaba.cloud.dubbo.metadata.MethodParameterMetadata; +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; /** - * Abstract HTTP Names Value {@link DubboGenericServiceParameterResolver Dubbo GenericService Parameter Resolver} + * Abstract HTTP Names Value {@link DubboGenericServiceParameterResolver Dubbo + * GenericService Parameter Resolver} * * @author Mercy */ -public abstract class AbstractNamedValueServiceParameterResolver extends AbstractDubboGenericServiceParameterResolver { +public abstract class AbstractNamedValueServiceParameterResolver + extends AbstractDubboGenericServiceParameterResolver { - /** - * Get the {@link MultiValueMap} of names and values - * - * @param request - * @return - */ - protected abstract MultiValueMap getNameAndValuesMap(HttpServerRequest request); + /** + * Get the {@link MultiValueMap} of names and values + * + * @param request + * @return + */ + protected abstract MultiValueMap getNameAndValuesMap( + HttpServerRequest request); - @Override - public Object resolve(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, - HttpServerRequest request) { + @Override + public Object resolve(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata, HttpServerRequest request) { - Collection names = getNames(restMethodMetadata, methodParameterMetadata); + Collection names = getNames(restMethodMetadata, methodParameterMetadata); - if (isEmpty(names)) { // index can't match - return null; - } + if (isEmpty(names)) { // index can't match + return null; + } - MultiValueMap nameAndValues = getNameAndValuesMap(request); + MultiValueMap nameAndValues = getNameAndValuesMap(request); - String targetName = null; + String targetName = null; - for (String name : names) { - if (nameAndValues.containsKey(name)) { - targetName = name; - break; - } - } + for (String name : names) { + if (nameAndValues.containsKey(name)) { + targetName = name; + break; + } + } - if (targetName == null) { // request parameter is abstract - return null; - } + if (targetName == null) { // request parameter is abstract + return null; + } - Class parameterType = resolveClass(methodParameterMetadata.getType()); + Class parameterType = resolveClass(methodParameterMetadata.getType()); - Object paramValue = null; + Object paramValue = null; - if (parameterType.isArray()) { // Array type - paramValue = nameAndValues.get(targetName); - } else { - paramValue = nameAndValues.getFirst(targetName); - } + if (parameterType.isArray()) { // Array type + paramValue = nameAndValues.get(targetName); + } + else { + paramValue = nameAndValues.getFirst(targetName); + } - return resolveValue(paramValue, parameterType); - } + return resolveValue(paramValue, parameterType); + } - @Override - public Object resolve(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, - RestMethodMetadata clientRestMethodMetadata, Object[] arguments) { + @Override + public Object resolve(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata, + RestMethodMetadata clientRestMethodMetadata, Object[] arguments) { - Collection names = getNames(restMethodMetadata, methodParameterMetadata); + Collection names = getNames(restMethodMetadata, methodParameterMetadata); - if (isEmpty(names)) { // index can't match - return null; - } + if (isEmpty(names)) { // index can't match + return null; + } - Integer index = null; + Integer index = null; - Map> clientIndexToName = clientRestMethodMetadata.getIndexToName(); + Map> clientIndexToName = clientRestMethodMetadata + .getIndexToName(); - for (Map.Entry> entry : clientIndexToName.entrySet()) { + for (Map.Entry> entry : clientIndexToName + .entrySet()) { - Collection clientParamNames = entry.getValue(); + Collection clientParamNames = entry.getValue(); - if (CollectionUtils.containsAny(names, clientParamNames)) { - index = entry.getKey(); - break; - } - } + if (CollectionUtils.containsAny(names, clientParamNames)) { + index = entry.getKey(); + break; + } + } - return index > -1 ? arguments[index] : null; - } + return index > -1 ? arguments[index] : null; + } - protected Collection getNames(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata) { + protected Collection getNames(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata) { - Map> indexToName = restMethodMetadata.getIndexToName(); + Map> indexToName = restMethodMetadata + .getIndexToName(); - int index = methodParameterMetadata.getIndex(); + int index = methodParameterMetadata.getIndex(); - Collection paramNames = indexToName.get(index); + Collection paramNames = indexToName.get(index); - return paramNames == null ? Collections.emptyList() : paramNames; - } + return paramNames == null ? Collections.emptyList() : paramNames; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java index 7b676e98d..9fc4a609c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java @@ -18,10 +18,11 @@ package com.alibaba.cloud.dubbo.service.parameter; import org.apache.dubbo.rpc.service.GenericService; +import org.springframework.core.Ordered; + import com.alibaba.cloud.dubbo.http.HttpServerRequest; import com.alibaba.cloud.dubbo.metadata.MethodParameterMetadata; import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; -import org.springframework.core.Ordered; /** * Dubbo {@link GenericService} Parameter Resolver @@ -30,14 +31,15 @@ import org.springframework.core.Ordered; */ public interface DubboGenericServiceParameterResolver extends Ordered { - /** - * Resolves a method parameter into an argument value from a given request. - * - * @return - */ - Object resolve(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, - HttpServerRequest request); + /** + * Resolves a method parameter into an argument value from a given request. + * + * @return + */ + Object resolve(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata, HttpServerRequest request); - Object resolve(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, - RestMethodMetadata clientRestMethodMetadata, Object[] arguments); + Object resolve(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata, + RestMethodMetadata clientRestMethodMetadata, Object[] arguments); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/PathVariableServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/PathVariableServiceParameterResolver.java index e861fa607..0bf093d33 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/PathVariableServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/PathVariableServiceParameterResolver.java @@ -16,25 +16,29 @@ */ package com.alibaba.cloud.dubbo.service.parameter; -import com.alibaba.cloud.dubbo.http.HttpServerRequest; import org.springframework.util.MultiValueMap; +import com.alibaba.cloud.dubbo.http.HttpServerRequest; + /** - * HTTP Request Path Variable {@link DubboGenericServiceParameterResolver Dubbo GenericService Parameter Resolver} + * HTTP Request Path Variable {@link DubboGenericServiceParameterResolver Dubbo + * GenericService Parameter Resolver} * * @author Mercy */ -public class PathVariableServiceParameterResolver extends AbstractNamedValueServiceParameterResolver { +public class PathVariableServiceParameterResolver + extends AbstractNamedValueServiceParameterResolver { - public static final int DEFAULT_ORDER = 3; + public static final int DEFAULT_ORDER = 3; - public PathVariableServiceParameterResolver() { - super(); - setOrder(DEFAULT_ORDER); - } + public PathVariableServiceParameterResolver() { + super(); + setOrder(DEFAULT_ORDER); + } - @Override - protected MultiValueMap getNameAndValuesMap(HttpServerRequest request) { - return request.getQueryParams(); - } + @Override + protected MultiValueMap getNameAndValuesMap( + HttpServerRequest request) { + return request.getQueryParams(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestBodyServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestBodyServiceParameterResolver.java index 1af50b710..7e3fa88e2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestBodyServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestBodyServiceParameterResolver.java @@ -16,102 +16,112 @@ */ package com.alibaba.cloud.dubbo.service.parameter; -import com.alibaba.cloud.dubbo.http.HttpServerRequest; -import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder; -import com.alibaba.cloud.dubbo.http.util.HttpMessageConverterResolver; -import com.alibaba.cloud.dubbo.metadata.MethodParameterMetadata; -import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; +import java.io.IOException; +import java.util.Collections; +import java.util.Objects; + +import javax.annotation.PostConstruct; + import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; -import javax.annotation.PostConstruct; -import java.io.IOException; -import java.util.Collections; -import java.util.Objects; +import com.alibaba.cloud.dubbo.http.HttpServerRequest; +import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder; +import com.alibaba.cloud.dubbo.http.util.HttpMessageConverterResolver; +import com.alibaba.cloud.dubbo.metadata.MethodParameterMetadata; +import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; /** * HTTP Request Body {@link DubboGenericServiceParameterResolver} * * @author Mercy */ -public class RequestBodyServiceParameterResolver extends AbstractDubboGenericServiceParameterResolver { +public class RequestBodyServiceParameterResolver + extends AbstractDubboGenericServiceParameterResolver { - public static final int DEFAULT_ORDER = 7; + public static final int DEFAULT_ORDER = 7; - @Autowired - private ObjectProvider httpMessageConverters; + @Autowired + private ObjectProvider httpMessageConverters; - private HttpMessageConverterResolver httpMessageConverterResolver; + private HttpMessageConverterResolver httpMessageConverterResolver; - public RequestBodyServiceParameterResolver() { - super(); - setOrder(DEFAULT_ORDER); - } + public RequestBodyServiceParameterResolver() { + super(); + setOrder(DEFAULT_ORDER); + } - @PostConstruct - public void init() { - HttpMessageConverters httpMessageConverters = this.httpMessageConverters.getIfAvailable(); + @PostConstruct + public void init() { + HttpMessageConverters httpMessageConverters = this.httpMessageConverters + .getIfAvailable(); - httpMessageConverterResolver = new HttpMessageConverterResolver(httpMessageConverters == null ? - Collections.emptyList() : httpMessageConverters.getConverters(), - getClassLoader()); - } + httpMessageConverterResolver = new HttpMessageConverterResolver( + httpMessageConverters == null ? Collections.emptyList() + : httpMessageConverters.getConverters(), + getClassLoader()); + } - private boolean supportParameter(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata) { + private boolean supportParameter(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata) { - Integer index = methodParameterMetadata.getIndex(); + Integer index = methodParameterMetadata.getIndex(); - Integer bodyIndex = restMethodMetadata.getBodyIndex(); + Integer bodyIndex = restMethodMetadata.getBodyIndex(); - if (!Objects.equals(index, bodyIndex)) { - return false; - } + if (!Objects.equals(index, bodyIndex)) { + return false; + } - Class parameterType = resolveClass(methodParameterMetadata.getType()); + Class parameterType = resolveClass(methodParameterMetadata.getType()); - Class bodyType = resolveClass(restMethodMetadata.getBodyType()); + Class bodyType = resolveClass(restMethodMetadata.getBodyType()); - return Objects.equals(parameterType, bodyType); - } + return Objects.equals(parameterType, bodyType); + } - @Override - public Object resolve(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, - HttpServerRequest request) { + @Override + public Object resolve(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata, HttpServerRequest request) { - if (!supportParameter(restMethodMetadata, methodParameterMetadata)) { - return null; - } + if (!supportParameter(restMethodMetadata, methodParameterMetadata)) { + return null; + } - Object result = null; + Object result = null; - Class parameterType = resolveClass(methodParameterMetadata.getType()); + Class parameterType = resolveClass(methodParameterMetadata.getType()); - HttpMessageConverterHolder holder = httpMessageConverterResolver.resolve(request, parameterType); + 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); - } - } + 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; - } + return result; + } - @Override - public Object resolve(RestMethodMetadata restMethodMetadata, MethodParameterMetadata methodParameterMetadata, - RestMethodMetadata clientRestMethodMetadata, Object[] arguments) { + @Override + public Object resolve(RestMethodMetadata restMethodMetadata, + MethodParameterMetadata methodParameterMetadata, + RestMethodMetadata clientRestMethodMetadata, Object[] arguments) { - if (!supportParameter(restMethodMetadata, methodParameterMetadata)) { - return null; - } + if (!supportParameter(restMethodMetadata, methodParameterMetadata)) { + return null; + } - Integer clientBodyIndex = clientRestMethodMetadata.getBodyIndex(); - return arguments[clientBodyIndex]; - } + Integer clientBodyIndex = clientRestMethodMetadata.getBodyIndex(); + return arguments[clientBodyIndex]; + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestHeaderServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestHeaderServiceParameterResolver.java index 7581f4667..4656ad019 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestHeaderServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestHeaderServiceParameterResolver.java @@ -16,25 +16,29 @@ */ package com.alibaba.cloud.dubbo.service.parameter; -import com.alibaba.cloud.dubbo.http.HttpServerRequest; import org.springframework.util.MultiValueMap; +import com.alibaba.cloud.dubbo.http.HttpServerRequest; + /** - * HTTP Request Header {@link DubboGenericServiceParameterResolver Dubbo GenericService Parameter Resolver} + * HTTP Request Header {@link DubboGenericServiceParameterResolver Dubbo GenericService + * Parameter Resolver} * * @author Mercy */ -public class RequestHeaderServiceParameterResolver extends AbstractNamedValueServiceParameterResolver { +public class RequestHeaderServiceParameterResolver + extends AbstractNamedValueServiceParameterResolver { - public static final int DEFAULT_ORDER = 9; + public static final int DEFAULT_ORDER = 9; - public RequestHeaderServiceParameterResolver() { - super(); - setOrder(DEFAULT_ORDER); - } + public RequestHeaderServiceParameterResolver() { + super(); + setOrder(DEFAULT_ORDER); + } - @Override - protected MultiValueMap getNameAndValuesMap(HttpServerRequest request) { - return request.getHeaders(); - } + @Override + protected MultiValueMap getNameAndValuesMap( + HttpServerRequest request) { + return request.getHeaders(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestParamServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestParamServiceParameterResolver.java index 18cd92d23..6ec3cdc17 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestParamServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/RequestParamServiceParameterResolver.java @@ -16,25 +16,29 @@ */ package com.alibaba.cloud.dubbo.service.parameter; -import com.alibaba.cloud.dubbo.http.HttpServerRequest; import org.springframework.util.MultiValueMap; +import com.alibaba.cloud.dubbo.http.HttpServerRequest; + /** - * HTTP Request Parameter {@link DubboGenericServiceParameterResolver Dubbo GenericService Parameter Resolver} + * HTTP Request Parameter {@link DubboGenericServiceParameterResolver Dubbo GenericService + * Parameter Resolver} * * @author Mercy */ -public class RequestParamServiceParameterResolver extends AbstractNamedValueServiceParameterResolver { +public class RequestParamServiceParameterResolver + extends AbstractNamedValueServiceParameterResolver { - public static final int DEFAULT_ORDER = 1; + public static final int DEFAULT_ORDER = 1; - public RequestParamServiceParameterResolver() { - super(); - setOrder(DEFAULT_ORDER); - } + public RequestParamServiceParameterResolver() { + super(); + setOrder(DEFAULT_ORDER); + } - @Override - protected MultiValueMap getNameAndValuesMap(HttpServerRequest request) { - return request.getQueryParams(); - } + @Override + protected MultiValueMap getNameAndValuesMap( + HttpServerRequest request) { + return request.getQueryParams(); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java index a1290a18e..94071d036 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java @@ -16,21 +16,23 @@ */ package com.alibaba.cloud.dubbo.util; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.PostConstruct; + import org.apache.dubbo.common.URL; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; -import javax.annotation.PostConstruct; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; /** * JSON Utilities class @@ -39,47 +41,49 @@ import java.util.stream.Collectors; */ public class JSONUtils { - private final Logger logger = LoggerFactory.getLogger(getClass()); + private final Logger logger = LoggerFactory.getLogger(getClass()); - private final ObjectMapper objectMapper = new ObjectMapper(); + private final ObjectMapper objectMapper = new ObjectMapper(); - @PostConstruct - public void init() { - this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - } + @PostConstruct + public void init() { + this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + } - public String toJSON(Collection urls) { - return toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toSet())); - } + public String toJSON(Collection urls) { + return toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toSet())); + } - public String toJSON(Object object) { - String jsonContent = null; - try { - jsonContent = objectMapper.writeValueAsString(object); - } catch (JsonProcessingException e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); - } - } - return jsonContent; - } + public String toJSON(Object object) { + String jsonContent = null; + try { + jsonContent = objectMapper.writeValueAsString(object); + } + catch (JsonProcessingException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return jsonContent; + } - public List toURLs(String urlsJSON) { - List list = toList(urlsJSON); - return list.stream().map(URL::valueOf).collect(Collectors.toList()); - } + public List toURLs(String urlsJSON) { + List list = toList(urlsJSON); + return list.stream().map(URL::valueOf).collect(Collectors.toList()); + } - public List toList(String json) { - List list = Collections.emptyList(); - try { - if (StringUtils.hasText(json)) { - list = objectMapper.readValue(json, List.class); - } - } catch (IOException e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); - } - } - return list; - } + public List toList(String json) { + List list = Collections.emptyList(); + try { + if (StringUtils.hasText(json)) { + list = objectMapper.readValue(json, List.class); + } + } + catch (IOException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return list; + } }