From 3407cd36de1809659e570d83794ac6c61103995f Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 28 Mar 2019 01:13:41 +0800 Subject: [PATCH 1/9] Refactor Dubbo Service registration logic: 1. Simplify registration implementation 2. Add Event-Driven --- .../DubboMetadataAutoConfiguration.java | 3 +- ...etadataEventHandlingAutoConfiguration.java | 151 ++++---- .../DubboServiceAutoConfiguration.java | 13 +- .../DubboTransporterInterceptor.java | 10 +- ...ata.java => DubboRestServiceMetadata.java} | 10 +- .../DubboServiceMetadataRepository.java | 37 +- .../openfeign/TargeterInvocationHandler.java | 10 +- .../registry/AbstractRegistrationFactory.java | 68 ---- .../registry/AbstractSpringCloudRegistry.java | 293 ++++++++++++++++ .../dubbo/registry/RegistrationFactory.java | 50 --- .../registry/RegistrationFactoryProvider.java | 144 -------- .../dubbo/registry/ServiceRegistryAspect.java | 59 ++++ .../dubbo/registry/SpringCloudRegistry.java | 325 +++++------------- .../registry/SpringCloudRegistryFactory.java | 22 +- .../ZookeeperRegistrationFactory.java | 52 --- .../ServiceInstancePreRegisteredEvent.java | 39 +++ .../ServiceInstanceRegisteredEvent.java} | 19 +- .../consul/ConsulRegistrationFactory.java | 88 ----- .../eureka/EurekaRegistrationFactory.java | 60 ---- .../service/DubboGenericServiceFactory.java | 4 +- .../PublishingDubboMetadataConfigService.java | 22 +- .../cloud/alibaba/dubbo/util/JSONUtils.java | 72 ++++ .../main/resources/META-INF/spring.factories | 7 +- .../src/main/resources/application.yaml | 2 +- 24 files changed, 718 insertions(+), 842 deletions(-) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/{DubboServiceMetadata.java => DubboRestServiceMetadata.java} (84%) delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractRegistrationFactory.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractSpringCloudRegistry.java delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactory.java delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactoryProvider.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/apache/zookeeper/ZookeeperRegistrationFactory.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/{DefaultRegistrationFactory.java => event/ServiceInstanceRegisteredEvent.java} (65%) delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/hashicorp/consul/ConsulRegistrationFactory.java delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/netflix/eureka/EurekaRegistrationFactory.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/JSONUtils.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index a853a3fb..1714b864 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -28,6 +28,7 @@ import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolve import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy; import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -41,7 +42,7 @@ import java.util.function.Supplier; * @author Mercy */ @Configuration -@Import({DubboServiceMetadataRepository.class, PublishingDubboMetadataConfigService.class}) +@Import({DubboServiceMetadataRepository.class, PublishingDubboMetadataConfigService.class, JSONUtils.class}) public class DubboMetadataAutoConfiguration { @Bean diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java index e91e03c3..c4823169 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java @@ -23,33 +23,40 @@ import org.apache.dubbo.config.ServiceConfig; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import com.ecwid.consul.v1.agent.model.NewService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.event.ApplicationFailedEvent; -import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; -import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory; +import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigService; import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService; -import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; +import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.EventListener; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.HashMap; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.DUBBO_URLS_METADATA_PROPERTY_NAME; /** * The Auto-Configuration class for Dubbo metadata {@link EventListener event handling}. @@ -60,6 +67,12 @@ import java.util.function.Supplier; @Configuration public class DubboMetadataEventHandlingAutoConfiguration { + private static final String CONSUL_REGISTRATION_CLASS_NAME = + "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; + + private static final String EUREKA_REGISTRATION_CLASS_NAME = + "org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration"; + private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired @@ -77,57 +90,45 @@ public class DubboMetadataEventHandlingAutoConfiguration { @Autowired private ConfigurableApplicationContext context; + @Autowired + private DubboServiceMetadataRepository dubboServiceMetadataRepository; + + @Autowired + private JSONUtils jsonUtils; + @Value("${spring.application.name:application}") private String currentApplicationName; + @Autowired + private ServiceRegistry serviceRegistry; + + private volatile Registration registration; + /** * The ServiceConfig of DubboMetadataConfigService to be exported, can be nullable. */ private ServiceConfig serviceConfig; - private ServiceInstance restServiceInstance; - @EventListener(ServiceBeanExportedEvent.class) public void onServiceBeanExported(ServiceBeanExportedEvent event) { ServiceBean serviceBean = event.getServiceBean(); publishServiceRestMetadata(serviceBean); - setRestServiceInstance(serviceBean); } - private void setRestServiceInstance(ServiceBean serviceBean) { - List urls = serviceBean.getExportedUrls(); - urls.stream() - .filter(url -> "rest".equalsIgnoreCase(url.getProtocol())) - .forEach(url -> { - String host = url.getIp(); - int port = url.getPort(); - - if (restServiceInstance == null) { - String instanceId = currentApplicationName + "-" + host + ":" + port; - this.restServiceInstance = new DefaultServiceInstance(instanceId, currentApplicationName, - host, port, false, new HashMap<>()); - } else { - - if (!host.equals(restServiceInstance.getHost())) { - if (logger.isWarnEnabled()) { - logger.warn("Current application[{}] host is not consistent, expected: {}, actual: {}", - currentApplicationName, restServiceInstance.getHost(), host); - } - } - - if (port != restServiceInstance.getPort()) { - if (logger.isWarnEnabled()) { - logger.warn("Current application[{}] port is not consistent, expected: {}, actual: {}", - currentApplicationName, restServiceInstance.getPort(), port); - } - } - } - }); + @ConditionalOnClass(name = EUREKA_REGISTRATION_CLASS_NAME) + @Bean + public ApplicationListener onServiceBeanExportedInEureka() { + return event -> { + reRegister(); + }; } - @EventListener(ApplicationReadyEvent.class) - public void onApplicationReady() { - exportDubboMetadataConfigService(); + private void reRegister() { + Registration registration = this.registration; + if (registration == null) { + return; + } + serviceRegistry.register(registration); } @EventListener(ApplicationFailedEvent.class) @@ -140,28 +141,62 @@ public class DubboMetadataEventHandlingAutoConfiguration { unexportDubboMetadataConfigService(); } - @ConditionalOnNotWebApplication + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + exportDubboMetadataConfigService(); + attachURLsIntoMetadata(registration); + setRegistration(registration); + } + + private void setRegistration(Registration registration) { + this.registration = registration; + } + + /** + * Handle the pre-registered event of {@link ServiceInstance} for Consul + * + * @return ApplicationListener + */ + @ConditionalOnClass(name = CONSUL_REGISTRATION_CLASS_NAME) @Bean - public ApplicationRunner applicationRunner() { - return args -> { - - if (restServiceInstance == null) { - return; + public ApplicationListener onServiceInstancePreRegisteredInConsul() { + return event -> { + Registration registration = event.getSource(); + String registrationClassName = registration.getClass().getName(); + if (CONSUL_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { + NewService newService = ((ConsulRegistration) registration).getService(); + String dubboURLsJson = getDubboURLsJSON(); + if (StringUtils.hasText(dubboURLsJson)) { + List tags = newService.getTags(); + tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson); + } } - - // From RegistrationFactoryProvider - RegistrationFactory registrationFactory = context.getBean(RegistrationFactory.class); - - ServiceRegistry serviceRegistry = context.getBean(ServiceRegistry.class); - - Registration registration = context.getBean(Registration.class); - - restServiceInstance.getMetadata().putAll(registration.getMetadata()); - - serviceRegistry.register(registrationFactory.create(restServiceInstance, context)); }; } + private void attachURLsIntoMetadata(Registration registration) { + if (registration == null) { + return; + } + Map metadata = registration.getMetadata(); + String dubboURLsJson = getDubboURLsJSON(); + if (StringUtils.hasText(dubboURLsJson)) { + metadata.put(DUBBO_URLS_METADATA_PROPERTY_NAME, dubboURLsJson); + } + } + + private String getDubboURLsJSON() { + Collection urls = dubboServiceMetadataRepository.getRegisteredUrls(); + if (CollectionUtils.isEmpty(urls)) { + if (logger.isDebugEnabled()) { + logger.debug("There is no registered URL to attach into metadata."); + } + return null; + } + return jsonUtils.toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toList())); + } + private void publishServiceRestMetadata(ServiceBean serviceBean) { dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java index 88da964d..c06108ed 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java @@ -18,9 +18,10 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.config.spring.util.PropertySourcesUtils; + import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactoryProvider; +import org.springframework.cloud.alibaba.dubbo.registry.ServiceRegistryAspect; import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler; import org.springframework.cloud.alibaba.dubbo.registry.handler.StandardDubboRegistryServiceIdHandler; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; @@ -72,14 +73,14 @@ public class DubboServiceAutoConfiguration { } @Bean - @ConditionalOnMissingBean - public DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler(ConfigurableApplicationContext context) { - return new StandardDubboRegistryServiceIdHandler(context); + public ServiceRegistryAspect serviceRegistryAspect() { + return new ServiceRegistryAspect(); } @Bean - public RegistrationFactoryProvider registrationFactoryProvider() { - return new RegistrationFactoryProvider(); + @ConditionalOnMissingBean + public DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler(ConfigurableApplicationContext context) { + return new StandardDubboRegistryServiceIdHandler(context); } /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java index 9920e8c5..4860a3c3 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java @@ -20,7 +20,7 @@ import org.apache.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericService; import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest; -import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; @@ -87,16 +87,16 @@ public class DubboTransporterInterceptor implements ClientHttpRequestInterceptor RequestMetadata clientMetadata = buildRequestMetadata(request); - DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, clientMetadata); + DubboRestServiceMetadata metadata = repository.get(serviceName, clientMetadata); - if (dubboServiceMetadata == null) { + if (metadata == null) { // if DubboServiceMetadata is not found, executes next return execution.execute(request, body); } - RestMethodMetadata dubboRestMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); + RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata(); - GenericService genericService = serviceFactory.create(dubboServiceMetadata, dubboTranslatedAttributes); + GenericService genericService = serviceFactory.create(metadata, dubboTranslatedAttributes); MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(request, body); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboServiceMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboRestServiceMetadata.java similarity index 84% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboServiceMetadata.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboRestServiceMetadata.java index f245df09..5c5ef3ad 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboServiceMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboRestServiceMetadata.java @@ -19,17 +19,17 @@ package org.springframework.cloud.alibaba.dubbo.metadata; import java.util.Objects; /** - * Dubbo Service Metadata + * Dubbo Rest Service Metadata * * @author Mercy */ -public class DubboServiceMetadata { +public class DubboRestServiceMetadata { private final ServiceRestMetadata serviceRestMetadata; private final RestMethodMetadata restMethodMetadata; - public DubboServiceMetadata(ServiceRestMetadata serviceRestMetadata, RestMethodMetadata restMethodMetadata) { + public DubboRestServiceMetadata(ServiceRestMetadata serviceRestMetadata, RestMethodMetadata restMethodMetadata) { this.serviceRestMetadata = serviceRestMetadata; this.restMethodMetadata = restMethodMetadata; } @@ -45,8 +45,8 @@ public class DubboServiceMetadata { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof DubboServiceMetadata)) return false; - DubboServiceMetadata that = (DubboServiceMetadata) o; + if (!(o instanceof DubboRestServiceMetadata)) return false; + DubboRestServiceMetadata that = (DubboRestServiceMetadata) o; return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) && Objects.equals(restMethodMetadata, that.restMethodMetadata); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java index e8d21a31..e4a58102 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java @@ -16,13 +16,15 @@ */ package org.springframework.cloud.alibaba.dubbo.metadata.repository; +import org.apache.dubbo.common.URL; + 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.annotation.Autowired; import org.springframework.cloud.alibaba.dubbo.http.matcher.RequestMetadataMatcher; -import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigService; @@ -30,6 +32,7 @@ import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServic import org.springframework.http.HttpRequest; import org.springframework.stereotype.Repository; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -51,17 +54,31 @@ public class DubboServiceMetadataRepository { private final ObjectMapper objectMapper = new ObjectMapper(); + private final Set registeredURLs = new LinkedHashSet<>(); + /** * Key is application name - * Value is Map + * Value is Map */ - private Map> repository = newHashMap(); + private Map> repository = newHashMap(); @Autowired private DubboMetadataConfigServiceProxy dubboMetadataConfigServiceProxy; + public void registerURL(URL url) { + this.registeredURLs.add(url); + } + + public void unregisterURL(URL url) { + this.registeredURLs.remove(url); + } + + public Collection getRegisteredUrls() { + return Collections.unmodifiableSet(registeredURLs); + } + /** - * Initialize the specified service's Dubbo Service Metadata + * Initialize the specified service's {@link ServiceRestMetadata} * * @param serviceName the service name */ @@ -81,14 +98,14 @@ public class DubboServiceMetadataRepository { return; } - Map metadataMap = getMetadataMap(serviceName); + Map metadataMap = getMetadataMap(serviceName); for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { serviceRestMetadata.getMeta().forEach(restMethodMetadata -> { RequestMetadata requestMetadata = restMethodMetadata.getRequest(); RequestMetadataMatcher matcher = new RequestMetadataMatcher(requestMetadata); - DubboServiceMetadata metadata = new DubboServiceMetadata(serviceRestMetadata, restMethodMetadata); + DubboRestServiceMetadata metadata = new DubboRestServiceMetadata(serviceRestMetadata, restMethodMetadata); metadataMap.put(matcher, metadata); }); } @@ -99,13 +116,13 @@ public class DubboServiceMetadataRepository { } /** - * Get a {@link DubboServiceMetadata} by the specified service name if {@link RequestMetadata} matched + * 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 DubboServiceMetadata} if matched, or null + * @return {@link DubboRestServiceMetadata} if matched, or null */ - public DubboServiceMetadata get(String serviceName, RequestMetadata requestMetadata) { + public DubboRestServiceMetadata get(String serviceName, RequestMetadata requestMetadata) { return match(repository, serviceName, requestMetadata); } @@ -148,7 +165,7 @@ public class DubboServiceMetadataRepository { return object; } - private Map getMetadataMap(String serviceName) { + private Map getMetadataMap(String serviceName) { return getMap(repository, serviceName); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java index 9ef731dd..fa93bb27 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/TargeterInvocationHandler.java @@ -24,7 +24,7 @@ import feign.Target; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported; -import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; @@ -147,13 +147,13 @@ class TargeterInvocationHandler implements InvocationHandler { for (Map.Entry entry : feignRestMethodMetadataMap.entrySet()) { RestMethodMetadata feignRestMethodMetadata = entry.getValue(); RequestMetadata feignRequestMetadata = feignRestMethodMetadata.getRequest(); - DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, feignRequestMetadata); - if (dubboServiceMetadata != null) { + 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(dubboServiceMetadata, dubboTranslatedAttributes); - RestMethodMetadata dubboRestMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); + GenericService dubboGenericService = dubboGenericServiceFactory.create(metadata, dubboTranslatedAttributes); + RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata(); MethodMetadata methodMetadata = dubboTransportedMethodMetadata.getMethodMetadata(); FeignMethodMetadata feignMethodMetadata = new FeignMethodMetadata(dubboGenericService, dubboRestMethodMetadata, feignRestMethodMetadata); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractRegistrationFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractRegistrationFactory.java deleted file mode 100644 index f17c3019..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractRegistrationFactory.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.URL; -import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler; -import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.context.ConfigurableApplicationContext; - -import java.util.LinkedHashMap; - -/** - * Abstract {@link RegistrationFactory} implementation - *

- * - * @param The subclass of {@link Registration} - * @author Mercy - */ -public abstract class AbstractRegistrationFactory implements RegistrationFactory { - - public final R create(URL url, ConfigurableApplicationContext applicationContext) { - ServiceInstance serviceInstance = createServiceInstance(url, applicationContext); - return create(serviceInstance, applicationContext); - } - - /** - * Create an instance {@link ServiceInstance}. This method maybe override by sub-class. - * - * @param url The Dubbo's {@link URL} - * @param applicationContext {@link ConfigurableApplicationContext} - * @return an instance {@link ServiceInstance} - */ - protected ServiceInstance createServiceInstance(URL url, ConfigurableApplicationContext applicationContext) { - String serviceId = createServiceId(url, applicationContext); - // Append default category if absent - String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); - URL newURL = url.addParameter(Constants.CATEGORY_KEY, category); - newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol()); - String ip = url.getIp(); - int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort()); - DefaultServiceInstance serviceInstance = new DefaultServiceInstance(url.toIdentityString(), serviceId, ip, port, false); - serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters())); - return serviceInstance; - } - - protected String createServiceId(URL url, ConfigurableApplicationContext applicationContext) { - DubboRegistryServiceIdHandler handler = applicationContext.getBean(DubboRegistryServiceIdHandler.class); - return handler.createServiceId(url); - } -} - diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractSpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractSpringCloudRegistry.java new file mode 100644 index 00000000..c52cf231 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/AbstractSpringCloudRegistry.java @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.registry.RegistryFactory; +import org.apache.dubbo.registry.support.FailbackRegistry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static java.util.Collections.singleton; +import static org.apache.dubbo.common.Constants.PROVIDER_SIDE; +import static org.apache.dubbo.common.Constants.SIDE_KEY; +import static org.springframework.util.ObjectUtils.isEmpty; + +/** + * 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 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; + + protected final ScheduledExecutorService servicesLookupScheduler; + + public AbstractSpringCloudRegistry(URL url, + DiscoveryClient discoveryClient, + ScheduledExecutorService servicesLookupScheduler) { + super(url); + this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L); + this.discoveryClient = discoveryClient; + this.servicesLookupScheduler = servicesLookupScheduler; + } + + 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) { + Set serviceNames = getServiceNames(url); + doSubscribe(url, listener, serviceNames); + } + + @Override + public final void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } + } + + @Override + public boolean isAvailable() { + return !discoveryClient.getServices().isEmpty(); + } + + protected void shutdownServiceNamesLookup() { + if (servicesLookupScheduler != null) { + servicesLookupScheduler.shutdown(); + } + } + + private void filterServiceNames(Collection serviceNames) { + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + return supports(serviceName); + } + }); + } + + protected abstract boolean supports(String serviceName); + + protected final Set getAllServiceNames() { + return new LinkedHashSet<>(discoveryClient.getServices()); + } + + /** + * Get the service names from the specified {@link URL url} + * + * @param url {@link URL} + * @return non-null + */ + private Set getServiceNames(URL url) { + if (isAdminProtocol(url)) { + return getServiceNamesForOps(url); + } else { + return singleton(getServiceName(url)); + } + } + + protected boolean isAdminProtocol(URL url) { + return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + /** + * Get the service names for Dubbo OPS + * + * @param url {@link URL} + * @return non-null + */ + protected Set getServiceNamesForOps(URL url) { + Set serviceNames = getAllServiceNames(); + filterServiceNames(serviceNames); + return serviceNames; + } + + protected abstract String getServiceName(URL url); + + private void doSubscribe(final URL url, final NotifyListener listener, final Collection serviceNames) { + + subscribe(url, listener, serviceNames); + + schedule(() -> { + subscribe(url, listener, serviceNames); + }); + } + + protected ScheduledFuture schedule(Runnable runnable) { + return this.servicesLookupScheduler.scheduleAtFixedRate(runnable, servicesLookupInterval, + servicesLookupInterval, TimeUnit.SECONDS); + } + + protected List getServiceInstances(String serviceName) { + return discoveryClient.getInstances(serviceName); + } + + private void subscribe(final URL url, final NotifyListener listener, final Collection serviceNames) { + for (String serviceName : serviceNames) { + List serviceInstances = getServiceInstances(serviceName); + if (!isEmpty(serviceInstances)) { + notifySubscriber(url, listener, serviceInstances); + } + } + } + + /** + * Notify the Healthy {@link ServiceInstance service instance} to subscriber. + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @param serviceInstances all {@link ServiceInstance instances} + */ + protected abstract void notifySubscriber(URL url, NotifyListener listener, List serviceInstances); + + protected void filterHealthyInstances(Collection instances) { + filter(instances, new Filter() { + @Override + public boolean accept(ServiceInstance data) { + // TODO check the details of status +// return serviceRegistry.getStatus(new DubboRegistration(data)) != null; + return true; + } + }); + } + + protected List buildURLs(URL consumerURL, Collection serviceInstances) { + if (serviceInstances.isEmpty()) { + return Collections.emptyList(); + } + List urls = new LinkedList(); + for (ServiceInstance serviceInstance : serviceInstances) { + URL url = buildURL(serviceInstance); + if (UrlUtils.isMatch(consumerURL, url)) { + urls.add(url); + } + } + return urls; + } + + private URL buildURL(ServiceInstance serviceInstance) { + URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), + serviceInstance.getHost(), + serviceInstance.getPort(), + serviceInstance.getMetadata()); + return url; + } + + private void filter(Collection collection, Filter filter) { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + T data = iterator.next(); + if (!filter.accept(data)) { // remove if not accept + iterator.remove(); + } + } + } + + private static T[] of(T... values) { + return values; + } + + /** + * A filter + */ + public interface Filter { + + /** + * Tests whether or not the specified data should be accepted. + * + * @param data The data to be tested + * @return true if and only if data + * should be accepted + */ + boolean accept(T data); + + } + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactory.java deleted file mode 100644 index d05eea94..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry; - -import org.apache.dubbo.common.URL; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.context.ConfigurableApplicationContext; - - -/** - * {@link Registration} Factory to createServiceInstance a instance of {@link Registration} - * - * @param The subclass of {@link Registration} - * @author Mercy - */ -public interface RegistrationFactory { - - /** - * Create a instance of {@link R} - * - * @param url The Dubbo's {@link URL} - * @param applicationContext {@link ConfigurableApplicationContext} - * @return a instance of {@link R}, if null, it indicates the registration will not be executed. - */ - R create(URL url, ConfigurableApplicationContext applicationContext); - - /** - * Create a instance of {@link R} - * - * @param serviceInstance {@link ServiceInstance} - * @param applicationContext {@link ConfigurableApplicationContext} - * @return a instance of {@link R}, if null, it indicates the registration will not be executed. - */ - R create(ServiceInstance serviceInstance, ConfigurableApplicationContext applicationContext); -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactoryProvider.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactoryProvider.java deleted file mode 100644 index c5debc68..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/RegistrationFactoryProvider.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.core.ResolvableType; - -import java.util.List; - -import static org.springframework.beans.BeanUtils.instantiateClass; -import static org.springframework.core.ResolvableType.forInstance; -import static org.springframework.core.ResolvableType.forType; -import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames; -import static org.springframework.util.ClassUtils.isPresent; -import static org.springframework.util.ClassUtils.resolveClassName; - -/** - * {@link RegistrationFactory} Provider - * - * @author Mercy - */ -public class RegistrationFactoryProvider implements FactoryBean, ApplicationContextAware { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private RegistrationFactory registrationFactory; - - @Override - public RegistrationFactory getObject() throws BeansException { - return registrationFactory; - } - - @Override - public Class getObjectType() { - return RegistrationFactory.class; - } - - public boolean isSingleton() { - return true; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - ServiceRegistry serviceRegistry = applicationContext.getBean(ServiceRegistry.class); - ClassLoader classLoader = applicationContext.getClassLoader(); - this.registrationFactory = buildRegistrationFactory(serviceRegistry, classLoader); - } - - private RegistrationFactory buildRegistrationFactory(ServiceRegistry serviceRegistry, - ClassLoader classLoader) { - RegistrationFactory registrationFactory = null; - List factoryClassNames = loadFactoryNames(RegistrationFactory.class, classLoader); - - ResolvableType serviceRegistryType = forInstance(serviceRegistry); - // Get first generic Class - Class registrationClass = resolveGenericClass(serviceRegistryType, ServiceRegistry.class, 0); - - for (String factoryClassName : factoryClassNames) { - if (isPresent(factoryClassName, classLoader)) { // ignore compilation issue - Class factoryClass = resolveClassName(factoryClassName, classLoader); - ResolvableType registrationFactoryType = forType(factoryClass); - Class actualRegistrationClass = resolveGenericClass(registrationFactoryType, RegistrationFactory.class, 0); - if (registrationClass.equals(actualRegistrationClass)) { - registrationFactory = (RegistrationFactory) instantiateClass(registrationFactoryType.getRawClass()); - break; - } - } - } - - if (registrationFactory == null) { - - if (logger.isWarnEnabled()) { - logger.warn("{} implementation can't be resolved by ServiceRegistry[{}]", - registrationClass.getSimpleName(), serviceRegistry.getClass().getName()); - } - - registrationFactory = new DefaultRegistrationFactory(); - } else { - if (logger.isInfoEnabled()) { - logger.info("{} has been resolved by ServiceRegistry[{}]", - registrationFactory.getClass().getName(), serviceRegistry.getClass().getName()); - } - } - - return registrationFactory; - } - - private Class resolveGenericClass(ResolvableType implementedType, Class interfaceClass, int index) { - - ResolvableType resolvableType = implementedType; - - try { - OUTER: - while (true) { - - ResolvableType[] interfaceTypes = resolvableType.getInterfaces(); - - for (ResolvableType interfaceType : interfaceTypes) { - if (interfaceType.resolve().equals(interfaceClass)) { - resolvableType = interfaceType; - break OUTER; - } - } - - ResolvableType superType = resolvableType.getSuperType(); - - Class superClass = superType.resolve(); - - if (Object.class.equals(superClass)) { - break; - } - - resolvableType = superType; - } - - } catch (Throwable e) { - resolvableType = ResolvableType.forType(void.class); - } - - return resolvableType.resolveGeneric(index); - } - -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java new file mode 100644 index 00000000..72ac16b0 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry; + +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; +import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstanceRegisteredEvent; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; + +/** + * {@link ServiceRegistry} Aspect + * + * @author Mercy + */ +@Aspect +public class ServiceRegistryAspect implements ApplicationEventPublisherAware { + + /** + * The pointcut expression for {@link ServiceRegistry#register(Registration)} + */ + private 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/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java index d87e1f6c..d973e629 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -16,299 +16,138 @@ */ package org.springframework.cloud.alibaba.dubbo.registry; -import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.RegistryFactory; -import org.apache.dubbo.registry.support.FailbackRegistry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler; + +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; -import static java.util.Collections.singletonList; -import static org.apache.dubbo.common.Constants.CONFIGURATORS_CATEGORY; -import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; -import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; -import static org.apache.dubbo.common.Constants.PROVIDER_SIDE; -import static org.apache.dubbo.common.Constants.ROUTERS_CATEGORY; -import static org.apache.dubbo.common.Constants.SIDE_KEY; +import static java.util.Collections.emptyMap; +import static org.apache.dubbo.common.Constants.APPLICATION_KEY; +import static org.springframework.util.CollectionUtils.isEmpty; /** * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" * * @author Mercy */ -public class SpringCloudRegistry extends FailbackRegistry { +public class SpringCloudRegistry extends AbstractSpringCloudRegistry { /** - * The parameter name of {@link #allServicesLookupInterval} + * The property name of Dubbo {@link URL URLs} metadata */ - public static final String ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.all.services.lookup.interval"; + public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo-urls"; /** - * The parameter name of {@link #registeredServicesLookupInterval} + * The parameter name of the services of Dubbo Provider */ - public static final String REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.registered.services.lookup.interval"; + public static final String DUBBO_PROVIDER_SERVICES_PARAM_NAME = "dubbo-provider-services"; /** - * All supported categories + * All services of Dubbo Provider */ - public static final String[] ALL_SUPPORTED_CATEGORIES = of( - PROVIDERS_CATEGORY, - CONSUMERS_CATEGORY, - ROUTERS_CATEGORY, - CONFIGURATORS_CATEGORY - ); + public static final String ALL_DUBBO_PROVIDER_SERVICES = "*"; - private final Logger logger = LoggerFactory.getLogger(getClass()); + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; - /** - * The interval in second of lookup service names(only for Dubbo-OPS) - */ - private final long allServicesLookupInterval; + private final JSONUtils jsonUtils; - private final long registeredServicesLookupInterval; + private final Set dubboProviderServices; - private final ServiceRegistry serviceRegistry; + private final Map dubboServiceKeysCache; - private final RegistrationFactory registrationFactory; - - private final DiscoveryClient discoveryClient; - - private final DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler; - - private final ScheduledExecutorService servicesLookupScheduler; - - private final ConfigurableApplicationContext applicationContext; - - public SpringCloudRegistry(URL url, - ServiceRegistry serviceRegistry, - RegistrationFactory registrationFactory, - DiscoveryClient discoveryClient, + public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient, ScheduledExecutorService servicesLookupScheduler, + DubboServiceMetadataRepository dubboServiceMetadataRepository, ConfigurableApplicationContext applicationContext) { - super(url); - this.allServicesLookupInterval = url.getParameter(ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 30L); - this.registeredServicesLookupInterval = url.getParameter(REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 300L); - this.serviceRegistry = serviceRegistry; - this.registrationFactory = registrationFactory; - this.discoveryClient = discoveryClient; - this.dubboRegistryServiceIdHandler = applicationContext.getBean(DubboRegistryServiceIdHandler.class); - this.applicationContext = applicationContext; - this.servicesLookupScheduler = servicesLookupScheduler; + super(url, discoveryClient, servicesLookupScheduler); + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + this.jsonUtils = applicationContext.getBean(JSONUtils.class); + this.dubboProviderServices = getDubboProviderServices(); + this.dubboServiceKeysCache = this.initDubboServiceKeysCache(); } - protected boolean shouldRegister(Registration registration) { - Map metadata = registration.getMetadata(); - String side = metadata.get(SIDE_KEY); - return PROVIDER_SIDE.equals(side); // Only register the Provider. + private Map initDubboServiceKeysCache() { + + if (isEmpty(dubboProviderServices)) { + return emptyMap(); + } + + Map newCache = new HashMap<>(); + + dubboProviderServices.stream() + .map(this::getServiceInstances) + .filter(this::isNotEmpty) + .forEach(serviceInstances -> { + ServiceInstance serviceInstance = serviceInstances.get(0); + getURLs(serviceInstance).forEach(url -> { + String serviceKey = url.getServiceKey(); + String serviceName = url.getParameter(APPLICATION_KEY); + newCache.put(serviceKey, serviceName); + }); + }); + + return newCache; + } + + private boolean isNotEmpty(Collection collection) { + return !CollectionUtils.isEmpty(collection); + } + + private List getURLs(ServiceInstance serviceInstance) { + Map metadata = serviceInstance.getMetadata(); + String dubboURLsJSON = metadata.get(DUBBO_URLS_METADATA_PROPERTY_NAME); + List urlValues = jsonUtils.toList(dubboURLsJSON); + return urlValues.stream().map(URL::valueOf).collect(Collectors.toList()); + } + + private Set getDubboProviderServices() { + URL registryURL = getUrl(); + String services = registryURL.getParameter(DUBBO_PROVIDER_SERVICES_PARAM_NAME, ALL_DUBBO_PROVIDER_SERVICES); + return ALL_DUBBO_PROVIDER_SERVICES.equalsIgnoreCase(services) ? + getAllServiceNames() : StringUtils.commaDelimitedListToSet(services); } @Override - public void doRegister(URL url) { - final Registration registration = createRegistration(url); - if (shouldRegister(registration)) { - serviceRegistry.register(registration); - } + protected void doRegister0(URL url) { + dubboServiceMetadataRepository.registerURL(url); } @Override - public void doUnregister(URL url) { - final Registration registration = createRegistration(url); - if (shouldRegister(registration)) { - this.serviceRegistry.deregister(registration); - } + protected void doUnregister0(URL url) { + dubboServiceMetadataRepository.unregisterURL(url); } @Override - public void doSubscribe(URL url, NotifyListener listener) { - List serviceNames = getServiceNames(url, listener); - doSubscribe(url, listener, serviceNames); - this.servicesLookupScheduler.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - doSubscribe(url, listener, serviceNames); - } - }, registeredServicesLookupInterval, registeredServicesLookupInterval, TimeUnit.SECONDS); + protected boolean supports(String serviceName) { + return dubboProviderServices.contains(serviceName); } @Override - public void doUnsubscribe(URL url, NotifyListener listener) { - if (isAdminProtocol(url)) { - shutdownServiceNamesLookup(); - } + protected String getServiceName(URL url) { + String serviceKey = url.getServiceKey(); + return dubboServiceKeysCache.get(serviceKey); } @Override - public boolean isAvailable() { - return !discoveryClient.getServices().isEmpty(); + protected void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) { + List urls = serviceInstances.stream().map(this::getURLs) + .flatMap(List::stream) + .collect(Collectors.toList()); + notify(url, listener, urls); } - - private void shutdownServiceNamesLookup() { - if (servicesLookupScheduler != null) { - servicesLookupScheduler.shutdown(); - } - } - - private Registration createRegistration(URL url) { - return registrationFactory.create(url, applicationContext); - } - - private void filterServiceNames(List serviceNames) { - filter(serviceNames, new Filter() { - @Override - public boolean accept(String serviceName) { - return dubboRegistryServiceIdHandler.supports(serviceName); - } - }); - } - - private List getAllServiceNames() { - return new LinkedList<>(discoveryClient.getServices()); - } - - /** - * Get the service names from the specified {@link URL url} - * - * @param url {@link URL} - * @param listener {@link NotifyListener} - * @return non-null - */ - private List getServiceNames(URL url, NotifyListener listener) { - if (isAdminProtocol(url)) { - initAllServicesLookupScheduler(url, listener); - return getServiceNamesForOps(url); - } else { - return singletonList(dubboRegistryServiceIdHandler.createServiceId(url)); - } - } - - - private boolean isAdminProtocol(URL url) { - return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); - } - - private void initAllServicesLookupScheduler(final URL url, final NotifyListener listener) { - servicesLookupScheduler.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - List serviceNames = getAllServiceNames(); - filterServiceNames(serviceNames); - doSubscribe(url, listener, serviceNames); - } - }, allServicesLookupInterval, allServicesLookupInterval, TimeUnit.SECONDS); - } - - private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) { - for (String serviceName : serviceNames) { - List serviceInstances = discoveryClient.getInstances(serviceName); - notifySubscriber(url, listener, serviceInstances); - } - } - - /** - * Notify the Healthy {@link ServiceInstance service instance} to subscriber. - * - * @param url {@link URL} - * @param listener {@link NotifyListener} - * @param serviceInstances all {@link ServiceInstance instances} - */ - private void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) { - List healthyInstances = new LinkedList(serviceInstances); - // Healthy Instances - filterHealthyInstances(healthyInstances); - List urls = buildURLs(url, healthyInstances); - this.notify(url, listener, urls); - } - - private void filterHealthyInstances(Collection instances) { - filter(instances, new Filter() { - @Override - public boolean accept(ServiceInstance data) { - // TODO check the details of status -// return serviceRegistry.getStatus(new DubboRegistration(data)) != null; - return true; - } - }); - } - - private List buildURLs(URL consumerURL, Collection serviceInstances) { - if (serviceInstances.isEmpty()) { - return Collections.emptyList(); - } - List urls = new LinkedList(); - for (ServiceInstance serviceInstance : serviceInstances) { - URL url = buildURL(serviceInstance); - if (UrlUtils.isMatch(consumerURL, url)) { - urls.add(url); - } - } - return urls; - } - - private URL buildURL(ServiceInstance serviceInstance) { - URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), - serviceInstance.getHost(), - serviceInstance.getPort(), - serviceInstance.getMetadata()); - return url; - } - - /** - * Get the service names for Dubbo OPS - * - * @param url {@link URL} - * @return non-null - */ - private List getServiceNamesForOps(URL url) { - List serviceNames = getAllServiceNames(); - filterServiceNames(serviceNames); - return serviceNames; - } - - private void filter(Collection collection, Filter filter) { - Iterator iterator = collection.iterator(); - while (iterator.hasNext()) { - T data = iterator.next(); - if (!filter.accept(data)) { // remove if not accept - iterator.remove(); - } - } - } - - private static T[] of(T... values) { - return values; - } - - /** - * A filter - */ - public interface Filter { - - /** - * Tests whether or not the specified data should be accepted. - * - * @param data The data to be tested - * @return true if and only if data - * should be accepted - */ - boolean accept(T data); - - } - } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java index 234c65d4..15dd3e5d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java @@ -20,11 +20,9 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.context.ConfigurableApplicationContext; import java.util.concurrent.ScheduledExecutorService; @@ -46,16 +44,12 @@ public class SpringCloudRegistryFactory implements RegistryFactory { private static ConfigurableApplicationContext applicationContext; - private final Logger logger = LoggerFactory.getLogger(getClass()); - private final ScheduledExecutorService servicesLookupScheduler; - private ServiceRegistry serviceRegistry; - - private RegistrationFactory registrationFactory; - private DiscoveryClient discoveryClient; + private DubboServiceMetadataRepository dubboServiceMetadataRepository; + private volatile boolean initialized = false; public SpringCloudRegistryFactory() { @@ -67,17 +61,15 @@ public class SpringCloudRegistryFactory implements RegistryFactory { if (initialized || applicationContext == null) { return; } - - this.serviceRegistry = applicationContext.getBean(ServiceRegistry.class); - this.registrationFactory = applicationContext.getBean(RegistrationFactory.class); this.discoveryClient = applicationContext.getBean(DiscoveryClient.class); + this.dubboServiceMetadataRepository = applicationContext.getBean(DubboServiceMetadataRepository.class); } @Override public Registry getRegistry(URL url) { init(); - return new SpringCloudRegistry(url, serviceRegistry, registrationFactory, discoveryClient, - servicesLookupScheduler, applicationContext); + return new SpringCloudRegistry(url, discoveryClient, servicesLookupScheduler, + dubboServiceMetadataRepository, applicationContext); } public static void setApplicationContext(ConfigurableApplicationContext applicationContext) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/apache/zookeeper/ZookeeperRegistrationFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/apache/zookeeper/ZookeeperRegistrationFactory.java deleted file mode 100644 index 23638325..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/apache/zookeeper/ZookeeperRegistrationFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper; - -import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory; -import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.zookeeper.discovery.ZookeeperInstance; -import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegistration; -import org.springframework.cloud.zookeeper.serviceregistry.ZookeeperRegistration; -import org.springframework.context.ConfigurableApplicationContext; - -/** - * Zookeeper {@link RegistrationFactory} - * - * @author Mercy - */ -public class ZookeeperRegistrationFactory extends AbstractRegistrationFactory { - - @Override - public ZookeeperRegistration create(ServiceInstance serviceInstance, ConfigurableApplicationContext applicationContext) { - ZookeeperInstance zookeeperInstance = new ZookeeperInstance(serviceInstance.getInstanceId(), - serviceInstance.getServiceId(), serviceInstance.getMetadata()); - - ZookeeperRegistration registration = ServiceInstanceRegistration - .builder() - .address(serviceInstance.getHost()) - .name(serviceInstance.getServiceId()) - .payload(zookeeperInstance) - .port(serviceInstance.getPort()) - .build(); - - // To trigger build() method - registration.getServiceInstance(); - - return registration; - } -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java new file mode 100644 index 00000000..6233e9a5 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry.event; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationEvent; + +/** + * The before-{@link ServiceRegistry#register(Registration) register} event for {@link ServiceInstance} + * + * @author Mercy + */ +public class ServiceInstancePreRegisteredEvent extends ApplicationEvent { + + public ServiceInstancePreRegisteredEvent(Registration source) { + super(source); + } + + @Override + public Registration getSource() { + return (Registration) super.getSource(); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DefaultRegistrationFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstanceRegisteredEvent.java similarity index 65% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DefaultRegistrationFactory.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstanceRegisteredEvent.java index 1bcfd534..8aab6aa7 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DefaultRegistrationFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/event/ServiceInstanceRegisteredEvent.java @@ -14,21 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.alibaba.dubbo.registry; +package org.springframework.cloud.alibaba.dubbo.registry.event; -import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; + +import java.util.EventObject; /** - * Default {@link RegistrationFactory} + * The after-{@link ServiceRegistry#register(Registration) register} event for {@link Registration} * * @author Mercy */ -public class DefaultRegistrationFactory extends AbstractRegistrationFactory { +public class ServiceInstanceRegisteredEvent extends EventObject { + + public ServiceInstanceRegisteredEvent(Registration source) { + super(source); + } @Override - public Registration create(ServiceInstance serviceInstance, ConfigurableApplicationContext applicationContext) { - return new DelegatingRegistration(serviceInstance); + public Registration getSource() { + return (Registration) super.getSource(); } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/hashicorp/consul/ConsulRegistrationFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/hashicorp/consul/ConsulRegistrationFactory.java deleted file mode 100644 index a5861fb9..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/hashicorp/consul/ConsulRegistrationFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul; - -import com.ecwid.consul.v1.agent.model.NewService; -import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory; -import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; -import org.springframework.cloud.consul.discovery.ConsulServerUtils; -import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; -import org.springframework.context.ConfigurableApplicationContext; - -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * {@link ConsulRegistration} {@link RegistrationFactory} implementation - * - * @author Mercy - */ -public class ConsulRegistrationFactory extends AbstractRegistrationFactory { - - @Override - public ConsulRegistration create(ServiceInstance serviceInstance, ConfigurableApplicationContext applicationContext) { - Map metadata = getMetadata(serviceInstance); - List tags = createTags(metadata); - - NewService service = new NewService(); - service.setId(serviceInstance.getInstanceId()); - service.setName(serviceInstance.getServiceId()); - service.setAddress(serviceInstance.getHost()); - service.setPort(serviceInstance.getPort()); - service.setMeta(metadata); - service.setTags(tags); - - ConsulDiscoveryProperties properties = applicationContext.getBean(ConsulDiscoveryProperties.class); - - ConsulRegistration registration = new ConsulRegistration(service, properties); - return registration; - } - - /** - * @param metadata - * @return - * @see ConsulServerUtils#getMetadata(java.util.List) - */ - private List createTags(Map metadata) { - List tags = new LinkedList<>(); - for (Map.Entry entry : metadata.entrySet()) { - String tag = entry.getKey() + "=" + entry.getValue(); - tags.add(tag); - - } - return tags; - } - - private Map getMetadata(ServiceInstance serviceInstance) { - Map metadata = serviceInstance.getMetadata(); - Set removedKeys = new LinkedHashSet<>(); - for (String key : metadata.keySet()) { - if (key.contains(".")) { - removedKeys.add(key); - } - } - for (String removedKey : removedKeys) { - metadata.remove(removedKey); - } - return metadata; - } -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/netflix/eureka/EurekaRegistrationFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/netflix/eureka/EurekaRegistrationFactory.java deleted file mode 100644 index e72bf40f..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/netflix/eureka/EurekaRegistrationFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka; - -import com.netflix.appinfo.HealthCheckHandler; -import com.netflix.discovery.EurekaClientConfig; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig; -import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; -import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; -import org.springframework.context.ConfigurableApplicationContext; - -/** - * {@link EurekaRegistration} Factory - * - * @author Mercy - */ -public class EurekaRegistrationFactory extends AbstractRegistrationFactory { - - @Override - public EurekaRegistration create(ServiceInstance serviceInstance, ConfigurableApplicationContext applicationContext) { - CloudEurekaInstanceConfig cloudEurekaInstanceConfig = applicationContext.getBean(CloudEurekaInstanceConfig.class); - ObjectProvider healthCheckHandler = applicationContext.getBeanProvider(HealthCheckHandler.class); - EurekaClientConfig eurekaClientConfig = applicationContext.getBean(EurekaClientConfig.class); - InetUtils inetUtils = applicationContext.getBean(InetUtils.class); - EurekaInstanceConfigBean eurekaInstanceConfigBean = new EurekaInstanceConfigBean(inetUtils); - BeanUtils.copyProperties(cloudEurekaInstanceConfig, eurekaInstanceConfigBean); - String serviceId = serviceInstance.getServiceId(); - eurekaInstanceConfigBean.setInstanceId(serviceInstance.getInstanceId()); - eurekaInstanceConfigBean.setVirtualHostName(serviceId); - eurekaInstanceConfigBean.setSecureVirtualHostName(serviceId); - eurekaInstanceConfigBean.setAppname(serviceId); - eurekaInstanceConfigBean.setHostname(serviceInstance.getHost()); - eurekaInstanceConfigBean.setNonSecurePort(serviceInstance.getPort()); - eurekaInstanceConfigBean.setMetadataMap(serviceInstance.getMetadata()); - - return EurekaRegistration.builder(eurekaInstanceConfigBean) - .with(healthCheckHandler) - .with(eurekaClientConfig, applicationContext) - .build(); - } -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java index 10cd08c9..d1648641 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboGenericServiceFactory.java @@ -25,7 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.propertyeditors.StringTrimmerEditor; -import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.util.StringUtils; import org.springframework.validation.DataBinder; @@ -54,7 +54,7 @@ public class DubboGenericServiceFactory { private final ConcurrentMap> cache = new ConcurrentHashMap<>(); - public GenericService create(DubboServiceMetadata dubboServiceMetadata, + public GenericService create(DubboRestServiceMetadata dubboServiceMetadata, Map dubboTranslatedAttributes) { ReferenceBean referenceBean = build(dubboServiceMetadata.getServiceRestMetadata(), dubboTranslatedAttributes); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataConfigService.java index fa49e94b..76fe660f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataConfigService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataConfigService.java @@ -16,13 +16,11 @@ */ package org.springframework.cloud.alibaba.dubbo.service; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.util.CollectionUtils; -import javax.annotation.PostConstruct; import java.util.LinkedHashSet; import java.util.Set; @@ -41,12 +39,8 @@ public class PublishingDubboMetadataConfigService implements DubboMetadataConfig */ private final Set serviceRestMetadata = new LinkedHashSet<>(); - private final ObjectMapper objectMapper = new ObjectMapper(); - - @PostConstruct - public void init() { - this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - } + @Autowired + private JSONUtils jsonUtils; /** * Publish the {@link Set} of {@link ServiceRestMetadata} @@ -64,12 +58,8 @@ public class PublishingDubboMetadataConfigService implements DubboMetadataConfig @Override public String getServiceRestMetadata() { String serviceRestMetadataJsonConfig = null; - try { - if (!isEmpty(serviceRestMetadata)) { - serviceRestMetadataJsonConfig = objectMapper.writeValueAsString(serviceRestMetadata); - } - } catch (JsonProcessingException e) { - throw new RuntimeException(e); + if (!isEmpty(serviceRestMetadata)) { + serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata); } return serviceRestMetadataJsonConfig; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/JSONUtils.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/JSONUtils.java new file mode 100644 index 00000000..1dd1f6da --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/util/JSONUtils.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.util; + +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.Collections; +import java.util.List; + +/** + * JSON Utilities class + * + * @author Mercy + */ +public class JSONUtils { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @PostConstruct + public void init() { + this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + 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 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; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index ed1c9c3f..951a6362 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -6,9 +6,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration org.springframework.context.ApplicationContextInitializer=\ - org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer - -org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory=\ - org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka.EurekaRegistrationFactory,\ - org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper.ZookeeperRegistrationFactory,\ - org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul.ConsulRegistrationFactory \ No newline at end of file + org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml index a890294c..786da0f2 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml @@ -16,4 +16,4 @@ feign: enabled: true server: - port: 8080 \ No newline at end of file + port: 0 \ No newline at end of file From 728c01991e36b5b9e2c4a346f2a2dc2633ae604d Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 28 Mar 2019 16:24:38 +0800 Subject: [PATCH 2/9] Separate all event-handling to smaller modules --- .../DubboMetadataAutoConfiguration.java | 49 +++++++- .../DubboServiceAutoConfiguration.java | 15 --- ...ServiceRegistrationAutoConfiguration.java} | 119 +++--------------- ...iceRegistrationEventPublishingAspect.java} | 6 +- .../DubboRegistryServiceIdHandler.java | 53 -------- ...StandardDubboRegistryServiceIdHandler.java | 96 -------------- .../DubboMetadataConfigServiceExporter.java | 109 ++++++++++++++++ .../main/resources/META-INF/spring.factories | 2 +- 8 files changed, 178 insertions(+), 271 deletions(-) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/{DubboMetadataEventHandlingAutoConfiguration.java => DubboServiceRegistrationAutoConfiguration.java} (59%) rename spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/{ServiceRegistryAspect.java => DubboServiceRegistrationEventPublishingAspect.java} (91%) delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/DubboRegistryServiceIdHandler.java delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/StandardDubboRegistryServiceIdHandler.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataConfigServiceExporter.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index 1714b864..2716510b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -17,21 +17,29 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.spring.ServiceBean; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import feign.Contract; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.event.ApplicationFailedEvent; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.alibaba.dubbo.metadata.DubboProtocolConfigSupplier; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceExporter; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy; import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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; @@ -42,9 +50,21 @@ import java.util.function.Supplier; * @author Mercy */ @Configuration -@Import({DubboServiceMetadataRepository.class, PublishingDubboMetadataConfigService.class, JSONUtils.class}) +@Import({DubboServiceMetadataRepository.class, + PublishingDubboMetadataConfigService.class, + DubboMetadataConfigServiceExporter.class, + JSONUtils.class}) public class DubboMetadataAutoConfiguration { + @Autowired + private PublishingDubboMetadataConfigService dubboMetadataConfigService; + + @Autowired + private MetadataResolver metadataResolver; + + @Autowired + private DubboMetadataConfigServiceExporter dubboMetadataConfigServiceExporter; + @Bean @ConditionalOnMissingBean public MetadataResolver metadataJsonResolver(ObjectProvider contract) { @@ -61,4 +81,31 @@ public class DubboMetadataAutoConfiguration { public DubboMetadataConfigServiceProxy dubboMetadataConfigServiceProxy(DubboGenericServiceFactory factory) { return new DubboMetadataConfigServiceProxy(factory); } + + // Event-Handling + + @EventListener(ServiceBeanExportedEvent.class) + public void onServiceBeanExported(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + publishServiceRestMetadata(serviceBean); + } + + private void publishServiceRestMetadata(ServiceBean serviceBean) { + dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); + } + + @EventListener(ApplicationReadyEvent.class) + public void onApplicationReady() { + dubboMetadataConfigServiceExporter.export(); + } + + @EventListener(ApplicationFailedEvent.class) + public void onApplicationFailed() { + dubboMetadataConfigServiceExporter.unexport(); + } + + @EventListener(ContextClosedEvent.class) + public void onContextClosed() { + dubboMetadataConfigServiceExporter.unexport(); + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java index c06108ed..c4abb94e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java @@ -21,16 +21,12 @@ import org.apache.dubbo.config.spring.util.PropertySourcesUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.cloud.alibaba.dubbo.registry.ServiceRegistryAspect; -import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler; -import org.springframework.cloud.alibaba.dubbo.registry.handler.StandardDubboRegistryServiceIdHandler; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.parameter.PathVariableServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestBodyServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestHeaderServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestParamServiceParameterResolver; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -72,17 +68,6 @@ public class DubboServiceAutoConfiguration { static class ParameterResolversConfiguration { } - @Bean - public ServiceRegistryAspect serviceRegistryAspect() { - return new ServiceRegistryAspect(); - } - - @Bean - @ConditionalOnMissingBean - public DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler(ConfigurableApplicationContext context) { - return new StandardDubboRegistryServiceIdHandler(context); - } - /** * Bugfix code for an issue : https://github.com/apache/incubator-dubbo-spring-boot-project/issues/459 * diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java similarity index 59% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index c4823169..e6c2432a 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataEventHandlingAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -17,35 +17,27 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import org.apache.dubbo.common.URL; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import com.ecwid.consul.v1.agent.model.NewService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.context.event.ApplicationFailedEvent; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; -import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; +import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; -import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigService; -import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceExporter; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; import org.springframework.context.ApplicationListener; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -53,19 +45,19 @@ import org.springframework.util.StringUtils; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import java.util.stream.Collectors; import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.DUBBO_URLS_METADATA_PROPERTY_NAME; /** - * The Auto-Configuration class for Dubbo metadata {@link EventListener event handling}. + * Dubbo Service Registration Auto-{@link Configuration} * * @author Mercy */ -@AutoConfigureAfter(value = {DubboMetadataAutoConfiguration.class}) @Configuration -public class DubboMetadataEventHandlingAutoConfiguration { +@Import({DubboServiceRegistrationEventPublishingAspect.class}) +@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) +public class DubboServiceRegistrationAutoConfiguration { private static final String CONSUL_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; @@ -76,44 +68,18 @@ public class DubboMetadataEventHandlingAutoConfiguration { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired - private MetadataResolver metadataResolver; - - @Autowired - private PublishingDubboMetadataConfigService dubboMetadataConfigService; - - @Autowired - private ApplicationConfig applicationConfig; - - @Autowired - private Supplier protocolConfigSupplier; - - @Autowired - private ConfigurableApplicationContext context; + private ServiceRegistry serviceRegistry; @Autowired private DubboServiceMetadataRepository dubboServiceMetadataRepository; @Autowired - private JSONUtils jsonUtils; - - @Value("${spring.application.name:application}") - private String currentApplicationName; + private DubboMetadataConfigServiceExporter dubboMetadataConfigServiceExporter; @Autowired - private ServiceRegistry serviceRegistry; + private JSONUtils jsonUtils; - private volatile Registration registration; - - /** - * The ServiceConfig of DubboMetadataConfigService to be exported, can be nullable. - */ - private ServiceConfig serviceConfig; - - @EventListener(ServiceBeanExportedEvent.class) - public void onServiceBeanExported(ServiceBeanExportedEvent event) { - ServiceBean serviceBean = event.getServiceBean(); - publishServiceRestMetadata(serviceBean); - } + private Registration registration; @ConditionalOnClass(name = EUREKA_REGISTRATION_CLASS_NAME) @Bean @@ -131,20 +97,15 @@ public class DubboMetadataEventHandlingAutoConfiguration { serviceRegistry.register(registration); } - @EventListener(ApplicationFailedEvent.class) - public void onApplicationFailed() { - unexportDubboMetadataConfigService(); - } - @EventListener(ContextClosedEvent.class) - public void onContextClosed() { - unexportDubboMetadataConfigService(); - } + // Event-Handling @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + + dubboMetadataConfigServiceExporter.export(); + Registration registration = event.getSource(); - exportDubboMetadataConfigService(); attachURLsIntoMetadata(registration); setRegistration(registration); } @@ -196,52 +157,4 @@ public class DubboMetadataEventHandlingAutoConfiguration { } return jsonUtils.toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toList())); } - - private void publishServiceRestMetadata(ServiceBean serviceBean) { - dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); - } - - private void exportDubboMetadataConfigService() { - - if (serviceConfig != null && serviceConfig.isExported()) { - return; - } - - if (StringUtils.isEmpty(dubboMetadataConfigService.getServiceRestMetadata())) { - // If there is no REST metadata, DubboMetadataConfigService will not be exported. - if (logger.isInfoEnabled()) { - logger.info("There is no REST metadata, the Dubbo service[{}] will not be exported.", - dubboMetadataConfigService.getClass().getName()); - } - return; - } - - serviceConfig = new ServiceConfig<>(); - - serviceConfig.setInterface(DubboMetadataConfigService.class); - // Use current Spring application name as the Dubbo Service version - serviceConfig.setVersion(currentApplicationName); - serviceConfig.setRef(dubboMetadataConfigService); - serviceConfig.setApplication(applicationConfig); - serviceConfig.setProtocol(protocolConfigSupplier.get()); - - serviceConfig.export(); - - if (logger.isInfoEnabled()) { - logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString()); - } - } - - private void unexportDubboMetadataConfigService() { - - if (serviceConfig == null || serviceConfig.isUnexported()) { - return; - } - - serviceConfig.unexport(); - - if (logger.isInfoEnabled()) { - logger.info("The Dubbo service[{}] has been unexported.", serviceConfig.toString()); - } - } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java similarity index 91% rename from spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java rename to spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java index 72ac16b0..ca05d837 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/ServiceRegistryAspect.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java @@ -27,12 +27,14 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; /** - * {@link ServiceRegistry} Aspect + * Dubbo Service Registration Event-Publishing Aspect * * @author Mercy + * @see ServiceInstancePreRegisteredEvent + * @see ServiceInstanceRegisteredEvent */ @Aspect -public class ServiceRegistryAspect implements ApplicationEventPublisherAware { +public class DubboServiceRegistrationEventPublishingAspect implements ApplicationEventPublisherAware { /** * The pointcut expression for {@link ServiceRegistry#register(Registration)} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/DubboRegistryServiceIdHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/DubboRegistryServiceIdHandler.java deleted file mode 100644 index 15a35029..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/DubboRegistryServiceIdHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry.handler; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.registry.Registry; -import org.springframework.context.ConfigurableApplicationContext; - -/** - * Dubbo {@link Registry} Spring Cloud Service Id Builder - * - * @author Mercy - */ -public interface DubboRegistryServiceIdHandler { - - /** - * Supports the specified id of Spring Cloud Service or not - * - * @param serviceId the specified id of Spring Cloud Service - * @return if supports, return true, or false - */ - boolean supports(String serviceId); - - /** - * Creates the id of Spring Cloud Service - * - * @param url The Dubbo's {@link URL} - * @return non-null - */ - String createServiceId(URL url); - - /** - * The instance if {@link ConfigurableApplicationContext} . - * - * @return non-null - */ - ConfigurableApplicationContext getContext(); - -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/StandardDubboRegistryServiceIdHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/StandardDubboRegistryServiceIdHandler.java deleted file mode 100644 index caaa0706..00000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/handler/StandardDubboRegistryServiceIdHandler.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cloud.alibaba.dubbo.registry.handler; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.URL; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.util.StringUtils; - -import java.util.Objects; - -import static java.lang.System.getProperty; -import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; -import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; -import static org.springframework.util.StringUtils.startsWithIgnoreCase; - -/** - * The Standard {@link DubboRegistryServiceIdHandler} - *

- * The service ID pattern is "${category}:${interface}:${version}:${group}" - * - * @author Mercy - */ -public class StandardDubboRegistryServiceIdHandler implements DubboRegistryServiceIdHandler { - - /** - * The separator for service name that could be changed by the Java Property "dubbo.service.name.separator". - */ - protected static final String SERVICE_NAME_SEPARATOR = getProperty("dubbo.service.name.separator", ":"); - - private final ConfigurableApplicationContext context; - - public StandardDubboRegistryServiceIdHandler(ConfigurableApplicationContext context) { - this.context = context; - } - - @Override - public boolean supports(String serviceId) { - return startsWithIgnoreCase(serviceId, PROVIDERS_CATEGORY) || - startsWithIgnoreCase(serviceId, CONSUMERS_CATEGORY); - } - - @Override - public String createServiceId(URL url) { - String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); - if (!Objects.equals(category, PROVIDERS_CATEGORY) && !Objects.equals(category, CONSUMERS_CATEGORY)) { - category = PROVIDERS_CATEGORY; - } - return createServiceId(url, category); - } - - @Override - public ConfigurableApplicationContext getContext() { - return context; - } - - /** - * This method maybe override by sub-class. - * - * @param url The Dubbo's {@link URL} - * @param category The category - * @return - */ - protected String createServiceId(URL url, String category) { - StringBuilder serviceNameBuilder = new StringBuilder(category); - appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); - appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); - appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY); - return serviceNameBuilder.toString(); - } - - private static void appendIfPresent(StringBuilder target, URL url, String parameterName) { - String parameterValue = url.getParameter(parameterName); - appendIfPresent(target, parameterValue); - } - - private static void appendIfPresent(StringBuilder target, String parameterValue) { - if (StringUtils.hasText(parameterValue)) { - target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); - } - } -} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataConfigServiceExporter.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataConfigServiceExporter.java new file mode 100644 index 00000000..a47d1895 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataConfigServiceExporter.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ServiceConfig; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.function.Supplier; + +/** + * {@link DubboMetadataConfigService} exporter + * + * @author Mercy + */ +@Component +public class DubboMetadataConfigServiceExporter { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ApplicationConfig applicationConfig; + + @Autowired + private PublishingDubboMetadataConfigService dubboMetadataConfigService; + + @Autowired + private Supplier protocolConfigSupplier; + + @Value("${spring.application.name:application}") + private String currentApplicationName; + + /** + * The ServiceConfig of DubboMetadataConfigService to be exported, can be nullable. + */ + private ServiceConfig serviceConfig; + + /** + * export {@link DubboMetadataConfigService} as Dubbo service + */ + public void export() { + + if (serviceConfig != null && serviceConfig.isExported()) { + return; + } + + if (StringUtils.isEmpty(dubboMetadataConfigService.getServiceRestMetadata())) { + // If there is no REST metadata, DubboMetadataConfigService will not be exported. + if (logger.isInfoEnabled()) { + logger.info("There is no REST metadata, the Dubbo service[{}] will not be exported.", + dubboMetadataConfigService.getClass().getName()); + } + return; + } + + serviceConfig = new ServiceConfig<>(); + + serviceConfig.setInterface(DubboMetadataConfigService.class); + // Use current Spring application name as the Dubbo Service version + serviceConfig.setVersion(currentApplicationName); + serviceConfig.setRef(dubboMetadataConfigService); + serviceConfig.setApplication(applicationConfig); + serviceConfig.setProtocol(protocolConfigSupplier.get()); + + serviceConfig.export(); + + if (logger.isInfoEnabled()) { + logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString()); + } + } + + + /** + * unexport {@link DubboMetadataConfigService} + */ + public void unexport() { + + if (serviceConfig == null || serviceConfig.isUnexported()) { + return; + } + + serviceConfig.unexport(); + + if (logger.isInfoEnabled()) { + logger.info("The Dubbo service[{}] has been unexported.", serviceConfig.toString()); + } + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index 951a6362..572cee86 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -1,7 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ - org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataEventHandlingAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration From ee91dfa9f53828381a445da9050bfcc38e87ade0 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 28 Mar 2019 22:13:07 +0800 Subject: [PATCH 3/9] Optimize modular implementation --- .../DubboMetadataAutoConfiguration.java | 15 ++- ...oServiceRegistrationAutoConfiguration.java | 121 ++++++++++-------- 2 files changed, 82 insertions(+), 54 deletions(-) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index 2716510b..2264e98b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -30,6 +30,7 @@ import org.springframework.cloud.alibaba.dubbo.metadata.DubboProtocolConfigSuppl import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; +import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceExporter; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy; @@ -90,12 +91,18 @@ public class DubboMetadataAutoConfiguration { publishServiceRestMetadata(serviceBean); } - private void publishServiceRestMetadata(ServiceBean serviceBean) { - dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); + /** + * On Dubbo Service registering in Spring Cloud Registry + */ + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered() { + dubboMetadataConfigServiceExporter.export(); } @EventListener(ApplicationReadyEvent.class) public void onApplicationReady() { + // Maybe invoke again if used Spring Cloud Registry, + // but don't worry. dubboMetadataConfigServiceExporter.export(); } @@ -108,4 +115,8 @@ public class DubboMetadataAutoConfiguration { public void onContextClosed() { dubboMetadataConfigServiceExporter.unexport(); } + + private void publishServiceRestMetadata(ServiceBean serviceBean) { + dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index e6c2432a..8fe92e9f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -23,19 +23,19 @@ import com.ecwid.consul.v1.agent.model.NewService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; -import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceExporter; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; -import org.springframework.context.ApplicationListener; -import org.springframework.context.annotation.Bean; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; @@ -47,6 +47,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; +import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.DUBBO_URLS_METADATA_PROPERTY_NAME; /** @@ -57,75 +59,87 @@ import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegist @Configuration @Import({DubboServiceRegistrationEventPublishingAspect.class}) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) +@AutoConfigureAfter(name = { + EUREKA_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_AUTO_CONFIGURATION_CLASS_NAME, + "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" +}, value = { + DubboMetadataAutoConfiguration.class +}) public class DubboServiceRegistrationAutoConfiguration { - private static final String CONSUL_REGISTRATION_CLASS_NAME = + public static final String EUREKA_AUTO_CONFIGURATION_CLASS_NAME = + "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"; + + public static final String CONSUL_AUTO_CONFIGURATION_CLASS_NAME = + "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; + + private static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; - private static final String EUREKA_REGISTRATION_CLASS_NAME = - "org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration"; - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private ServiceRegistry serviceRegistry; + private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class); @Autowired private DubboServiceMetadataRepository dubboServiceMetadataRepository; - @Autowired - private DubboMetadataConfigServiceExporter dubboMetadataConfigServiceExporter; - @Autowired private JSONUtils jsonUtils; - private Registration registration; - - @ConditionalOnClass(name = EUREKA_REGISTRATION_CLASS_NAME) - @Bean - public ApplicationListener onServiceBeanExportedInEureka() { - return event -> { - reRegister(); - }; - } - - private void reRegister() { - Registration registration = this.registration; - if (registration == null) { - return; - } - serviceRegistry.register(registration); - } - - - // Event-Handling @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - - dubboMetadataConfigServiceExporter.export(); - Registration registration = event.getSource(); attachURLsIntoMetadata(registration); - setRegistration(registration); } - private void setRegistration(Registration registration) { - this.registration = registration; + @Configuration + @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) + @AutoConfigureOrder + static class EurekaConfiguration { + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private ServiceRegistry serviceRegistry; + + private volatile Registration registration; + + + @EventListener(ServiceBeanExportedEvent.class) + public void onServiceBeanExported() { + reRegister(); + } + + private void reRegister() { + if (registration == null) { + return; + } + serviceRegistry.register(registration); + } + + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + registration = event.getSource(); + } + } - /** - * Handle the pre-registered event of {@link ServiceInstance} for Consul - * - * @return ApplicationListener - */ - @ConditionalOnClass(name = CONSUL_REGISTRATION_CLASS_NAME) - @Bean - public ApplicationListener onServiceInstancePreRegisteredInConsul() { - return event -> { + @Configuration + @ConditionalOnBean(name = CONSUL_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(); String registrationClassName = registration.getClass().getName(); - if (CONSUL_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { + if (CONSUL_AUTO_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { NewService newService = ((ConsulRegistration) registration).getService(); String dubboURLsJson = getDubboURLsJSON(); if (StringUtils.hasText(dubboURLsJson)) { @@ -133,7 +147,8 @@ public class DubboServiceRegistrationAutoConfiguration { tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson); } } - }; + } + } private void attachURLsIntoMetadata(Registration registration) { @@ -157,4 +172,6 @@ public class DubboServiceRegistrationAutoConfiguration { } return jsonUtils.toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toList())); } + + } From ba569af8bc57706c45eb1ffbaa3267500513c8e3 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 29 Mar 2019 00:59:15 +0800 Subject: [PATCH 4/9] Remove non-web Nacos application registration --- .../NacosDiscoveryAutoConfiguration.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java index 97e04060..6e6c2008 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -16,12 +16,10 @@ package org.springframework.cloud.alibaba.nacos; -import org.springframework.boot.ApplicationRunner; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.alibaba.nacos.discovery.NacosDiscoveryClientAutoConfiguration; @@ -77,26 +75,4 @@ public class NacosDiscoveryAutoConfiguration { return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); } - - @Bean - @ConditionalOnBean(NacosAutoServiceRegistration.class) // NacosAutoServiceRegistration - // should be present - @ConditionalOnNotWebApplication // Not Web Application - public ApplicationRunner applicationRunner( - NacosAutoServiceRegistration nacosAutoServiceRegistration) { - return args -> { - // WebServerInitializedEvent should not be multicast in Non-Web environment. - // Whatever, NacosAutoServiceRegistration must be checked it's running or not. - if (!nacosAutoServiceRegistration.isRunning()) { // If it's not running, let - // it start. - // FIXME: Please make sure "spring.cloud.nacos.discovery.port" must be - // configured on an available port, - // or the startup or Nacos health check will be failed. - nacosAutoServiceRegistration.start(); - // NacosAutoServiceRegistration will be stopped after its destroy() method - // is invoked. - // @PreDestroy destroy() -> stop() - } - }; - } } \ No newline at end of file From 8218c9d38b6c692e0f29f1e47a8e411349b132c2 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 29 Mar 2019 19:58:00 +0800 Subject: [PATCH 5/9] Optimize --- spring-cloud-alibaba-dubbo/pom.xml | 2 +- .../DubboMetadataAutoConfiguration.java | 2 +- ...oServiceRegistrationAutoConfiguration.java | 60 ++++--- ...ionNonWebApplicationAutoConfiguration.java | 156 ++++++++++++++++++ .../metadata/DubboProtocolConfigSupplier.java | 7 +- ...viceRegistrationEventPublishingAspect.java | 2 +- .../main/resources/META-INF/spring.factories | 1 + .../DubboSpringCloudConsumerBootstrap.java | 5 +- .../src/main/resources/application.yaml | 2 +- .../pom.xml | 7 + .../DubboSpringCloudProviderBootstrap.java | 2 + 11 files changed, 211 insertions(+), 35 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml index 9d4ce799..df606fd6 100644 --- a/spring-cloud-alibaba-dubbo/pom.xml +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -14,7 +14,7 @@ Spring Cloud Alibaba Dubbo - 2.7.0 + 2.7.1 2.1.0.RELEASE 2.1.0.RELEASE 4.0.1 diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index 2264e98b..7eff2f81 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -73,7 +73,7 @@ public class DubboMetadataAutoConfiguration { } @Bean - public Supplier dubboProtocolConfigSupplier(Collection protocols) { + public Supplier dubboProtocolConfigSupplier(ObjectProvider> protocols) { return new DubboProtocolConfigSupplier(protocols); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index 8fe92e9f..c926fd6b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -17,16 +17,20 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import org.apache.dubbo.common.URL; -import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; 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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; @@ -35,7 +39,6 @@ import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; @@ -49,6 +52,7 @@ import java.util.stream.Collectors; import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; +import static org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect.REGISTER_POINTCUT_EXPRESSION; import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.DUBBO_URLS_METADATA_PROPERTY_NAME; /** @@ -74,7 +78,7 @@ public class DubboServiceRegistrationAutoConfiguration { public static final String CONSUL_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; - private static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME = + public static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class); @@ -95,32 +99,29 @@ public class DubboServiceRegistrationAutoConfiguration { @Configuration @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) @AutoConfigureOrder - static class EurekaConfiguration { - - @Autowired - private ApplicationContext applicationContext; + @Aspect + class EurekaConfiguration { @Autowired private ServiceRegistry serviceRegistry; - private volatile Registration registration; + private Registration registration; + private boolean deferredRegistration = true; - @EventListener(ServiceBeanExportedEvent.class) - public void onServiceBeanExported() { - reRegister(); - } - - private void reRegister() { - if (registration == null) { - return; + @Around(REGISTER_POINTCUT_EXPRESSION) + public Object doRegister(ProceedingJoinPoint pjp, Registration registration) throws Throwable { + this.registration = registration; + if (deferredRegistration) { + return null; } - serviceRegistry.register(registration); + return pjp.proceed(pjp.getArgs()); } - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - registration = event.getSource(); + @EventListener(ApplicationStartedEvent.class) + public void onApplicationStarted() { + deferredRegistration = false; + serviceRegistry.register(registration); } } @@ -138,17 +139,22 @@ public class DubboServiceRegistrationAutoConfiguration { @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { Registration registration = event.getSource(); - String registrationClassName = registration.getClass().getName(); + Class registrationClass = AopUtils.getTargetClass(registration); + String registrationClassName = registrationClass.getName(); if (CONSUL_AUTO_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { - NewService newService = ((ConsulRegistration) registration).getService(); - String dubboURLsJson = getDubboURLsJSON(); - if (StringUtils.hasText(dubboURLsJson)) { - List tags = newService.getTags(); - tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson); - } + ConsulRegistration consulRegistration = (ConsulRegistration) registration; + attachURLsIntoMetadata(consulRegistration); } } + private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) { + NewService newService = consulRegistration.getService(); + String dubboURLsJson = getDubboURLsJSON(); + if (StringUtils.hasText(dubboURLsJson)) { + List tags = newService.getTags(); + tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson); + } + } } private void attachURLsIntoMetadata(Registration registration) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java new file mode 100644 index 00000000..3f69e7ad --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.spring.ServiceBean; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; + +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; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration; +import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; +import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import java.util.List; + +import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; +import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; + +/** + * Dubbo Service Registration Auto-{@link Configuration} for Non-Web application + * + * @author Mercy + */ +@Configuration +@ConditionalOnNotWebApplication +@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) +@AutoConfigureAfter(DubboServiceRegistrationAutoConfiguration.class) +@Aspect +public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { + + @Autowired + private ServiceRegistry serviceRegistry; + + @Autowired + private Registration registration; + + private volatile Integer webPort = null; + + private volatile boolean registered = false; + + @Around("execution(* org.springframework.cloud.client.serviceregistry.Registration.getPort())") + public Object getPort(ProceedingJoinPoint pjp) throws Throwable { + return webPort != null ? webPort : pjp.proceed(); + } + + @EventListener(ServiceBeanExportedEvent.class) + public void onServiceBeanExported(ServiceBeanExportedEvent event) { + setWebPort(event.getServiceBean()); + 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. + * + * @param serviceBean {@link ServiceBean} + */ + private void setWebPort(ServiceBean serviceBean) { + if (webPort == null) { + List urls = serviceBean.getExportedUrls(); + urls.stream() + .filter(url -> "rest".equalsIgnoreCase(url.getProtocol())) + .findFirst() + .ifPresent(url -> { + webPort = url.getPort(); + }); + } + } + + @Configuration + @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) + @AutoConfigureOrder + static class EurekaConfiguration { + + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + setPort(event.getSource()); + } + + private void setPort(Registration registration) { + EurekaRegistration eurekaRegistration = (EurekaRegistration) registration; + CloudEurekaInstanceConfig cloudEurekaInstanceConfig = eurekaRegistration.getInstanceConfig(); + cloudEurekaInstanceConfig.setNonSecurePort(registration.getPort()); + } + + } + + @Configuration + @ConditionalOnBean(name = CONSUL_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(); + 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); + } + } + } + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboProtocolConfigSupplier.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboProtocolConfigSupplier.java index 5eb3adfb..d5d99430 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboProtocolConfigSupplier.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/DubboProtocolConfigSupplier.java @@ -18,6 +18,8 @@ package org.springframework.cloud.alibaba.dubbo.metadata; import org.apache.dubbo.config.ProtocolConfig; +import org.springframework.beans.factory.ObjectProvider; + import java.util.Collection; import java.util.Iterator; import java.util.function.Supplier; @@ -31,15 +33,16 @@ import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL; */ public class DubboProtocolConfigSupplier implements Supplier { - private final Collection protocols; + private final ObjectProvider> protocols; - public DubboProtocolConfigSupplier(Collection protocols) { + public DubboProtocolConfigSupplier(ObjectProvider> protocols) { this.protocols = protocols; } @Override public ProtocolConfig get() { ProtocolConfig protocolConfig = null; + Collection protocols = this.protocols.getIfAvailable(); for (ProtocolConfig protocol : protocols) { String protocolName = protocol.getName(); if (DEFAULT_PROTOCOL.equals(protocolName)) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java index ca05d837..17826624 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java @@ -39,7 +39,7 @@ public class DubboServiceRegistrationEventPublishingAspect implements Applicatio /** * The pointcut expression for {@link ServiceRegistry#register(Registration)} */ - private static final String REGISTER_POINTCUT_EXPRESSION = + public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && args(registration)"; private ApplicationEventPublisher applicationEventPublisher; diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index 572cee86..6f0ffd96 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -2,6 +2,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudConsumerBootstrap.java b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudConsumerBootstrap.java index 8c2a0c9e..2e389ce2 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudConsumerBootstrap.java +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudConsumerBootstrap.java @@ -17,6 +17,7 @@ package org.springframework.cloud.alibaba.dubbo.bootstrap; import org.apache.dubbo.config.annotation.Reference; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.ApplicationRunner; @@ -52,7 +53,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; @EnableFeignClients public class DubboSpringCloudConsumerBootstrap { - @Reference(version = "1.0.0") + @Reference(version = "1.0.0", protocol = "dubbo") private RestService restService; @Autowired @@ -94,7 +95,7 @@ public class DubboSpringCloudConsumerBootstrap { } @FeignClient("${provider.application.name}") - @DubboTransported() + @DubboTransported(protocol = "dubbo") public interface DubboFeignRestService { @GetMapping(value = "/param") diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/resources/application.yaml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/resources/application.yaml index 263a5699..41c67146 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/resources/application.yaml +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-consumer-sample/src/main/resources/application.yaml @@ -9,4 +9,4 @@ server: provider: application: - name: spring-cloud-alibaba-dubbo-web-provider \ No newline at end of file + name: spring-cloud-alibaba-dubbo-provider \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/pom.xml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/pom.xml index 68832a50..9c43a453 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/pom.xml +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/pom.xml @@ -17,6 +17,13 @@ + + + javax.servlet + javax.servlet-api + 3.1.0 + + org.springframework diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudProviderBootstrap.java b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudProviderBootstrap.java index 4606a190..8e6ed4e9 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudProviderBootstrap.java +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudProviderBootstrap.java @@ -16,6 +16,7 @@ */ package org.springframework.cloud.alibaba.dubbo.bootstrap; +import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @@ -30,6 +31,7 @@ public class DubboSpringCloudProviderBootstrap { public static void main(String[] args) { new SpringApplicationBuilder(DubboSpringCloudProviderBootstrap.class) .properties("spring.profiles.active=nacos") + .web(WebApplicationType.NONE) .run(args); } } From a50324c43ab66c47c83f4ff21dcf5ad4f04c5a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=A9=AC=E5=93=A5?= Date: Fri, 29 Mar 2019 20:08:50 +0800 Subject: [PATCH 6/9] To add Gateway demo --- .../pom.xml | 1 + .../pom.xml | 39 ++++ ...bboSpringCloudServletGatewayBootstrap.java | 23 +++ .../dubbo/gateway/DubboGatewayServlet.java | 188 ++++++++++++++++++ .../src/main/resources/application.yaml | 12 ++ .../src/main/resources/bootstrap.yaml | 70 +++++++ 6 files changed, 333 insertions(+) create mode 100644 spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/pom.xml create mode 100644 spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudServletGatewayBootstrap.java create mode 100644 spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java create mode 100644 spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/application.yaml create mode 100644 spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/bootstrap.yaml diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/pom.xml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/pom.xml index 6a96eb0d..b393fddb 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/pom.xml +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/pom.xml @@ -20,6 +20,7 @@ spring-cloud-dubbo-provider-sample spring-cloud-dubbo-consumer-sample spring-cloud-dubbo-provider-web-sample + spring-cloud-dubbo-servlet-gateway-sample diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/pom.xml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/pom.xml new file mode 100644 index 00000000..75b6d18e --- /dev/null +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/pom.xml @@ -0,0 +1,39 @@ + + + + spring-cloud-alibaba-dubbo-examples + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../pom.xml + + 4.0.0 + + org.springframework.cloud + spring-cloud-dubbo-servlet-gateway-sample + Spring Cloud Dubbo Servlet Gateway Sample + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-dubbo-sample-api + ${project.version} + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudServletGatewayBootstrap.java b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudServletGatewayBootstrap.java new file mode 100644 index 00000000..0ad4d68e --- /dev/null +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudServletGatewayBootstrap.java @@ -0,0 +1,23 @@ +package org.springframework.cloud.alibaba.dubbo.bootstrap; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +/** + * Dubbo Spring Cloud Servlet Gateway Bootstrap + */ +@EnableDiscoveryClient +@EnableAutoConfiguration +@EnableFeignClients +@ServletComponentScan(basePackages = "org.springframework.cloud.alibaba.dubbo.gateway") +public class DubboSpringCloudServletGatewayBootstrap { + + public static void main(String[] args) { + new SpringApplicationBuilder(DubboSpringCloudServletGatewayBootstrap.class) + .properties("spring.profiles.active=nacos") + .run(args); + } +} diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java new file mode 100644 index 00000000..46fcf5e2 --- /dev/null +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java @@ -0,0 +1,188 @@ +package org.springframework.cloud.alibaba.dubbo.gateway; + +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.rpc.service.GenericException; +import org.apache.dubbo.rpc.service.GenericService; +import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest; +import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.CollectionUtils; +import org.springframework.util.PathMatcher; +import org.springframework.util.StreamUtils; +import org.springframework.web.util.UriComponents; + +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +import static org.springframework.web.util.UriComponentsBuilder.fromUriString; + +@WebServlet(urlPatterns = "/dsc/*") +public class DubboGatewayServlet extends HttpServlet { + + private final DubboServiceMetadataRepository repository; + + private final DubboTransportedMetadata dubboTransportedMetadata; + + private final DubboGenericServiceFactory serviceFactory; + + private final DubboGenericServiceExecutionContextFactory contextFactory; + + private final PathMatcher pathMatcher = new AntPathMatcher(); + + public DubboGatewayServlet(DubboServiceMetadataRepository repository, + DubboGenericServiceFactory serviceFactory, + DubboGenericServiceExecutionContextFactory contextFactory) { + this.repository = repository; + this.dubboTransportedMetadata = new DubboTransportedMetadata(); + dubboTransportedMetadata.setProtocol("dubbo"); + dubboTransportedMetadata.setCluster("failover"); + this.serviceFactory = serviceFactory; + this.contextFactory = contextFactory; + } + + public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + + // /g/{app-name}/{rest-path} + String requestURI = request.getRequestURI(); + // /g/ + String servletPath = request.getServletPath(); + + String part = StringUtils.substringAfter(requestURI, servletPath); + + String serviceName = StringUtils.substringBetween(part, "/", "/"); + + // App name= spring-cloud-alibaba-dubbo-web-provider (127.0.0.1:8080) + + String restPath = StringUtils.substringAfter(part, serviceName); + + // 初始化 serviceName 的 REST 请求元数据 + repository.initialize(serviceName); + // 将 HttpServletRequest 转化为 RequestMetadata + RequestMetadata clientMetadata = buildRequestMetadata(request, restPath); + + DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, clientMetadata); + + if (dubboServiceMetadata == null) { + // if DubboServiceMetadata is not found, executes next + throw new ServletException("DubboServiceMetadata can't be found!"); + } + + RestMethodMetadata dubboRestMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); + + GenericService genericService = serviceFactory.create(dubboServiceMetadata, dubboTransportedMetadata); + + // TODO: Get the Request Body from HttpServletRequest + byte[] body = getRequestBody(request); + + MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(new HttpRequestAdapter(request), body); + +// customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata); + + DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, httpServerRequest); + + Object result = null; + GenericException exception = null; + + try { + result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters()); + } catch (GenericException e) { + exception = e; + } + response.getWriter().println(result); + } + + private byte[] getRequestBody(HttpServletRequest request) throws IOException { + ServletInputStream inputStream = request.getInputStream(); + return StreamUtils.copyToByteArray(inputStream); + } + + private static class HttpRequestAdapter implements HttpRequest { + + private final HttpServletRequest request; + + private HttpRequestAdapter(HttpServletRequest request) { + this.request = request; + } + + @Override + public String getMethodValue() { + return request.getMethod(); + } + + @Override + public URI getURI() { + try { + return new URI(request.getRequestURL().toString() + "?" + request.getQueryString()); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + throw new RuntimeException(); + } + + @Override + public HttpHeaders getHeaders() { + return new HttpHeaders(); + } + } + +// protected void customizeRequest(MutableHttpServerRequest httpServerRequest, +// RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) { +// +// RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest(); +// String pathPattern = dubboRequestMetadata.getPath(); +// +// Map pathVariables = pathMatcher.extractUriTemplateVariables(pathPattern, httpServerRequest.getPath()); +// +// if (!CollectionUtils.isEmpty(pathVariables)) { +// // Put path variables Map into query parameters Map +// httpServerRequest.params(pathVariables); +// } +// +// } + + private RequestMetadata buildRequestMetadata(HttpServletRequest request, String restPath) { + UriComponents uriComponents = fromUriString(request.getRequestURI()).build(true); + RequestMetadata requestMetadata = new RequestMetadata(); + requestMetadata.setPath(restPath); + requestMetadata.setMethod(request.getMethod()); + requestMetadata.setParams(getParams(request)); + requestMetadata.setHeaders(getHeaders(request)); + return requestMetadata; + } + + private Map> getHeaders(HttpServletRequest request) { + Map> map = new LinkedHashMap<>(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + Enumeration headerValues = request.getHeaders(headerName); + map.put(headerName, Collections.list(headerValues)); + } + return map; + } + + private Map> getParams(HttpServletRequest request) { + Map> map = new LinkedHashMap<>(); + for (Map.Entry entry : request.getParameterMap().entrySet()) { + map.put(entry.getKey(), Arrays.asList(entry.getValue())); + } + return map; + } +} diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/application.yaml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/application.yaml new file mode 100644 index 00000000..263a5699 --- /dev/null +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/application.yaml @@ -0,0 +1,12 @@ +dubbo: + registry: + # The Spring Cloud Dubbo's registry extension + address: spring-cloud://localhost +# The traditional Dubbo's registry +# address: zookeeper://127.0.0.1:2181 +server: + port: 0 + +provider: + application: + name: spring-cloud-alibaba-dubbo-web-provider \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/bootstrap.yaml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/bootstrap.yaml new file mode 100644 index 00000000..a86acd15 --- /dev/null +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/resources/bootstrap.yaml @@ -0,0 +1,70 @@ +spring: + application: + name: spring-cloud-alibaba-dubbo-servlet-gateway + main: + allow-bean-definition-overriding: true + + + # default disable all + cloud: + nacos: + discovery: + enabled: false + register-enabled: false + zookeeper: + enabled: false + consul: + enabled: false + +eureka: + client: + enabled: false + +ribbon: + nacos: + enabled: false + +--- +spring: + profiles: nacos + + cloud: + nacos: + discovery: + enabled: true + register-enabled: true + server-addr: 127.0.0.1:8848 + +ribbon: + nacos: + enabled: true + +--- +spring: + profiles: eureka + +eureka: + client: + enabled: true + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ + + +--- +spring: + profiles: zookeeper + cloud: + zookeeper: + enabled: true + connect-string: 127.0.0.1:2181 + + +--- +spring: + profiles: consul + + cloud: + consul: + enabled: true + host: 127.0.0.1 + port: 8500 \ No newline at end of file From 5c291eef163b3cb50e82e7e43f8d72d665567ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=A9=AC=E5=93=A5?= Date: Fri, 29 Mar 2019 20:16:15 +0800 Subject: [PATCH 7/9] Add Spring Boot version --- spring-cloud-alibaba-dubbo/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml index df606fd6..c3146471 100644 --- a/spring-cloud-alibaba-dubbo/pom.xml +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -15,6 +15,7 @@ 2.7.1 + 2.7.0 2.1.0.RELEASE 2.1.0.RELEASE 4.0.1 @@ -178,7 +179,7 @@ org.apache.dubbo dubbo-spring-boot-starter - ${dubbo.version} + ${dubbo-spring-boot.version} From cda6d4ac6a982e95f24c40ea9e3e7a3662df5d2b Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 1 Apr 2019 10:30:59 +0800 Subject: [PATCH 8/9] Polish spring-cloud-incubator/spring-cloud-alibaba#509 : Random port Dubbo Spring Cloud Provider registration issue --- .../src/main/resources/application.yaml | 2 +- .../src/main/resources/bootstrap.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml index 786da0f2..a890294c 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/application.yaml @@ -16,4 +16,4 @@ feign: enabled: true server: - port: 0 \ No newline at end of file + port: 8080 \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/bootstrap.yaml b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/bootstrap.yaml index fd82247b..0d8dfca9 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/bootstrap.yaml +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-provider-web-sample/src/main/resources/bootstrap.yaml @@ -1,6 +1,6 @@ spring: application: - name: spring-cloud-alibaba-dubbo-web-provider + name: spring-cloud-alibaba-dubbo-provider main: allow-bean-definition-overriding: true From 4b111e4e467449a8557666c0e0ce863e81196703 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 2 Apr 2019 01:45:53 +0800 Subject: [PATCH 9/9] Polish spring-cloud-incubator/spring-cloud-alibaba#510 : Dubbo Spring Cloud Non-Web Provider Registration issue --- .../DubboMetadataAutoConfiguration.java | 28 +- ...oServiceRegistrationAutoConfiguration.java | 68 ++-- ...ionNonWebApplicationAutoConfiguration.java | 33 +- .../dubbo/registry/SpringCloudRegistry.java | 4 +- ...ebApplicationEnvironmentPostProcessor.java | 199 ++++++++++ .../main/resources/META-INF/spring.factories | 7 +- .../dubbo/gateway/DubboGatewayServlet.java | 364 +++++++++--------- 7 files changed, 455 insertions(+), 248 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/env/DubboNonWebApplicationEnvironmentPostProcessor.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index 7eff2f81..94184b4b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -25,12 +25,10 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.event.ApplicationFailedEvent; -import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.alibaba.dubbo.metadata.DubboProtocolConfigSupplier; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver; import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver; -import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceExporter; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy; @@ -89,26 +87,12 @@ public class DubboMetadataAutoConfiguration { public void onServiceBeanExported(ServiceBeanExportedEvent event) { ServiceBean serviceBean = event.getServiceBean(); publishServiceRestMetadata(serviceBean); - } - - /** - * On Dubbo Service registering in Spring Cloud Registry - */ - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered() { - dubboMetadataConfigServiceExporter.export(); - } - - @EventListener(ApplicationReadyEvent.class) - public void onApplicationReady() { - // Maybe invoke again if used Spring Cloud Registry, - // but don't worry. - dubboMetadataConfigServiceExporter.export(); + exportDubboMetadataConfigService(); } @EventListener(ApplicationFailedEvent.class) public void onApplicationFailed() { - dubboMetadataConfigServiceExporter.unexport(); + unExportDubboMetadataConfigService(); } @EventListener(ContextClosedEvent.class) @@ -119,4 +103,12 @@ public class DubboMetadataAutoConfiguration { private void publishServiceRestMetadata(ServiceBean serviceBean) { dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); } + + private void exportDubboMetadataConfigService() { + dubboMetadataConfigServiceExporter.export(); + } + + private void unExportDubboMetadataConfigService() { + dubboMetadataConfigServiceExporter.unexport(); + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index c926fd6b..081e5b6e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -17,28 +17,32 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure; import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.spring.ServiceBean; import com.ecwid.consul.v1.agent.model.NewService; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; +import com.netflix.appinfo.InstanceInfo; import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; +import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry; +import org.springframework.context.SmartLifecycle; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; @@ -52,8 +56,8 @@ import java.util.stream.Collectors; import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; -import static org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect.REGISTER_POINTCUT_EXPRESSION; import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.DUBBO_URLS_METADATA_PROPERTY_NAME; +import static org.springframework.util.ObjectUtils.isEmpty; /** * Dubbo Service Registration Auto-{@link Configuration} @@ -81,6 +85,9 @@ public class DubboServiceRegistrationAutoConfiguration { public static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; + public static final String ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME = + "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration"; + private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class); @Autowired @@ -89,7 +96,6 @@ public class DubboServiceRegistrationAutoConfiguration { @Autowired private JSONUtils jsonUtils; - @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { Registration registration = event.getSource(); @@ -98,32 +104,32 @@ public class DubboServiceRegistrationAutoConfiguration { @Configuration @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) - @AutoConfigureOrder @Aspect - class EurekaConfiguration { + class EurekaConfiguration implements SmartInitializingSingleton { @Autowired - private ServiceRegistry serviceRegistry; + private ObjectProvider> serviceBeans; - private Registration registration; + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration); + InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo(); + attachURLsIntoMetadata(instanceInfo.getMetadata()); + } - private boolean deferredRegistration = true; - - @Around(REGISTER_POINTCUT_EXPRESSION) - public Object doRegister(ProceedingJoinPoint pjp, Registration registration) throws Throwable { - this.registration = registration; - if (deferredRegistration) { - return null; + /** + * {@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); } - return pjp.proceed(pjp.getArgs()); } - - @EventListener(ApplicationStartedEvent.class) - public void onApplicationStarted() { - deferredRegistration = false; - serviceRegistry.register(registration); - } - } @Configuration @@ -161,7 +167,13 @@ public class DubboServiceRegistrationAutoConfiguration { if (registration == null) { return; } - Map metadata = registration.getMetadata(); + synchronized (registration) { + Map metadata = registration.getMetadata(); + attachURLsIntoMetadata(metadata); + } + } + + private void attachURLsIntoMetadata(Map metadata) { String dubboURLsJson = getDubboURLsJSON(); if (StringUtils.hasText(dubboURLsJson)) { metadata.put(DUBBO_URLS_METADATA_PROPERTY_NAME, dubboURLsJson); @@ -178,6 +190,4 @@ public class DubboServiceRegistrationAutoConfiguration { } return jsonUtils.toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toList())); } - - -} +} \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java index 3f69e7ad..15a5190b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java @@ -24,9 +24,9 @@ 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; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -36,15 +36,14 @@ import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; -import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig; -import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; +import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegistration; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; import java.util.List; import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; -import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; +import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME; /** * Dubbo Service Registration Auto-{@link Configuration} for Non-Web application @@ -58,6 +57,8 @@ import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboService @Aspect public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { + private static final String REST_PROTOCOL = "rest"; + @Autowired private ServiceRegistry serviceRegistry; @@ -96,7 +97,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { if (webPort == null) { List urls = serviceBean.getExportedUrls(); urls.stream() - .filter(url -> "rest".equalsIgnoreCase(url.getProtocol())) + .filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol())) .findFirst() .ifPresent(url -> { webPort = url.getPort(); @@ -105,26 +106,26 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) - @AutoConfigureOrder - static class EurekaConfiguration { + @ConditionalOnBean(name = ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME) + class ZookeeperConfiguration implements SmartInitializingSingleton { + + @Autowired + private ServiceInstanceRegistration registration; @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { - setPort(event.getSource()); + registration.setPort(webPort); } - private void setPort(Registration registration) { - EurekaRegistration eurekaRegistration = (EurekaRegistration) registration; - CloudEurekaInstanceConfig cloudEurekaInstanceConfig = eurekaRegistration.getInstanceConfig(); - cloudEurekaInstanceConfig.setNonSecurePort(registration.getPort()); + @Override + public void afterSingletonsInstantiated() { + // invoke getServiceInstance() method to trigger the ServiceInstance building before register + registration.getServiceInstance(); } - } @Configuration @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME) - @AutoConfigureOrder class ConsulConfiguration { /** @@ -153,4 +154,4 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { } } -} +} \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java index d973e629..5fb3d2e4 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -50,12 +50,12 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { /** * The property name of Dubbo {@link URL URLs} metadata */ - public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo-urls"; + public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo.urls"; /** * The parameter name of the services of Dubbo Provider */ - public static final String DUBBO_PROVIDER_SERVICES_PARAM_NAME = "dubbo-provider-services"; + public static final String DUBBO_PROVIDER_SERVICES_PARAM_NAME = "dubbo.provider-services"; /** * All services of Dubbo Provider diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/env/DubboNonWebApplicationEnvironmentPostProcessor.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/env/DubboNonWebApplicationEnvironmentPostProcessor.java new file mode 100644 index 00000000..60faa7c3 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/env/DubboNonWebApplicationEnvironmentPostProcessor.java @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry.env; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL; +import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; + +/** + * 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"; + + private static final String SERVER_PORT_PROPERTY_NAME = "server.port"; + + private static final String PORT_PROPERTY_NAME = "port"; + + private static final String PROTOCOL_PROPERTY_NAME_PREFIX = "dubbo.protocol"; + + private static final String PROTOCOL_NAME_PROPERTY_NAME_SUFFIX = DOT + "name"; + + private static final String PROTOCOL_PORT_PROPERTY_NAME_SUFFIX = DOT + PORT_PROPERTY_NAME; + + 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 = PROTOCOL_PROPERTY_NAME_PREFIX + PROTOCOL_NAME_PROPERTY_NAME_SUFFIX; + + private static final String PROTOCOLS_PROPERTY_NAME_PREFIX = "dubbo.protocols"; + + private static final String REST_PROTOCOL = "rest"; + + private final Logger logger = LoggerFactory.getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class); + + @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; + } + + resetServerPort(environment); + } + + /** + * Reset server port property if it's absent, whose value is configured by "dubbbo.protocol.port" + * or "dubbo.protcols.rest.port" + * + * @param environment + */ + private void resetServerPort(ConfigurableEnvironment environment) { + + 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); + + } + + 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) { + if (serverPort == null) { + return; + } + + MutablePropertySources propertySources = environment.getPropertySources(); + + Map properties = new HashMap<>(); + properties.put(SERVER_PORT_PROPERTY_NAME, String.valueOf(serverPort)); + + addOrReplace(propertySources, properties); + } + + /** + * 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; + } + + private static boolean isRestProtocol(String protocol) { + return REST_PROTOCOL.equalsIgnoreCase(protocol); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index 6f0ffd96..515af6f5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -6,5 +6,10 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration + org.springframework.context.ApplicationContextInitializer=\ - org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer \ No newline at end of file + org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer + + +org.springframework.boot.env.EnvironmentPostProcessor=\ +org.springframework.cloud.alibaba.dubbo.registry.env.DubboNonWebApplicationEnvironmentPostProcessor \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java index 46fcf5e2..0bff5e0c 100644 --- a/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java +++ b/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-servlet-gateway-sample/src/main/java/org/springframework/cloud/alibaba/dubbo/gateway/DubboGatewayServlet.java @@ -1,188 +1,188 @@ -package org.springframework.cloud.alibaba.dubbo.gateway; - -import org.apache.commons.lang.StringUtils; -import org.apache.dubbo.rpc.service.GenericException; -import org.apache.dubbo.rpc.service.GenericService; -import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest; -import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; -import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; -import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext; -import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; -import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpRequest; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.CollectionUtils; -import org.springframework.util.PathMatcher; -import org.springframework.util.StreamUtils; -import org.springframework.web.util.UriComponents; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; - -import static org.springframework.web.util.UriComponentsBuilder.fromUriString; - -@WebServlet(urlPatterns = "/dsc/*") -public class DubboGatewayServlet extends HttpServlet { - - private final DubboServiceMetadataRepository repository; - - private final DubboTransportedMetadata dubboTransportedMetadata; - - private final DubboGenericServiceFactory serviceFactory; - - private final DubboGenericServiceExecutionContextFactory contextFactory; - - private final PathMatcher pathMatcher = new AntPathMatcher(); - - public DubboGatewayServlet(DubboServiceMetadataRepository repository, - DubboGenericServiceFactory serviceFactory, - DubboGenericServiceExecutionContextFactory contextFactory) { - this.repository = repository; - this.dubboTransportedMetadata = new DubboTransportedMetadata(); - dubboTransportedMetadata.setProtocol("dubbo"); - dubboTransportedMetadata.setCluster("failover"); - this.serviceFactory = serviceFactory; - this.contextFactory = contextFactory; - } - - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - - // /g/{app-name}/{rest-path} - String requestURI = request.getRequestURI(); - // /g/ - String servletPath = request.getServletPath(); - - String part = StringUtils.substringAfter(requestURI, servletPath); - - String serviceName = StringUtils.substringBetween(part, "/", "/"); - - // App name= spring-cloud-alibaba-dubbo-web-provider (127.0.0.1:8080) - - String restPath = StringUtils.substringAfter(part, serviceName); - - // 初始化 serviceName 的 REST 请求元数据 - repository.initialize(serviceName); - // 将 HttpServletRequest 转化为 RequestMetadata - RequestMetadata clientMetadata = buildRequestMetadata(request, restPath); - - DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, clientMetadata); - - if (dubboServiceMetadata == null) { - // if DubboServiceMetadata is not found, executes next - throw new ServletException("DubboServiceMetadata can't be found!"); - } - - RestMethodMetadata dubboRestMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); - - GenericService genericService = serviceFactory.create(dubboServiceMetadata, dubboTransportedMetadata); - - // TODO: Get the Request Body from HttpServletRequest - byte[] body = getRequestBody(request); - - MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(new HttpRequestAdapter(request), body); - -// customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata); - - DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, httpServerRequest); - - Object result = null; - GenericException exception = null; - - try { - result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters()); - } catch (GenericException e) { - exception = e; - } - response.getWriter().println(result); - } - - private byte[] getRequestBody(HttpServletRequest request) throws IOException { - ServletInputStream inputStream = request.getInputStream(); - return StreamUtils.copyToByteArray(inputStream); - } - - private static class HttpRequestAdapter implements HttpRequest { - - private final HttpServletRequest request; - - private HttpRequestAdapter(HttpServletRequest request) { - this.request = request; - } - - @Override - public String getMethodValue() { - return request.getMethod(); - } - - @Override - public URI getURI() { - try { - return new URI(request.getRequestURL().toString() + "?" + request.getQueryString()); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - throw new RuntimeException(); - } - - @Override - public HttpHeaders getHeaders() { - return new HttpHeaders(); - } - } - -// protected void customizeRequest(MutableHttpServerRequest httpServerRequest, -// RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) { +//package org.springframework.cloud.alibaba.dubbo.gateway; // -// RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest(); -// String pathPattern = dubboRequestMetadata.getPath(); +//import org.apache.commons.lang.StringUtils; +//import org.apache.dubbo.rpc.service.GenericException; +//import org.apache.dubbo.rpc.service.GenericService; +//import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest; +//import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; +//import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata; +//import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; +//import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; +//import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +//import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext; +//import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; +//import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; +//import org.springframework.http.HttpHeaders; +//import org.springframework.http.HttpRequest; +//import org.springframework.util.AntPathMatcher; +//import org.springframework.util.CollectionUtils; +//import org.springframework.util.PathMatcher; +//import org.springframework.util.StreamUtils; +//import org.springframework.web.util.UriComponents; // -// Map pathVariables = pathMatcher.extractUriTemplateVariables(pathPattern, httpServerRequest.getPath()); +//import javax.servlet.ServletException; +//import javax.servlet.ServletInputStream; +//import javax.servlet.annotation.WebServlet; +//import javax.servlet.http.HttpServlet; +//import javax.servlet.http.HttpServletRequest; +//import javax.servlet.http.HttpServletResponse; +//import java.io.IOException; +//import java.net.URI; +//import java.net.URISyntaxException; +//import java.util.*; // -// if (!CollectionUtils.isEmpty(pathVariables)) { -// // Put path variables Map into query parameters Map -// httpServerRequest.params(pathVariables); +//import static org.springframework.web.util.UriComponentsBuilder.fromUriString; +// +//@WebServlet(urlPatterns = "/dsc/*") +//public class DubboGatewayServlet extends HttpServlet { +// +// private final DubboServiceMetadataRepository repository; +// +// private final DubboTransportedMetadata dubboTransportedMetadata; +// +// private final DubboGenericServiceFactory serviceFactory; +// +// private final DubboGenericServiceExecutionContextFactory contextFactory; +// +// private final PathMatcher pathMatcher = new AntPathMatcher(); +// +// public DubboGatewayServlet(DubboServiceMetadataRepository repository, +// DubboGenericServiceFactory serviceFactory, +// DubboGenericServiceExecutionContextFactory contextFactory) { +// this.repository = repository; +// this.dubboTransportedMetadata = new DubboTransportedMetadata(); +// dubboTransportedMetadata.setProtocol("dubbo"); +// dubboTransportedMetadata.setCluster("failover"); +// this.serviceFactory = serviceFactory; +// this.contextFactory = contextFactory; +// } +// +// public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { +// +// // /g/{app-name}/{rest-path} +// String requestURI = request.getRequestURI(); +// // /g/ +// String servletPath = request.getServletPath(); +// +// String part = StringUtils.substringAfter(requestURI, servletPath); +// +// String serviceName = StringUtils.substringBetween(part, "/", "/"); +// +// // App name= spring-cloud-alibaba-dubbo-web-provider (127.0.0.1:8080) +// +// String restPath = StringUtils.substringAfter(part, serviceName); +// +// // 初始化 serviceName 的 REST 请求元数据 +// repository.initialize(serviceName); +// // 将 HttpServletRequest 转化为 RequestMetadata +// RequestMetadata clientMetadata = buildRequestMetadata(request, restPath); +// +// DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, clientMetadata); +// +// if (dubboServiceMetadata == null) { +// // if DubboServiceMetadata is not found, executes next +// throw new ServletException("DubboServiceMetadata can't be found!"); // } // +// RestMethodMetadata dubboRestMethodMetadata = dubboServiceMetadata.getRestMethodMetadata(); +// +// GenericService genericService = serviceFactory.create(dubboServiceMetadata, dubboTransportedMetadata); +// +// // TODO: Get the Request Body from HttpServletRequest +// byte[] body = getRequestBody(request); +// +// MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(new HttpRequestAdapter(request), body); +// +//// customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata); +// +// DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, httpServerRequest); +// +// Object result = null; +// GenericException exception = null; +// +// try { +// result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters()); +// } catch (GenericException e) { +// exception = e; +// } +// response.getWriter().println(result); // } - - private RequestMetadata buildRequestMetadata(HttpServletRequest request, String restPath) { - UriComponents uriComponents = fromUriString(request.getRequestURI()).build(true); - RequestMetadata requestMetadata = new RequestMetadata(); - requestMetadata.setPath(restPath); - requestMetadata.setMethod(request.getMethod()); - requestMetadata.setParams(getParams(request)); - requestMetadata.setHeaders(getHeaders(request)); - return requestMetadata; - } - - private Map> getHeaders(HttpServletRequest request) { - Map> map = new LinkedHashMap<>(); - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - Enumeration headerValues = request.getHeaders(headerName); - map.put(headerName, Collections.list(headerValues)); - } - return map; - } - - private Map> getParams(HttpServletRequest request) { - Map> map = new LinkedHashMap<>(); - for (Map.Entry entry : request.getParameterMap().entrySet()) { - map.put(entry.getKey(), Arrays.asList(entry.getValue())); - } - return map; - } -} +// +// private byte[] getRequestBody(HttpServletRequest request) throws IOException { +// ServletInputStream inputStream = request.getInputStream(); +// return StreamUtils.copyToByteArray(inputStream); +// } +// +// private static class HttpRequestAdapter implements HttpRequest { +// +// private final HttpServletRequest request; +// +// private HttpRequestAdapter(HttpServletRequest request) { +// this.request = request; +// } +// +// @Override +// public String getMethodValue() { +// return request.getMethod(); +// } +// +// @Override +// public URI getURI() { +// try { +// return new URI(request.getRequestURL().toString() + "?" + request.getQueryString()); +// } catch (URISyntaxException e) { +// e.printStackTrace(); +// } +// throw new RuntimeException(); +// } +// +// @Override +// public HttpHeaders getHeaders() { +// return new HttpHeaders(); +// } +// } +// +//// protected void customizeRequest(MutableHttpServerRequest httpServerRequest, +//// RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) { +//// +//// RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest(); +//// String pathPattern = dubboRequestMetadata.getPath(); +//// +//// Map pathVariables = pathMatcher.extractUriTemplateVariables(pathPattern, httpServerRequest.getPath()); +//// +//// if (!CollectionUtils.isEmpty(pathVariables)) { +//// // Put path variables Map into query parameters Map +//// httpServerRequest.params(pathVariables); +//// } +//// +//// } +// +// private RequestMetadata buildRequestMetadata(HttpServletRequest request, String restPath) { +// UriComponents uriComponents = fromUriString(request.getRequestURI()).build(true); +// RequestMetadata requestMetadata = new RequestMetadata(); +// requestMetadata.setPath(restPath); +// requestMetadata.setMethod(request.getMethod()); +// requestMetadata.setParams(getParams(request)); +// requestMetadata.setHeaders(getHeaders(request)); +// return requestMetadata; +// } +// +// private Map> getHeaders(HttpServletRequest request) { +// Map> map = new LinkedHashMap<>(); +// Enumeration headerNames = request.getHeaderNames(); +// while (headerNames.hasMoreElements()) { +// String headerName = headerNames.nextElement(); +// Enumeration headerValues = request.getHeaders(headerName); +// map.put(headerName, Collections.list(headerValues)); +// } +// return map; +// } +// +// private Map> getParams(HttpServletRequest request) { +// Map> map = new LinkedHashMap<>(); +// for (Map.Entry entry : request.getParameterMap().entrySet()) { +// map.put(entry.getKey(), Arrays.asList(entry.getValue())); +// } +// return map; +// } +//}