From 3cf4b7cead480fede484162d28086b6b67e576ce Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 17 Apr 2019 10:24:41 +0800 Subject: [PATCH 1/4] Polish spring-cloud-incubator/spring-cloud-alibaba#559 : Add registered URLs into DubboMetadataService --- .../DubboMetadataAutoConfiguration.java | 15 +- ...oServiceRegistrationAutoConfiguration.java | 44 +-- ...ionNonWebApplicationAutoConfiguration.java | 27 +- .../metadata/DubboProtocolConfigSupplier.java | 24 +- .../DubboServiceMetadataRepository.java | 304 ++++++++++++++---- .../registry/AbstractSpringCloudRegistry.java | 121 +++++-- .../dubbo/registry/SpringCloudRegistry.java | 21 +- .../registry/SpringCloudRegistryFactory.java | 11 +- .../service/DubboGenericServiceFactory.java | 4 +- .../dubbo/service/DubboMetadataService.java | 44 ++- .../service/DubboMetadataServiceExporter.java | 39 ++- ...DubboMetadataServiceInvocationHandler.java | 16 +- .../service/DubboMetadataServiceProxy.java | 43 ++- .../IntrospectiveDubboMetadataService.java | 91 ++++++ .../PublishingDubboMetadataService.java | 66 ---- .../cloud/alibaba/dubbo/util/JSONUtils.java | 13 + 16 files changed, 633 insertions(+), 250 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java delete mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataService.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 331b63987..a4b107850 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 @@ -32,7 +32,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.DubboMetadataServiceExporter; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy; -import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataService; +import org.springframework.cloud.alibaba.dubbo.service.IntrospectiveDubboMetadataService; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -50,13 +50,13 @@ import java.util.function.Supplier; */ @Configuration @Import({DubboServiceMetadataRepository.class, - PublishingDubboMetadataService.class, + IntrospectiveDubboMetadataService.class, DubboMetadataServiceExporter.class, JSONUtils.class}) public class DubboMetadataAutoConfiguration { @Autowired - private PublishingDubboMetadataService dubboMetadataService; + private DubboServiceMetadataRepository dubboServiceMetadataRepository; @Autowired private MetadataResolver metadataResolver; @@ -87,7 +87,6 @@ public class DubboMetadataAutoConfiguration { public void onServiceBeanExported(ServiceBeanExportedEvent event) { ServiceBean serviceBean = event.getServiceBean(); publishServiceRestMetadata(serviceBean); - exportDubboMetadataConfigService(); } @EventListener(ApplicationFailedEvent.class) @@ -97,15 +96,11 @@ public class DubboMetadataAutoConfiguration { @EventListener(ContextClosedEvent.class) public void onContextClosed() { - dubboMetadataConfigServiceExporter.unexport(); + unExportDubboMetadataConfigService(); } private void publishServiceRestMetadata(ServiceBean serviceBean) { - dubboMetadataService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); - } - - private void exportDubboMetadataConfigService() { - dubboMetadataConfigServiceExporter.export(); + dubboServiceMetadataRepository.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); } private void unExportDubboMetadataConfigService() { 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 4ca3246e9..8c547b574 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 @@ -16,7 +16,6 @@ */ 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; @@ -35,7 +34,6 @@ 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.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; @@ -46,17 +44,13 @@ import org.springframework.context.SmartLifecycle; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; import java.util.Collection; 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.metadata.repository.DubboServiceMetadataRepository.DUBBO_URLS_METADATA_PROPERTY_NAME; import static org.springframework.util.ObjectUtils.isEmpty; /** @@ -93,13 +87,10 @@ public class DubboServiceRegistrationAutoConfiguration { @Autowired private DubboServiceMetadataRepository dubboServiceMetadataRepository; - @Autowired - private JSONUtils jsonUtils; - @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { Registration registration = event.getSource(); - attachURLsIntoMetadata(registration); + attachDubboMetadataServiceMetadata(registration); } @Configuration @@ -115,7 +106,7 @@ public class DubboServiceRegistrationAutoConfiguration { Registration registration = event.getSource(); EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration); InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo(); - attachURLsIntoMetadata(instanceInfo.getMetadata()); + attachDubboMetadataServiceMetadata(instanceInfo.getMetadata()); } /** @@ -155,39 +146,30 @@ public class DubboServiceRegistrationAutoConfiguration { private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) { NewService newService = consulRegistration.getService(); - String dubboURLsJson = getDubboURLsJSON(); - if (StringUtils.hasText(dubboURLsJson)) { + Map serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata(); + if (!isEmpty(serviceMetadata)) { List tags = newService.getTags(); - tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson); + for (Map.Entry entry : serviceMetadata.entrySet()) { + tags.add(entry.getKey() + "=" + entry.getValue()); + } } } } - private void attachURLsIntoMetadata(Registration registration) { + private void attachDubboMetadataServiceMetadata(Registration registration) { if (registration == null) { return; } 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); + attachDubboMetadataServiceMetadata(metadata); } } - 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; + private void attachDubboMetadataServiceMetadata(Map metadata) { + Map serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata(); + if (!isEmpty(serviceMetadata)) { + metadata.putAll(serviceMetadata); } - 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 9c6b87cd6..0f1f46d78 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 @@ -41,7 +41,7 @@ import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegist import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; -import java.util.Collection; +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.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME; @@ -97,20 +97,21 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { */ private void setServerPort() { if (serverPort == null) { - Collection urls = repository.getRegisteredUrls(); - urls.stream() - .filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol())) - .findFirst() - .ifPresent(url -> { + for (List urls : repository.getAllExportedUrls().values()) { + urls.stream() + .filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol())) + .findFirst() + .ifPresent(url -> { + serverPort = url.getPort(); + }); + + // If REST protocol is not present, use any applied port. + if (serverPort == null) { + urls.stream() + .findAny().ifPresent(url -> { serverPort = url.getPort(); }); - - // If REST protocol is not present, use any applied port. - if (serverPort == null) { - urls.stream() - .findAny().ifPresent(url -> { - serverPort = url.getPort(); - }); + } } } } 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 d5d994303..dd02429d8 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 @@ -25,6 +25,7 @@ import java.util.Iterator; import java.util.function.Supplier; import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL; +import static org.springframework.util.CollectionUtils.isEmpty; /** * Dubbo's {@link ProtocolConfig} {@link Supplier} @@ -43,23 +44,26 @@ public class DubboProtocolConfigSupplier implements Supplier { public ProtocolConfig get() { ProtocolConfig protocolConfig = null; Collection protocols = this.protocols.getIfAvailable(); - for (ProtocolConfig protocol : protocols) { - String protocolName = protocol.getName(); - if (DEFAULT_PROTOCOL.equals(protocolName)) { - protocolConfig = protocol; - break; + + if (!isEmpty(protocols)) { + for (ProtocolConfig protocol : protocols) { + String protocolName = protocol.getName(); + if (DEFAULT_PROTOCOL.equals(protocolName)) { + protocolConfig = protocol; + break; + } } - } - if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them - Iterator iterator = protocols.iterator(); - protocolConfig = iterator.hasNext() ? iterator.next() : null; + if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them + Iterator iterator = protocols.iterator(); + protocolConfig = iterator.hasNext() ? iterator.next() : null; + } } if (protocolConfig == null) { protocolConfig = new ProtocolConfig(); protocolConfig.setName(DEFAULT_PROTOCOL); - protocolConfig.setPort(20880); + protocolConfig.setPort(-1); } return protocolConfig; 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 a1205b580..3965ece0d 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 @@ -30,6 +30,7 @@ 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.DubboMetadataService; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceExporter; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; @@ -37,12 +38,12 @@ import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.http.HttpRequest; import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import javax.annotation.PostConstruct; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -51,10 +52,19 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import static java.lang.String.format; +import static java.lang.String.valueOf; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableMap; +import static java.util.Collections.unmodifiableSet; import static org.apache.dubbo.common.Constants.APPLICATION_KEY; +import static org.apache.dubbo.common.Constants.VERSION_KEY; import static org.springframework.cloud.alibaba.dubbo.env.DubboCloudProperties.ALL_DUBBO_SERVICES; import static org.springframework.cloud.alibaba.dubbo.http.DefaultHttpRequest.builder; import static org.springframework.util.CollectionUtils.isEmpty; +import static org.springframework.util.StringUtils.hasText; /** * Dubbo Service Metadata {@link Repository} @@ -65,17 +75,56 @@ import static org.springframework.util.CollectionUtils.isEmpty; public class DubboServiceMetadataRepository { /** - * The property name of Dubbo {@link URL URLs} metadata + * The prefix of {@link DubboMetadataService} : "dubbo.metadata-service." */ - public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo.urls"; + public static final String DUBBO_METADATA_SERVICE_PREFIX = "dubbo.metadata-service."; + + /** + * The {@link URL URLs} property name of {@link DubboMetadataService} : "dubbo.metadata-service.urls" + */ + public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = DUBBO_METADATA_SERVICE_PREFIX + "urls"; + + /** + * The {@link String#format(String, Object...) pattern} of dubbo protocols port + */ + public static final String DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN = "dubbo.protocols.%s.port"; private final Logger logger = LoggerFactory.getLogger(getClass()); private final ObjectMapper objectMapper = new ObjectMapper(); - private final Set registeredURLs = new LinkedHashSet<>(); + // =================================== Registration =================================== // + + /** + * All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method + * and value is the {@link List} of {@link URL URLs} + */ + private final MultiValueMap allExportedURLs = new LinkedMultiValueMap<>(); + + // ==================================================================================== // + + + // =================================== Subscription =================================== // + + private Set subscribedServices; + + /** + * The subscribed {@link URL urls} {@link Map} of {@link DubboMetadataService}, + * whose key is the return value of {@link URL#getServiceKey()} method and value is the {@link List} of + * {@link URL URLs} + */ + private final MultiValueMap subscribedDubboMetadataServiceURLs = new LinkedMultiValueMap<>(); + + // ==================================================================================== // - private final Map dubboServiceKeysRepository = new HashMap<>(); + + // =================================== REST Metadata ================================== // + + /** + * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, + * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods. + */ + private final Set serviceRestMetadata = new LinkedHashSet<>(); /** * Key is application name @@ -83,7 +132,10 @@ public class DubboServiceMetadataRepository { */ private Map> dubboRestServiceMetadataRepository = newHashMap(); - private Set subscribedServices; + // ==================================================================================== // + + + // =================================== Dependencies =================================== // @Autowired private DubboCloudProperties dubboCloudProperties; @@ -100,67 +152,179 @@ public class DubboServiceMetadataRepository { @Value("${spring.application.name}") private String currentApplicationName; + @Autowired + private DubboMetadataServiceExporter dubboMetadataServiceExporter; + + // ==================================================================================== // + + @PostConstruct public void init() { + // Keep the order in following invocations initSubscribedServices(); - initDubboServiceKeysRepository(); - retainAvailableSubscribedServices(); + initSubscribedDubboMetadataServices(); initDubboRestServiceMetadataRepository(); } /** - * The specified service is subscribe or not + * Get the metadata {@link Map} of {@link DubboMetadataService} * - * @param serviceName the service name - * @return + * @return non-null read-only {@link Map} */ - public boolean isSubscribedService(String serviceName) { - return subscribedServices.contains(serviceName); + public Map getDubboMetadataServiceMetadata() { + + List dubboMetadataServiceURLs = dubboMetadataServiceExporter.export(); + + // remove the exported URLs of DubboMetadataService + removeDubboMetadataServiceURLs(dubboMetadataServiceURLs); + + Map metadata = newHashMap(); + + addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs); + addDubboProtocolsPortMetadata(metadata); + + return Collections.unmodifiableMap(metadata); + } + + private void removeDubboMetadataServiceURLs(List dubboMetadataServiceURLs) { + dubboMetadataServiceURLs.forEach(this::unexportURL); + } + + private void addDubboMetadataServiceURLsMetadata(Map metadata, List dubboMetadataServiceURLs) { + String dubboMetadataServiceURLsJSON = jsonUtils.toJSON(dubboMetadataServiceURLs); + metadata.put(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME, dubboMetadataServiceURLsJSON); + } + + private void addDubboProtocolsPortMetadata(Map metadata) { + + allExportedURLs.values() + .stream() + .flatMap(v -> v.stream()) + .forEach(url -> { + String protocol = url.getProtocol(); + String propertyName = getDubboProtocolPropertyName(protocol); + String propertyValue = valueOf(url.getPort()); + metadata.put(propertyName, propertyValue); + }); } /** - * Get the service name by the {@link URL#getServiceKey() service key} + * Get the property name of Dubbo Protocol * - * @param url {@link URL} - * @return the service name if found + * @param protocol Dubbo Protocol + * @return non-null */ - public String getServiceName(URL url) { - return getServiceName(url.getServiceKey()); + public String getDubboProtocolPropertyName(String protocol) { + return format(DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN, protocol); } /** - * Get the service name by the {@link URL#getServiceKey() service key} + * Publish the {@link Set} of {@link ServiceRestMetadata} * - * @param serviceKey the {@link URL#getServiceKey() service key} - * @return the service name if found + * @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata} */ - public String getServiceName(String serviceKey) { - return dubboServiceKeysRepository.get(serviceKey); + public void publishServiceRestMetadata(Set serviceRestMetadataSet) { + for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { + if (!isEmpty(serviceRestMetadata.getMeta())) { + this.serviceRestMetadata.add(serviceRestMetadata); + } + } + } + + /** + * Get the {@link Set} of {@link ServiceRestMetadata} + * + * @return non-null read-only {@link Set} + */ + public Set getServiceRestMetadata() { + return unmodifiableSet(serviceRestMetadata); + } + +// /** +// * Get The subscribed {@link DubboMetadataService}'s {@link URL URLs} +// * +// * @return non-null read-only {@link List} +// */ +// public List getSubscribedDubboMetadataServiceURLs() { +// return Collections.unmodifiableList(subscribedDubboMetadataServiceURLs); +// } + + public List findSubscribedDubboMetadataServiceURLs(String serviceName, String group, String version, + String protocol) { + String serviceKey = URL.buildKey(serviceName, group, version); + List urls = subscribedDubboMetadataServiceURLs.get(serviceKey); + + if (isEmpty(urls)) { + return emptyList(); + } + + return hasText(protocol) ? + urls.stream().filter(url -> url.getProtocol().equalsIgnoreCase(protocol)).collect(Collectors.toList()) : + unmodifiableList(urls) + ; + } + + /** + * The specified service is subscribe or not + * + * @param serviceName the service name + * @return + */ + public boolean isSubscribedService(String serviceName) { + return subscribedServices.contains(serviceName); } - public void registerURL(URL url) { - this.registeredURLs.add(url); + public void exportURL(URL url) { + this.allExportedURLs.add(url.getServiceKey(), url); } - public void unregisterURL(URL url) { - this.registeredURLs.remove(url); + public void unexportURL(URL url) { + String key = url.getServiceKey(); + List urls = allExportedURLs.get(key); + urls.remove(url); + this.allExportedURLs.addAll(key, urls); } - public Collection getRegisteredUrls() { - return Collections.unmodifiableSet(registeredURLs); + /** + * Get all exported {@link URL urls}. + * + * @return non-null read-only + */ + public Map> getAllExportedUrls() { + return unmodifiableMap(allExportedURLs); } /** - * Build the {@link URL urls} by the specified {@link ServiceInstance} + * Get all exported {@link URL#getServiceKey() service keys} + * + * @return non-null read-only + */ + public Set getAllServiceKeys() { + return allExportedURLs.keySet(); + } + + /** + * Get the {@link URL urls} that {@link DubboMetadataService} exported by the specified {@link ServiceInstance} * * @param serviceInstance {@link ServiceInstance} * @return the mutable {@link URL urls} */ - public List buildURLs(ServiceInstance serviceInstance) { + public List getDubboMetadataServiceURLs(ServiceInstance serviceInstance) { + Map metadata = serviceInstance.getMetadata(); + String dubboURLsJSON = metadata.get(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME); + return jsonUtils.toURLs(dubboURLsJSON); + } + + public Integer getDubboProtocolPort(ServiceInstance serviceInstance, String protocol) { + String protocolProperty = getDubboProtocolPropertyName(protocol); Map metadata = serviceInstance.getMetadata(); - String dubboURLsJSON = metadata.get(DUBBO_URLS_METADATA_PROPERTY_NAME); - List urlValues = jsonUtils.toList(dubboURLsJSON); - return urlValues.stream().map(URL::valueOf).collect(Collectors.toList()); + String protocolPort = metadata.get(protocolProperty); + return hasText(protocolPort) ? Integer.valueOf(protocolPort) : null; + } + + public List getExportedURLs(String serviceInstance, String group, String version) { + String serviceKey = URL.buildKey(serviceInstance, group, version); + return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList()); } /** @@ -212,6 +376,10 @@ public class DubboServiceMetadataRepository { return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata); } + public Set getSubscribedServices() { + return Collections.unmodifiableSet(subscribedServices); + } + private T match(Map> repository, String serviceName, RequestMetadata requestMetadata) { @@ -256,18 +424,22 @@ public class DubboServiceMetadataRepository { } private Set getServiceRestMetadataSet(String serviceName) { - DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.newProxy(serviceName); - - Set metadata = Collections.emptySet(); - try { - String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata(); - if(StringUtils.hasText(serviceRestMetadataJsonConfig)) { - metadata = objectMapper.readValue(serviceRestMetadataJsonConfig, - TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class)); - } - } catch (Exception e) { - if (logger.isErrorEnabled()) { - logger.error(e.getMessage(), e); + + Set metadata = emptySet(); + + DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName); + + if (dubboMetadataService != null) { + try { + String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata(); + if (hasText(serviceRestMetadataJsonConfig)) { + metadata = objectMapper.readValue(serviceRestMetadataJsonConfig, + TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class)); + } + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } } } return metadata; @@ -292,8 +464,16 @@ public class DubboServiceMetadataRepository { private void initSubscribedServices() { // If subscribes all services - if (ALL_DUBBO_SERVICES.equalsIgnoreCase(dubboCloudProperties.getSubscribedServices())) { - subscribedServices = new HashSet<>(discoveryClient.getServices()); + if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) { + List services = discoveryClient.getServices(); + subscribedServices = new HashSet<>(services); + if (logger.isWarnEnabled()) { + logger.warn("Current application will subscribe all services(size:{}) in registry, " + + "a lot of memory and CPU cycles may be used, " + + "thus it's strongly recommend you using the externalized property '{}' " + + "to specify the services", + subscribedServices.size(), "dubbo.cloud.subscribed-services"); + } } else { subscribedServices = new HashSet<>(dubboCloudProperties.subscribedServices()); } @@ -305,23 +485,33 @@ public class DubboServiceMetadataRepository { subscribedServices.remove(currentApplicationName); } - private void initDubboServiceKeysRepository() { + private void initSubscribedDubboMetadataServices() { + // clear subscribedDubboMetadataServiceURLs + subscribedDubboMetadataServiceURLs.clear(); + subscribedServices.stream() .map(discoveryClient::getInstances) .filter(this::isNotEmpty) .forEach(serviceInstances -> { ServiceInstance serviceInstance = serviceInstances.get(0); - buildURLs(serviceInstance).forEach(url -> { - String serviceKey = url.getServiceKey(); - String serviceName = url.getParameter(APPLICATION_KEY); - dubboServiceKeysRepository.put(serviceKey, serviceName); + getDubboMetadataServiceURLs(serviceInstance).forEach(dubboMetadataServiceURL -> { + initSubscribedDubboMetadataServiceURLs(dubboMetadataServiceURL); + initDubboMetadataServiceProxy(dubboMetadataServiceURL); }); }); } - private void retainAvailableSubscribedServices() { - // dubboServiceKeysRepository.values() returns the available services(possible duplicated ones) - subscribedServices = new HashSet<>(dubboServiceKeysRepository.values()); + private void initSubscribedDubboMetadataServiceURLs(URL dubboMetadataServiceURL) { + // add subscriptions + String serviceKey = dubboMetadataServiceURL.getServiceKey(); + subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL); + } + + private void initDubboMetadataServiceProxy(URL dubboMetadataServiceURL) { + String serviceName = dubboMetadataServiceURL.getParameter(APPLICATION_KEY); + String version = dubboMetadataServiceURL.getParameter(VERSION_KEY); + // Initialize DubboMetadataService with right version + dubboMetadataConfigServiceProxy.initProxy(serviceName, version); } private void initDubboRestServiceMetadataRepository() { 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 index 4674f0e18..d2842bcc6 100644 --- 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 @@ -24,12 +24,18 @@ import org.apache.dubbo.registry.support.FailbackRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataService; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import java.util.Collection; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -38,9 +44,12 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; +import static org.apache.dubbo.common.Constants.APPLICATION_KEY; +import static org.apache.dubbo.common.Constants.GROUP_KEY; +import static org.apache.dubbo.common.Constants.PROTOCOL_KEY; import static org.apache.dubbo.common.Constants.PROVIDER_SIDE; import static org.apache.dubbo.common.Constants.SIDE_KEY; +import static org.apache.dubbo.common.Constants.VERSION_KEY; import static org.springframework.util.ObjectUtils.isEmpty; import static org.springframework.util.StringUtils.hasText; @@ -56,6 +65,8 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { */ public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval"; + protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName(); + protected final Logger logger = LoggerFactory.getLogger(getClass()); /** @@ -65,14 +76,26 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { private final DiscoveryClient discoveryClient; + private final DubboServiceMetadataRepository repository; + + private final DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; + + private final JSONUtils jsonUtils; + protected final ScheduledExecutorService servicesLookupScheduler; public AbstractSpringCloudRegistry(URL url, DiscoveryClient discoveryClient, + DubboServiceMetadataRepository dubboServiceMetadataRepository, + DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, + JSONUtils jsonUtils, ScheduledExecutorService servicesLookupScheduler) { super(url); this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L); this.discoveryClient = discoveryClient; + this.repository = dubboServiceMetadataRepository; + this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy; + this.jsonUtils = jsonUtils; this.servicesLookupScheduler = servicesLookupScheduler; } @@ -122,13 +145,83 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { @Override public final void doSubscribe(URL url, NotifyListener listener) { - Set serviceNames = getServiceNames(url); - doSubscribe(url, listener, serviceNames); + + if (isAdminURL(url)) { + // TODO in future + } else if (isDubboMetadataServiceURL(url)) { // for DubboMetadataService + subscribeDubboMetadataServiceURLs(url, listener); + } else { // for general Dubbo Services + subscribeDubboServiceURLs(url, listener); + } + } + + protected void subscribeDubboServiceURLs(URL url, NotifyListener listener) { + + doSubscribeDubboServiceURLs(url, listener); + + schedule(() -> { + doSubscribeDubboServiceURLs(url, listener); + }); + } + + protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { + + Set subscribedServices = repository.getSubscribedServices(); + + subscribedServices.stream() + .map(dubboMetadataConfigServiceProxy::getProxy) + .filter(Objects::nonNull) + .forEach(dubboMetadataService -> { + String serviceInterface = url.getServiceInterface(); + String group = url.getParameter(GROUP_KEY); + String version = url.getParameter(VERSION_KEY); + String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface, group, version); + List exportedURLs = jsonUtils.toURLs(exportedURLsJSON); + List allSubscribedURLs = new LinkedList<>(); + for (URL exportedURL : exportedURLs) { + String serviceName = exportedURL.getParameter(APPLICATION_KEY); + List serviceInstances = discoveryClient.getInstances(serviceName); + String protocol = exportedURL.getProtocol(); + List subscribedURLs = new LinkedList<>(); + serviceInstances.forEach(serviceInstance -> { + Integer port = repository.getDubboProtocolPort(serviceInstance, protocol); + String host = serviceInstance.getHost(); + if (port == null) { + if (logger.isWarnEnabled()) { + logger.warn("The protocol[{}] port of Dubbo service instance[host : {}] " + + "can't be resolved", protocol, host); + } + } else { + URL subscribedURL = new URL(protocol, host, port, exportedURL.getParameters()); + subscribedURLs.add(subscribedURL); + } + }); + + if (logger.isDebugEnabled()) { + logger.debug("The subscribed URLs[ service name : {} , protocol : {}] will be notified : {}" + , serviceName, protocol, subscribedURLs); + } + + allSubscribedURLs.addAll(subscribedURLs); + } + + listener.notify(allSubscribedURLs); + }); + } + + + private void subscribeDubboMetadataServiceURLs(URL url, NotifyListener listener) { + String serviceInterface = url.getServiceInterface(); + String group = url.getParameter(GROUP_KEY); + String version = url.getParameter(VERSION_KEY); + String protocol = url.getParameter(PROTOCOL_KEY); + List urls = repository.findSubscribedDubboMetadataServiceURLs(serviceInterface, group, version, protocol); + listener.notify(urls); } @Override public final void doUnsubscribe(URL url, NotifyListener listener) { - if (isAdminProtocol(url)) { + if (isAdminURL(url)) { shutdownServiceNamesLookup(); } } @@ -154,22 +247,12 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { 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 isAdminURL(URL url) { + return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); } - protected boolean isAdminProtocol(URL url) { - return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); + protected boolean isDubboMetadataServiceURL(URL url) { + return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); } /** @@ -183,8 +266,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { return filterServiceNames(serviceNames); } - protected abstract String getServiceName(URL url); - private void doSubscribe(final URL url, final NotifyListener listener, final Collection serviceNames) { subscribe(url, listener, serviceNames); 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 24db73660..d3e04f475 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 @@ -21,6 +21,8 @@ import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.RegistryFactory; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; @@ -38,20 +40,22 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { private final DubboServiceMetadataRepository dubboServiceMetadataRepository; public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient, - ScheduledExecutorService servicesLookupScheduler, - DubboServiceMetadataRepository dubboServiceMetadataRepository) { - super(url, discoveryClient, servicesLookupScheduler); + DubboServiceMetadataRepository dubboServiceMetadataRepository, + DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, + JSONUtils jsonUtils, + ScheduledExecutorService servicesLookupScheduler) { + super(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler); this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; } @Override protected void doRegister0(URL url) { - dubboServiceMetadataRepository.registerURL(url); + dubboServiceMetadataRepository.exportURL(url); } @Override protected void doUnregister0(URL url) { - dubboServiceMetadataRepository.unregisterURL(url); + dubboServiceMetadataRepository.unexportURL(url); } @Override @@ -59,15 +63,10 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { return dubboServiceMetadataRepository.isSubscribedService(serviceName); } - @Override - protected String getServiceName(URL url) { - return dubboServiceMetadataRepository.getServiceName(url); - } - @Override protected void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) { List urls = serviceInstances.stream() - .map(dubboServiceMetadataRepository::buildURLs) + .map(dubboServiceMetadataRepository::getDubboMetadataServiceURLs) .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 4a0468015..36897cf61 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 @@ -22,6 +22,8 @@ import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.ConfigurableApplicationContext; @@ -50,6 +52,10 @@ public class SpringCloudRegistryFactory implements RegistryFactory { private DubboServiceMetadataRepository dubboServiceMetadataRepository; + private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy; + + private JSONUtils jsonUtils; + private volatile boolean initialized = false; public SpringCloudRegistryFactory() { @@ -63,12 +69,15 @@ public class SpringCloudRegistryFactory implements RegistryFactory { } this.discoveryClient = applicationContext.getBean(DiscoveryClient.class); this.dubboServiceMetadataRepository = applicationContext.getBean(DubboServiceMetadataRepository.class); + this.dubboMetadataConfigServiceProxy = applicationContext.getBean(DubboMetadataServiceProxy.class); + this.jsonUtils = applicationContext.getBean(JSONUtils.class); } @Override public Registry getRegistry(URL url) { init(); - return new SpringCloudRegistry(url, discoveryClient, servicesLookupScheduler, dubboServiceMetadataRepository); + return new SpringCloudRegistry(url, discoveryClient, dubboServiceMetadataRepository, + dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler); } public static void setApplicationContext(ConfigurableApplicationContext applicationContext) { 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 d16486417..1198bd74e 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 @@ -62,9 +62,9 @@ public class DubboGenericServiceFactory { return referenceBean == null ? null : referenceBean.get(); } - public GenericService create(String serviceName, Class serviceClass) { + public GenericService create(String serviceName, Class serviceClass, String version) { String interfaceName = serviceClass.getName(); - ReferenceBean referenceBean = build(interfaceName, serviceName, null, emptyMap()); + ReferenceBean referenceBean = build(interfaceName, version, serviceName, emptyMap()); return referenceBean.get(); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java index c0d78acae..fd99e2c41 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java @@ -16,21 +16,61 @@ */ package org.springframework.cloud.alibaba.dubbo.service; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.annotation.Service; + import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; +import java.util.List; +import java.util.Map; import java.util.Set; /** - * Dubbo Metadata Service + * Dubbo Metadata Service is a core interface for service subscribers, + * it must keep the stable of structure in every evolution , makes sure all subscribers' compatibility. + *

+ * The interface contract's version must be {@link #VERSION} constant and group must be current Dubbo application name * * @author Mercy */ public interface DubboMetadataService { /** - * Get The json content of {@link ServiceRestMetadata} {@link Set} + * Current version of the interface contract + */ + String VERSION = "1.0.0"; + + /** + * Get the json content of {@link ServiceRestMetadata} {@link Set} * * @return null if present */ String getServiceRestMetadata(); + + + /** + * Get all exported {@link URL#getServiceKey() service keys} + * + * @return non-null read-only {@link Set} + */ + Set getAllServiceKeys(); + + /** + * Get all exported Dubbo's {@link URL URLs} {@link Map} whose key is the return value of + * {@link URL#getServiceKey()} method and value is the json content of List of {@link URL URLs} + * + * @return non-null read-only {@link Map} + */ + Map getAllExportedURLs(); + + /** + * Get the json content of an exported List of {@link URL URLs} by the serviceInstance , group and version + * + * @param serviceInstance The class name of service interface + * @param group {@link Service#group() the service group} (optional) + * @param version {@link Service#version() the service version} (optional) + * @return non-null read-only {@link List} + * @see URL + */ + String getExportedURLs(String serviceInstance, String group, String version); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java index b2b866c5f..5f1d48afa 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java @@ -16,6 +16,7 @@ */ package org.springframework.cloud.alibaba.dubbo.service; +import org.apache.dubbo.common.URL; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ServiceConfig; @@ -26,6 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import javax.annotation.PreDestroy; +import java.util.List; import java.util.function.Supplier; /** @@ -47,7 +50,7 @@ public class DubboMetadataServiceExporter { @Autowired private Supplier protocolConfigSupplier; - @Value("${spring.application.name:application}") + @Value("${spring.application.name:${dubbo.application.name:application}}") private String currentApplicationName; /** @@ -57,33 +60,39 @@ public class DubboMetadataServiceExporter { /** * export {@link DubboMetadataService} as Dubbo service + * + * @return the exported {@link URL URLs} */ - public void export() { + public List export() { - if (serviceConfig != null && serviceConfig.isExported()) { - return; - } + if (serviceConfig == null || !serviceConfig.isExported()) { - serviceConfig = new ServiceConfig<>(); + serviceConfig = new ServiceConfig<>(); - serviceConfig.setInterface(DubboMetadataService.class); - // Use current Spring application name as the Dubbo Service version - serviceConfig.setVersion(currentApplicationName); - serviceConfig.setRef(dubboMetadataService); - serviceConfig.setApplication(applicationConfig); - serviceConfig.setProtocol(protocolConfigSupplier.get()); + serviceConfig.setInterface(DubboMetadataService.class); + // Use DubboMetadataService.VERSION as the Dubbo Service version + serviceConfig.setVersion(DubboMetadataService.VERSION); + // Use current Spring application name as the Dubbo Service group + serviceConfig.setGroup(currentApplicationName); + serviceConfig.setRef(dubboMetadataService); + serviceConfig.setApplication(applicationConfig); + serviceConfig.setProtocol(protocolConfigSupplier.get()); - serviceConfig.export(); + serviceConfig.export(); - if (logger.isInfoEnabled()) { - logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString()); + if (logger.isInfoEnabled()) { + logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString()); + } } + + return serviceConfig.getExportedUrls(); } /** * unexport {@link DubboMetadataService} */ + @PreDestroy public void unexport() { if (serviceConfig == null || serviceConfig.isUnexported()) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java index e4a7b24c2..4138b3b8d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java @@ -20,6 +20,7 @@ import org.apache.dubbo.rpc.service.GenericService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.util.stream.Stream; /** * {@link DubboMetadataService} {@link InvocationHandler} @@ -39,16 +40,17 @@ class DubboMetadataServiceInvocationHandler implements InvocationHandler { private final GenericService genericService; - public DubboMetadataServiceInvocationHandler(String serviceName, DubboGenericServiceFactory dubboGenericServiceFactory) { - this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class); + public DubboMetadataServiceInvocationHandler(String serviceName, String version, DubboGenericServiceFactory dubboGenericServiceFactory) { + this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class, version); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String methodName = method.getName(); - if (METHOD_NAME.equals(methodName)) { - return genericService.$invoke(methodName, PARAMETER_TYPES, PARAMETER_VALUES); - } - return method.invoke(proxy, args); + return genericService.$invoke(method.getName(), getParameterTypes(method), args); + } + + private String[] getParameterTypes(Method method) { + Class[] parameterTypes = method.getParameterTypes(); + return Stream.of(parameterTypes).map(Class::getName).toArray(length -> new String[length]); } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceProxy.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceProxy.java index 660834e34..614207c21 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceProxy.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceProxy.java @@ -17,35 +17,68 @@ package org.springframework.cloud.alibaba.dubbo.service; import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.DisposableBean; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import static java.lang.reflect.Proxy.newProxyInstance; /** * The proxy of {@link DubboMetadataService} */ -public class DubboMetadataServiceProxy implements BeanClassLoaderAware { +public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean { private final DubboGenericServiceFactory dubboGenericServiceFactory; private ClassLoader classLoader; + private final Map dubboMetadataServiceCache = new ConcurrentHashMap<>(); + public DubboMetadataServiceProxy(DubboGenericServiceFactory dubboGenericServiceFactory) { this.dubboGenericServiceFactory = dubboGenericServiceFactory; } /** - * New proxy instance of {@link DubboMetadataService} via the specified service name + * Initializes {@link DubboMetadataService}'s Proxy * * @param serviceName the service name + * @param version the service version * @return a {@link DubboMetadataService} proxy */ - public DubboMetadataService newProxy(String serviceName) { - return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class}, - new DubboMetadataServiceInvocationHandler(serviceName, dubboGenericServiceFactory)); + public DubboMetadataService initProxy(String serviceName, String version) { + return dubboMetadataServiceCache.computeIfAbsent(serviceName, name -> newProxy(name, version)); + } + + /** + * Get a proxy instance of {@link DubboMetadataService} via the specified service name + * + * @param serviceName the service name + * @return a {@link DubboMetadataService} proxy + */ + public DubboMetadataService getProxy(String serviceName) { + return dubboMetadataServiceCache.get(serviceName); } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } + + @Override + public void destroy() throws Exception { + dubboMetadataServiceCache.clear(); + } + + /** + * New a proxy instance of {@link DubboMetadataService} via the specified service name + * + * @param serviceName the service name + * @param version the service version + * @return a {@link DubboMetadataService} proxy + */ + protected DubboMetadataService newProxy(String serviceName, String version) { + return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class}, + new DubboMetadataServiceInvocationHandler(serviceName, version, dubboGenericServiceFactory)); + } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java new file mode 100644 index 000000000..672f06176 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java @@ -0,0 +1,91 @@ +/* + * 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.common.URL; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; +import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; +import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.Collections.unmodifiableMap; +import static org.springframework.util.CollectionUtils.isEmpty; + +/** + * Introspective {@link DubboMetadataService} implementation + * + * @author Mercy + */ +public class IntrospectiveDubboMetadataService implements DubboMetadataService { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private DubboServiceMetadataRepository dubboServiceMetadataRepository; + + @Autowired + private JSONUtils jsonUtils; + + @Override + public String getServiceRestMetadata() { + Set serviceRestMetadata = dubboServiceMetadataRepository.getServiceRestMetadata(); + String serviceRestMetadataJsonConfig = null; + if (!isEmpty(serviceRestMetadata)) { + serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata); + } + return serviceRestMetadataJsonConfig; + } + + @Override + public Set getAllServiceKeys() { + return dubboServiceMetadataRepository.getAllServiceKeys(); + } + + @Override + public Map getAllExportedURLs() { + Map> allExportedUrls = dubboServiceMetadataRepository.getAllExportedUrls(); + if (isEmpty(allExportedUrls)) { + if (logger.isDebugEnabled()) { + logger.debug("There is no registered URL."); + } + return Collections.emptyMap(); + } + + Map result = new HashMap<>(); + + allExportedUrls.forEach((serviceKey, urls) -> { + result.put(serviceKey, jsonUtils.toJSON(urls)); + }); + + return unmodifiableMap(result); + } + + @Override + public String getExportedURLs(String serviceInstance, String group, String version) { + List urls = dubboServiceMetadataRepository.getExportedURLs(serviceInstance, group, version); + return jsonUtils.toJSON(urls); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataService.java deleted file mode 100644 index 6fef49c74..000000000 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/PublishingDubboMetadataService.java +++ /dev/null @@ -1,66 +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.service; - -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 java.util.LinkedHashSet; -import java.util.Set; - -import static org.springframework.util.ObjectUtils.isEmpty; - -/** - * Publishing {@link DubboMetadataService} implementation - * - * @author Mercy - */ -public class PublishingDubboMetadataService implements DubboMetadataService { - - /** - * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service, - * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods. - */ - private final Set serviceRestMetadata = new LinkedHashSet<>(); - - @Autowired - private JSONUtils jsonUtils; - - /** - * Publish the {@link Set} of {@link ServiceRestMetadata} - * - * @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata} - */ - public void publishServiceRestMetadata(Set serviceRestMetadataSet) { - for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) { - if (!CollectionUtils.isEmpty(serviceRestMetadata.getMeta())) { - this.serviceRestMetadata.add(serviceRestMetadata); - } - } - } - - @Override - public String getServiceRestMetadata() { - String serviceRestMetadataJsonConfig = null; - 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 index 1dd1f6daf..2ed9a7b58 100644 --- 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 @@ -16,6 +16,8 @@ */ package org.springframework.cloud.alibaba.dubbo.util; +import org.apache.dubbo.common.URL; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -25,8 +27,10 @@ import org.springframework.util.StringUtils; import javax.annotation.PostConstruct; import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * JSON Utilities class @@ -44,6 +48,10 @@ public class JSONUtils { this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); } + public String toJSON(Collection urls) { + return toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toSet())); + } + public String toJSON(Object object) { String jsonContent = null; try { @@ -56,6 +64,11 @@ public class JSONUtils { return jsonContent; } + public List toURLs(String urlsJSON) { + List list = toList(urlsJSON); + return list.stream().map(URL::valueOf).collect(Collectors.toList()); + } + public List toList(String json) { List list = Collections.emptyList(); try { From aef27e885e99ac32d71e3f3668d1c01cb60a99a8 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 17 Apr 2019 11:32:23 +0800 Subject: [PATCH 2/4] Polish spring-cloud-incubator/spring-cloud-alibaba#559 : Refactor and filter protocol --- .../DubboServiceMetadataRepository.java | 4 ++-- .../registry/AbstractSpringCloudRegistry.java | 23 ++++++++++++++----- .../dubbo/service/DubboMetadataService.java | 6 ++--- ...DubboMetadataServiceInvocationHandler.java | 22 ++++++++++-------- .../IntrospectiveDubboMetadataService.java | 4 ++-- 5 files changed, 37 insertions(+), 22 deletions(-) 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 3965ece0d..cf32659e1 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 @@ -322,8 +322,8 @@ public class DubboServiceMetadataRepository { return hasText(protocolPort) ? Integer.valueOf(protocolPort) : null; } - public List getExportedURLs(String serviceInstance, String group, String version) { - String serviceKey = URL.buildKey(serviceInstance, group, version); + public List getExportedURLs(String serviceInterface, String group, String version) { + String serviceKey = URL.buildKey(serviceInterface, group, version); return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList()); } 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 index d2842bcc6..06855d024 100644 --- 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 @@ -172,15 +172,11 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { .map(dubboMetadataConfigServiceProxy::getProxy) .filter(Objects::nonNull) .forEach(dubboMetadataService -> { - String serviceInterface = url.getServiceInterface(); - String group = url.getParameter(GROUP_KEY); - String version = url.getParameter(VERSION_KEY); - String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface, group, version); - List exportedURLs = jsonUtils.toURLs(exportedURLsJSON); + List exportedURLs = getExportedURLs(dubboMetadataService, url); List allSubscribedURLs = new LinkedList<>(); for (URL exportedURL : exportedURLs) { String serviceName = exportedURL.getParameter(APPLICATION_KEY); - List serviceInstances = discoveryClient.getInstances(serviceName); + List serviceInstances = getServiceInstances(serviceName); String protocol = exportedURL.getProtocol(); List subscribedURLs = new LinkedList<>(); serviceInstances.forEach(serviceInstance -> { @@ -209,6 +205,21 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { }); } + private List getExportedURLs(DubboMetadataService dubboMetadataService, URL url) { + String serviceInterface = url.getServiceInterface(); + String group = url.getParameter(GROUP_KEY); + String version = url.getParameter(VERSION_KEY); + // The subscribed protocol may be null + String subscribedProtocol = url.getParameter(PROTOCOL_KEY); + String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface, group, version); + return jsonUtils + .toURLs(exportedURLsJSON) + .stream() + .filter(exportedURL -> + subscribedProtocol == null || subscribedProtocol.equalsIgnoreCase(exportedURL.getProtocol()) + ).collect(Collectors.toList()); + } + private void subscribeDubboMetadataServiceURLs(URL url, NotifyListener listener) { String serviceInterface = url.getServiceInterface(); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java index fd99e2c41..131a0c1af 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataService.java @@ -64,13 +64,13 @@ public interface DubboMetadataService { Map getAllExportedURLs(); /** - * Get the json content of an exported List of {@link URL URLs} by the serviceInstance , group and version + * Get the json content of an exported List of {@link URL URLs} by the serviceInterface , group and version * - * @param serviceInstance The class name of service interface + * @param serviceInterface The class name of service interface * @param group {@link Service#group() the service group} (optional) * @param version {@link Service#version() the service version} (optional) * @return non-null read-only {@link List} * @see URL */ - String getExportedURLs(String serviceInstance, String group, String version); + String getExportedURLs(String serviceInterface, String group, String version); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java index 4138b3b8d..db95179fc 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceInvocationHandler.java @@ -18,6 +18,9 @@ package org.springframework.cloud.alibaba.dubbo.service; import org.apache.dubbo.rpc.service.GenericService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.stream.Stream; @@ -29,14 +32,7 @@ import java.util.stream.Stream; */ class DubboMetadataServiceInvocationHandler implements InvocationHandler { - /** - * The method name of {@link DubboMetadataService#getServiceRestMetadata()} - */ - private static final String METHOD_NAME = "getServiceRestMetadata"; - - private static final String[] PARAMETER_TYPES = new String[0]; - - private static final String[] PARAMETER_VALUES = new String[0]; + private final Logger logger = LoggerFactory.getLogger(getClass()); private final GenericService genericService; @@ -46,7 +42,15 @@ class DubboMetadataServiceInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - return genericService.$invoke(method.getName(), getParameterTypes(method), args); + Object returnValue = null; + try { + returnValue = genericService.$invoke(method.getName(), getParameterTypes(method), args); + } catch (Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return returnValue; } private String[] getParameterTypes(Method method) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java index 672f06176..b409db98c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java @@ -84,8 +84,8 @@ public class IntrospectiveDubboMetadataService implements DubboMetadataService { } @Override - public String getExportedURLs(String serviceInstance, String group, String version) { - List urls = dubboServiceMetadataRepository.getExportedURLs(serviceInstance, group, version); + public String getExportedURLs(String serviceInterface, String group, String version) { + List urls = dubboServiceMetadataRepository.getExportedURLs(serviceInterface, group, version); return jsonUtils.toJSON(urls); } } From 0a9930c8c244305aabb1c8adc24285aefc5111ab Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 17 Apr 2019 12:51:27 +0800 Subject: [PATCH 3/4] Polish spring-cloud-incubator/spring-cloud-alibaba#559 : Resolve BeanCurrentlyInCreationException issue --- .../DubboMetadataAutoConfiguration.java | 4 ++-- .../service/DubboMetadataServiceExporter.java | 5 +++-- .../IntrospectiveDubboMetadataService.java | 15 ++++++++++----- 3 files changed, 15 insertions(+), 9 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 a4b107850..b41553d5f 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 @@ -56,7 +56,7 @@ import java.util.function.Supplier; public class DubboMetadataAutoConfiguration { @Autowired - private DubboServiceMetadataRepository dubboServiceMetadataRepository; + private ObjectProvider dubboServiceMetadataRepository; @Autowired private MetadataResolver metadataResolver; @@ -100,7 +100,7 @@ public class DubboMetadataAutoConfiguration { } private void publishServiceRestMetadata(ServiceBean serviceBean) { - dubboServiceMetadataRepository.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); + dubboServiceMetadataRepository.getIfAvailable().publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean)); } private void unExportDubboMetadataConfigService() { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java index 5f1d48afa..598b1ac3b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/DubboMetadataServiceExporter.java @@ -23,6 +23,7 @@ import org.apache.dubbo.config.ServiceConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -45,7 +46,7 @@ public class DubboMetadataServiceExporter { private ApplicationConfig applicationConfig; @Autowired - private DubboMetadataService dubboMetadataService; + private ObjectProvider dubboMetadataService; @Autowired private Supplier protocolConfigSupplier; @@ -74,7 +75,7 @@ public class DubboMetadataServiceExporter { serviceConfig.setVersion(DubboMetadataService.VERSION); // Use current Spring application name as the Dubbo Service group serviceConfig.setGroup(currentApplicationName); - serviceConfig.setRef(dubboMetadataService); + serviceConfig.setRef(dubboMetadataService.getIfAvailable()); serviceConfig.setApplication(applicationConfig); serviceConfig.setProtocol(protocolConfigSupplier.get()); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java index b409db98c..048f4e2e7 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/service/IntrospectiveDubboMetadataService.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; @@ -44,14 +45,14 @@ public class IntrospectiveDubboMetadataService implements DubboMetadataService { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired - private DubboServiceMetadataRepository dubboServiceMetadataRepository; + private ObjectProvider dubboServiceMetadataRepository; @Autowired private JSONUtils jsonUtils; @Override public String getServiceRestMetadata() { - Set serviceRestMetadata = dubboServiceMetadataRepository.getServiceRestMetadata(); + Set serviceRestMetadata = getRepository().getServiceRestMetadata(); String serviceRestMetadataJsonConfig = null; if (!isEmpty(serviceRestMetadata)) { serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata); @@ -61,12 +62,12 @@ public class IntrospectiveDubboMetadataService implements DubboMetadataService { @Override public Set getAllServiceKeys() { - return dubboServiceMetadataRepository.getAllServiceKeys(); + return getRepository().getAllServiceKeys(); } @Override public Map getAllExportedURLs() { - Map> allExportedUrls = dubboServiceMetadataRepository.getAllExportedUrls(); + Map> allExportedUrls = getRepository().getAllExportedUrls(); if (isEmpty(allExportedUrls)) { if (logger.isDebugEnabled()) { logger.debug("There is no registered URL."); @@ -85,7 +86,11 @@ public class IntrospectiveDubboMetadataService implements DubboMetadataService { @Override public String getExportedURLs(String serviceInterface, String group, String version) { - List urls = dubboServiceMetadataRepository.getExportedURLs(serviceInterface, group, version); + List urls = getRepository().getExportedURLs(serviceInterface, group, version); return jsonUtils.toJSON(urls); } + + private DubboServiceMetadataRepository getRepository() { + return dubboServiceMetadataRepository.getIfAvailable(); + } } From 18c4fccebf6d09c04cd79805365877e541aad731 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 17 Apr 2019 13:33:55 +0800 Subject: [PATCH 4/4] Polish spring-cloud-incubator/spring-cloud-alibaba#559 : Optimize Scheduler tasks --- .../registry/AbstractSpringCloudRegistry.java | 97 ++++++------------- .../dubbo/registry/SpringCloudRegistry.java | 18 ---- 2 files changed, 29 insertions(+), 86 deletions(-) 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 index 06855d024..b60c82474 100644 --- 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 @@ -31,8 +31,7 @@ import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; -import java.util.Collection; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -40,7 +39,6 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; import java.util.stream.Collectors; import static java.util.Collections.emptyList; @@ -50,7 +48,6 @@ import static org.apache.dubbo.common.Constants.PROTOCOL_KEY; import static org.apache.dubbo.common.Constants.PROVIDER_SIDE; import static org.apache.dubbo.common.Constants.SIDE_KEY; import static org.apache.dubbo.common.Constants.VERSION_KEY; -import static org.springframework.util.ObjectUtils.isEmpty; import static org.springframework.util.StringUtils.hasText; /** @@ -67,6 +64,8 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName(); + private static final Set schedulerTasks = new HashSet<>(); + protected final Logger logger = LoggerFactory.getLogger(getClass()); /** @@ -82,6 +81,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { private final JSONUtils jsonUtils; + protected final ScheduledExecutorService servicesLookupScheduler; public AbstractSpringCloudRegistry(URL url, @@ -159,9 +159,14 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { doSubscribeDubboServiceURLs(url, listener); - schedule(() -> { - doSubscribeDubboServiceURLs(url, listener); - }); + submitSchedulerTaskIfAbsent(url, listener); + } + + private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) { + String taskId = url.toIdentityString(); + if (schedulerTasks.add(taskId)) { + schedule(() -> doSubscribeDubboServiceURLs(url, listener)); + } } protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { @@ -194,8 +199,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { }); if (logger.isDebugEnabled()) { - logger.debug("The subscribed URLs[ service name : {} , protocol : {}] will be notified : {}" - , serviceName, protocol, subscribedURLs); + logger.debug("The subscribed URL[{}] will notify all URLs : {}", url, subscribedURLs); } allSubscribedURLs.addAll(subscribedURLs); @@ -205,6 +209,22 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { }); } + private List getServiceInstances(String serviceName) { + return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList(); + } + + private List doGetServiceInstances(String serviceName) { + List serviceInstances = emptyList(); + try { + serviceInstances = discoveryClient.getInstances(serviceName); + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return serviceInstances; + } + private List getExportedURLs(DubboMetadataService dubboMetadataService, URL url) { String serviceInterface = url.getServiceInterface(); String group = url.getParameter(GROUP_KEY); @@ -220,7 +240,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { ).collect(Collectors.toList()); } - private void subscribeDubboMetadataServiceURLs(URL url, NotifyListener listener) { String serviceInterface = url.getServiceInterface(); String group = url.getParameter(GROUP_KEY); @@ -248,16 +267,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { } } - private Set filterServiceNames(Collection serviceNames) { - return new LinkedHashSet<>(filter(serviceNames, this::supports)); - } - - protected abstract boolean supports(String serviceName); - - protected final Set getAllServiceNames() { - return new LinkedHashSet<>(discoveryClient.getServices()); - } - protected boolean isAdminURL(URL url) { return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); } @@ -266,56 +275,8 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); } - /** - * Get the service names for Dubbo OPS - * - * @param url {@link URL} - * @return non-null - */ - protected Set getServiceNamesForOps(URL url) { - Set serviceNames = getAllServiceNames(); - return filterServiceNames(serviceNames); - } - - 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 hasText(serviceName) ? discoveryClient.getInstances(serviceName) : emptyList(); - } - - 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 Collection filter(Collection collection, Predicate filter) { - return collection.stream() - .filter(filter) - .collect(Collectors.toList()); - } } 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 d3e04f475..4928d40e1 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 @@ -17,18 +17,14 @@ package org.springframework.cloud.alibaba.dubbo.registry; import org.apache.dubbo.common.URL; -import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.RegistryFactory; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy; import org.springframework.cloud.alibaba.dubbo.util.JSONUtils; -import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; -import java.util.List; import java.util.concurrent.ScheduledExecutorService; -import java.util.stream.Collectors; /** * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" @@ -57,18 +53,4 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { protected void doUnregister0(URL url) { dubboServiceMetadataRepository.unexportURL(url); } - - @Override - protected boolean supports(String serviceName) { - return dubboServiceMetadataRepository.isSubscribedService(serviceName); - } - - @Override - protected void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) { - List urls = serviceInstances.stream() - .map(dubboServiceMetadataRepository::getDubboMetadataServiceURLs) - .flatMap(List::stream) - .collect(Collectors.toList()); - notify(url, listener, urls); - } }