From 3407cd36de1809659e570d83794ac6c61103995f Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 28 Mar 2019 01:13:41 +0800 Subject: [PATCH] Refactor Dubbo Service registration logic: 1. Simplify registration implementation 2. Add Event-Driven --- .../DubboMetadataAutoConfiguration.java | 3 +- ...etadataEventHandlingAutoConfiguration.java | 149 +++++---- .../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 | 313 +++++------------- .../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, 711 insertions(+), 835 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 a853a3fb0..1714b864a 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 e91e03c31..c48231698 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,26 +141,60 @@ public class DubboMetadataEventHandlingAutoConfiguration { unexportDubboMetadataConfigService(); } - @ConditionalOnNotWebApplication - @Bean - public ApplicationRunner applicationRunner() { - return args -> { - - if (restServiceInstance == null) { - return; - } - - // From RegistrationFactoryProvider - RegistrationFactory registrationFactory = context.getBean(RegistrationFactory.class); + @EventListener(ServiceInstancePreRegisteredEvent.class) + public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { + Registration registration = event.getSource(); + exportDubboMetadataConfigService(); + attachURLsIntoMetadata(registration); + setRegistration(registration); + } - ServiceRegistry serviceRegistry = context.getBean(ServiceRegistry.class); + private void setRegistration(Registration registration) { + this.registration = registration; + } - Registration registration = context.getBean(Registration.class); + /** + * Handle the pre-registered event of {@link ServiceInstance} for Consul + * + * @return ApplicationListener + */ + @ConditionalOnClass(name = CONSUL_REGISTRATION_CLASS_NAME) + @Bean + 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); + } + } + }; + } - restServiceInstance.getMetadata().putAll(registration.getMetadata()); + 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); + } + } - serviceRegistry.register(registrationFactory.create(restServiceInstance, context)); - }; + 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) { 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 88da964d8..c06108ede 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 9920e8c50..4860a3c37 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 f245df091..5c5ef3ad7 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 e8d21a310..e4a581027 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 9ef731dd6..fa93bb279 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 f17c30195..000000000 --- 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 000000000..c52cf231c --- /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 d05eea944..000000000 --- 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 c5debc684..000000000 --- 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 000000000..72ac16b0a --- /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 d87e1f6c1..d973e6293 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 { - - /** - * The parameter name of {@link #allServicesLookupInterval} - */ - public static final String ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.all.services.lookup.interval"; +public class SpringCloudRegistry extends AbstractSpringCloudRegistry { /** - * The parameter name of {@link #registeredServicesLookupInterval} + * The property name of Dubbo {@link URL URLs} metadata */ - public static final String REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.registered.services.lookup.interval"; + public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo-urls"; /** - * All supported categories + * The parameter name of the services of Dubbo Provider */ - public static final String[] ALL_SUPPORTED_CATEGORIES = of( - PROVIDERS_CATEGORY, - CONSUMERS_CATEGORY, - ROUTERS_CATEGORY, - CONFIGURATORS_CATEGORY - ); - - private final Logger logger = LoggerFactory.getLogger(getClass()); + public static final String DUBBO_PROVIDER_SERVICES_PARAM_NAME = "dubbo-provider-services"; /** - * The interval in second of lookup service names(only for Dubbo-OPS) + * All services of Dubbo Provider */ - private final long allServicesLookupInterval; - - private final long registeredServicesLookupInterval; - - private final ServiceRegistry serviceRegistry; - - private final RegistrationFactory registrationFactory; + public static final String ALL_DUBBO_PROVIDER_SERVICES = "*"; - private final DiscoveryClient discoveryClient; + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; - private final DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler; + private final JSONUtils jsonUtils; - private final ScheduledExecutorService servicesLookupScheduler; + private final Set dubboProviderServices; - private final ConfigurableApplicationContext applicationContext; + private final Map dubboServiceKeysCache; - 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; - } - - protected boolean shouldRegister(Registration registration) { - Map metadata = registration.getMetadata(); - String side = metadata.get(SIDE_KEY); - return PROVIDER_SIDE.equals(side); // Only register the Provider. - } - - @Override - public void doRegister(URL url) { - final Registration registration = createRegistration(url); - if (shouldRegister(registration)) { - serviceRegistry.register(registration); - } - } - - @Override - public void doUnregister(URL url) { - final Registration registration = createRegistration(url); - if (shouldRegister(registration)) { - this.serviceRegistry.deregister(registration); - } - } - - @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); - } - - @Override - public void doUnsubscribe(URL url, NotifyListener listener) { - if (isAdminProtocol(url)) { - shutdownServiceNamesLookup(); - } - } - - @Override - public boolean isAvailable() { - return !discoveryClient.getServices().isEmpty(); - } - - 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); - } - }); + super(url, discoveryClient, servicesLookupScheduler); + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + this.jsonUtils = applicationContext.getBean(JSONUtils.class); + this.dubboProviderServices = getDubboProviderServices(); + this.dubboServiceKeysCache = this.initDubboServiceKeysCache(); } - private List getAllServiceNames() { - return new LinkedList<>(discoveryClient.getServices()); - } + private Map initDubboServiceKeysCache() { - /** - * 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)); + if (isEmpty(dubboProviderServices)) { + return emptyMap(); } - } + Map newCache = new HashMap<>(); - private boolean isAdminProtocol(URL url) { - return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); - } + 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); + }); + }); - 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); + return newCache; } - 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 boolean isNotEmpty(Collection collection) { + return !CollectionUtils.isEmpty(collection); } - 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 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 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 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); } - private URL buildURL(ServiceInstance serviceInstance) { - URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), - serviceInstance.getHost(), - serviceInstance.getPort(), - serviceInstance.getMetadata()); - return url; + @Override + protected void doRegister0(URL url) { + dubboServiceMetadataRepository.registerURL(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; + @Override + protected void doUnregister0(URL url) { + dubboServiceMetadataRepository.unregisterURL(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(); - } - } + @Override + protected boolean supports(String serviceName) { + return dubboProviderServices.contains(serviceName); } - private static T[] of(T... values) { - return values; + @Override + protected String getServiceName(URL url) { + String serviceKey = url.getServiceKey(); + return dubboServiceKeysCache.get(serviceKey); } - /** - * 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); - + @Override + 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); } - } 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 234c65d44..15dd3e5d4 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 23638325c..000000000 --- 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 000000000..6233e9a5b --- /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 1bcfd534f..8aab6aa76 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 a5861fb9e..000000000 --- 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 e72bf40f2..000000000 --- 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 10cd08c9f..d16486417 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 fa49e94bb..76fe660f9 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 000000000..1dd1f6daf --- /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 ed1c9c3f4..951a63622 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 a890294c8..786da0f27 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