diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java index 9f1999c7..f992365e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/DubboMetadataEndpointAutoConfiguration.java @@ -28,6 +28,8 @@ import com.alibaba.cloud.dubbo.actuate.endpoint.DubboRestMetadataEndpoint; /** * Dubbo Metadata Endpoints Auto-{@link Configuration} + * + * @author Mercy */ @ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.annotation.Endpoint") @PropertySource(value = "classpath:/META-INF/dubbo/default/actuator-endpoints.properties") diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java index 8d0f13dd..e04e246d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/actuate/endpoint/DubboRestMetadataEndpoint.java @@ -26,6 +26,8 @@ import com.alibaba.cloud.dubbo.service.DubboMetadataService; /** * Dubbo Rest Metadata {@link Endpoint} + * + * @author Mercy */ @Endpoint(id = "dubborestmetadata") public class DubboRestMetadataEndpoint { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java index 7e34b77e..23dcf34f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/annotation/DubboTransported.java @@ -27,6 +27,7 @@ import java.lang.annotation.Target; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.rpc.ExporterListener; import org.apache.dubbo.rpc.Filter; + import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.client.RestTemplate; @@ -51,6 +52,7 @@ import org.springframework.web.client.RestTemplate; * *

* + * @author Mercy * @see FeignClient * @see LoadBalanced */ diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java index 4117c7e8..5165e4b5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java @@ -136,7 +136,7 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration * {@link DubboTransported @DubboTransported} * * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} - * {@link RestTemplate} + * {@link RestTemplate} * @param attributesResolver {@link DubboTransportedAttributesResolver} * @return non-null {@link Map} */ @@ -162,8 +162,8 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration * * @param restTemplate {@link LoadBalanced @LoadBalanced} {@link RestTemplate} Bean * @param dubboTranslatedAttributes the annotation dubboTranslatedAttributes - * {@link RestTemplate} bean being annotated - * {@link DubboTransported @DubboTransported} + * {@link RestTemplate} bean being annotated + * {@link DubboTransported @DubboTransported} */ private void adaptRestTemplate(RestTemplate restTemplate, Map dubboTranslatedAttributes) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java index ffb83035..f39aa5fb 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java @@ -22,6 +22,7 @@ import java.util.function.Supplier; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; + import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java index b4f723ed..70d992dc 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java @@ -49,15 +49,6 @@ public class DubboServiceAutoConfiguration { return new DubboGenericServiceFactory(); } - @Configuration - @Import(value = { DubboGenericServiceExecutionContextFactory.class, - RequestParamServiceParameterResolver.class, - RequestBodyServiceParameterResolver.class, - RequestHeaderServiceParameterResolver.class, - PathVariableServiceParameterResolver.class }) - static class ParameterResolversConfiguration { - } - /** * Build a primary {@link PropertyResolver} bean to {@link Autowired @Autowired} * @@ -69,4 +60,13 @@ public class DubboServiceAutoConfiguration { public PropertyResolver primaryPropertyResolver(Environment environment) { return environment; } + + @Configuration + @Import(value = { DubboGenericServiceExecutionContextFactory.class, + RequestParamServiceParameterResolver.class, + RequestBodyServiceParameterResolver.class, + RequestHeaderServiceParameterResolver.class, + PathVariableServiceParameterResolver.class }) + static class ParameterResolversConfiguration { + } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java new file mode 100644 index 00000000..db22da91 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java @@ -0,0 +1,552 @@ +/* + * 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 com.alibaba.cloud.dubbo.autoconfigure; + +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient.hostToServiceInstanceList; +import static org.springframework.util.StringUtils.hasText; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.listen.Listenable; +import org.apache.curator.framework.listen.ListenerContainer; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.TreeCache; +import org.apache.curator.framework.recipes.cache.TreeCacheEvent; +import org.apache.curator.framework.recipes.cache.TreeCacheListener; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.registry.NotifyListener; + +import org.apache.zookeeper.Watcher; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; +import org.springframework.cloud.consul.discovery.ConsulCatalogWatch; +import org.springframework.cloud.netflix.eureka.CloudEurekaClient; +import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryProperties; +import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceWatch; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.ReflectionUtils; + +import com.alibaba.cloud.dubbo.env.DubboCloudProperties; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.AbstractSpringCloudRegistry; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; +import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.cloud.nacos.discovery.NacosWatch; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.netflix.discovery.CacheRefreshedEvent; +import com.netflix.discovery.shared.Applications; + +/** + * Dubbo Service Discovery Auto {@link Configuration} (after + * {@link DubboServiceRegistrationAutoConfiguration}) + * + * @author Mercy + * @see DubboServiceRegistrationAutoConfiguration + * @see Configuration + * @see DiscoveryClient + */ +@Configuration +@ConditionalOnClass(name = "org.springframework.cloud.client.discovery.DiscoveryClient") +@ConditionalOnProperty(name = "spring.cloud.discovery.enabled", matchIfMissing = true) +@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, + ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, + NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME }, value = { + DubboServiceRegistrationAutoConfiguration.class }) +public class DubboServiceDiscoveryAutoConfiguration { + + public static final String ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryAutoConfiguration"; + + public static final String CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration"; + + public static final String NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration"; + + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ApplicationEventPublisher applicationEventPublisher; + + private final DiscoveryClient discoveryClient; + + private final AtomicReference heartbeatState = new AtomicReference<>(); + + /** + * @see #defaultHeartbeatEventChangePredicate() + */ + private final ObjectProvider> heartbeatEventChangedPredicate; + + public DubboServiceDiscoveryAutoConfiguration( + DubboServiceMetadataRepository dubboServiceMetadataRepository, + ApplicationEventPublisher applicationEventPublisher, + DiscoveryClient discoveryClient, + ObjectProvider> heartbeatEventChangedPredicate) { + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + this.applicationEventPublisher = applicationEventPublisher; + this.discoveryClient = discoveryClient; + this.heartbeatEventChangedPredicate = heartbeatEventChangedPredicate; + } + + /** + * Dispatch a {@link ServiceInstancesChangedEvent} + * + * @param serviceName the name of service + * @param serviceInstances the {@link ServiceInstance instances} of some service + * @see AbstractSpringCloudRegistry#registerServiceInstancesChangedEventListener(URL, + * NotifyListener) + */ + private void dispatchServiceInstancesChangedEvent(String serviceName, + Collection serviceInstances) { + if (!hasText(serviceName) || serviceInstances == null) { + return; + } + ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(serviceName, + serviceInstances); + if (logger.isInfoEnabled()) { + logger.info( + "The event of the service instances[name : {} , size : {}] change is about to be dispatched", + serviceName, serviceInstances.size()); + } + applicationEventPublisher.publishEvent(event); + } + + private List getInstances(String serviceName) { + return discoveryClient.getInstances(serviceName); + } + + /** + * Dispatch a {@link ServiceInstancesChangedEvent} when the {@link HeartbeatEvent} + * raised, use for these scenarios: + *
    + *
  • Eureka : {@link CloudEurekaClient#onCacheRefreshed()} publishes a + * {@link HeartbeatEvent} instead of {@link CacheRefreshedEvent}
  • + *
  • Zookeeper : + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + * publishes a {@link HeartbeatEvent} when + * {@link ZookeeperDiscoveryProperties#getRoot() the services' root path} has been + * changed
  • + *
  • Consul : {@link ConsulCatalogWatch#catalogServicesWatch()} publishes a + * {@link HeartbeatEvent} when + * Consul's Blocking + * Queries response
  • + *
  • Nacos : {@link NacosWatch#nacosServicesWatch()} publishes a + * {@link HeartbeatEvent} under a {@link TaskScheduler} every + * {@link NacosDiscoveryProperties#getWatchDelay()} milliseconds
  • + *
+ *

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

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

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

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

+ *

+ * ${{@link #rootPath}}/{serviceName}/{serviceInstanceId} + * + * @see #rootPath + * @see #SERVICE_NAME_PATH_VARIABLE_NAME + * @see #SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME + */ + private final String serviceInstancePathPattern; + + /** + * The {@link ThreadLocal} holds the processed service name + */ + private final ThreadLocal processedServiceNameThreadLocal; + + ZookeeperConfiguration(ZookeeperDiscoveryProperties zookeeperDiscoveryProperties, + ZookeeperServiceWatch zookeeperServiceWatch) { + this.zookeeperServiceWatch = zookeeperServiceWatch; + this.rootPath = zookeeperDiscoveryProperties.getRoot(); + this.pathMatcher = new AntPathMatcher(NODE_PATH_SEPARATOR); + this.serviceInstancePathPattern = rootPath + NODE_PATH_SEPARATOR + "{" + + SERVICE_NAME_PATH_VARIABLE_NAME + "}" + NODE_PATH_SEPARATOR + "{" + + SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME + "}"; + this.processedServiceNameThreadLocal = new ThreadLocal<>(); + } + + /** + * Zookeeper uses {@link TreeCacheEvent} to trigger + * {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus + * {@link HeartbeatEvent} handle is always ignored + * + * @return false forever + */ + @Bean + public Predicate heartbeatEventChangedPredicate() { + return event -> false; + } + + /** + * Handle on {@link InstanceRegisteredEvent} after + * {@link ZookeeperServiceWatch#onApplicationEvent(InstanceRegisteredEvent)} + * + * @param event {@link InstanceRegisteredEvent} + * @see #reattachTreeCacheListeners() + */ + @Override + public void onApplicationEvent(InstanceRegisteredEvent event) { + reattachTreeCacheListeners(); + } + + /** + * Re-attach the {@link TreeCacheListener TreeCacheListeners} + */ + private void reattachTreeCacheListeners() { + + TreeCache treeCache = zookeeperServiceWatch.getCache(); + + Listenable listenable = treeCache.getListenable(); + + /** + * All registered TreeCacheListeners except {@link ZookeeperServiceWatch}. + * Usually, "otherListeners" will be empty because Spring Cloud Zookeeper only + * adds "zookeeperServiceWatch" bean as {@link TreeCacheListener} + */ + List otherListeners = new LinkedList<>(); + + if (listenable instanceof ListenerContainer) { + ListenerContainer listenerContainer = (ListenerContainer) listenable; + listenerContainer.forEach(listener -> { + /** + * Even though "listener" is an instance of + * {@link ZookeeperServiceWatch}, "zookeeperServiceWatch" bean that + * was enhanced by AOP is different from the former, thus it's + * required to exclude "listener" + */ + if (!(listener instanceof ZookeeperServiceWatch)) { + otherListeners.add(listener); + } + return null; + }); + + // remove all TreeCacheListeners temporarily + listenerContainer.clear(); + // re-store zookeeperServiceWatch, and make sure it's first one + // now "beforeChildEvent" is available for Spring AOP + listenerContainer.addListener(zookeeperServiceWatch); + // re-store others + otherListeners.forEach(listenerContainer::addListener); + } + else { + if (logger.isWarnEnabled()) { + logger.warn( + "Tell me which version Curator framework current application used? I will do better :D"); + } + } + } + + /** + * Try to {@link #dispatchServiceInstancesChangedEvent(String, Collection) + * dispatch} {@link ServiceInstancesChangedEvent} before + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + * execution if required + * + * @param client {@link CuratorFramework} + * @param event {@link TreeCacheEvent} + */ + @Before(CHILD_EVENT_POINTCUT_EXPRESSION) + public void beforeChildEvent(CuratorFramework client, TreeCacheEvent event) { + if (supportsEventType(event)) { + String serviceName = resolveServiceName(event); + if (hasText(serviceName)) { + dispatchServiceInstancesChangedEvent(serviceName, + getInstances(serviceName)); + } + } + } + + @After(CHILD_EVENT_POINTCUT_EXPRESSION) + public void afterChildEvent(CuratorFramework client, TreeCacheEvent event) { + } + + /** + * Resolve the name of service + * + * @param event {@link TreeCacheEvent} + * @return If the Zookeeper's {@link ChildData#getPath() node path} that was + * notified comes from {@link ServiceInstance the service instance}, return it's + * parent path as the service name, or return null + */ + private String resolveServiceName(TreeCacheEvent event) { + ChildData childData = event.getData(); + String path = childData.getPath(); + if (logger.isDebugEnabled()) { + logger.debug("ZK node[path : {}] event type : {}", path, event.getType()); + } + + String serviceName = null; + + if (pathMatcher.match(serviceInstancePathPattern, path)) { + Map variables = pathMatcher + .extractUriTemplateVariables(serviceInstancePathPattern, path); + serviceName = variables.get(SERVICE_NAME_PATH_VARIABLE_NAME); + } + + return serviceName; + } + + /** + * The {@link TreeCacheEvent#getType() event type} is supported or not + * + * @param event {@link TreeCacheEvent} + * @return the rule is same as + * {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)} + * method + */ + private boolean supportsEventType(TreeCacheEvent event) { + TreeCacheEvent.Type eventType = event.getType(); + return eventType.equals(TreeCacheEvent.Type.NODE_ADDED) + || eventType.equals(TreeCacheEvent.Type.NODE_REMOVED) + || eventType.equals(TreeCacheEvent.Type.NODE_UPDATED); + } + } + + /** + * Consul Customized Configuration + */ + @Configuration + @ConditionalOnBean(name = CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + class ConsulConfiguration { + + } + + /** + * Nacos Customized Configuration + */ + @Configuration + @ConditionalOnBean(name = NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + class NacosConfiguration { + + private final NamingService namingService; + + /** + * the set of services is listening + */ + private final Set listeningServices; + + NacosConfiguration(NacosDiscoveryProperties nacosDiscoveryProperties) { + this.namingService = nacosDiscoveryProperties.namingServiceInstance(); + this.listeningServices = new ConcurrentSkipListSet<>(); + } + + /** + * Nacos uses {@link EventListener} to trigger + * {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus + * {@link HeartbeatEvent} handle is always ignored + * + * @return false forever + */ + @Bean + public Predicate heartbeatEventChangedPredicate() { + return event -> false; + } + + @EventListener(SubscribedServicesChangedEvent.class) + public void onSubscribedServicesChangedEvent(SubscribedServicesChangedEvent event) + throws Exception { + // subscribe EventListener for each service + event.getNewSubscribedServices().forEach(this::subscribeEventListener); + } + + private void subscribeEventListener(String serviceName) { + if (listeningServices.add(serviceName)) { + try { + namingService.subscribe(serviceName, event -> { + if (event instanceof NamingEvent) { + NamingEvent namingEvent = (NamingEvent) event; + List serviceInstances = hostToServiceInstanceList( + namingEvent.getInstances(), serviceName); + dispatchServiceInstancesChangedEvent(serviceName, + serviceInstances); + } + }); + } + catch (NacosException e) { + ReflectionUtils.rethrowRuntimeException(e); + } + } + } + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index 6a863412..6031edce 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -16,8 +16,8 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS; import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL; import static org.springframework.util.ObjectUtils.isEmpty; @@ -28,6 +28,7 @@ import java.util.Map; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ServiceBean; + import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,7 +57,6 @@ import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistr import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; - import com.ecwid.consul.v1.agent.model.NewService; import com.netflix.appinfo.InstanceInfo; @@ -68,19 +68,19 @@ import com.netflix.appinfo.InstanceInfo; @Configuration @Import({ DubboServiceRegistrationEventPublishingAspect.class }) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureAfter(name = { EUREKA_AUTO_CONFIGURATION_CLASS_NAME, - CONSUL_AUTO_CONFIGURATION_CLASS_NAME, +@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME, "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" }, value = { DubboMetadataAutoConfiguration.class }) public class DubboServiceRegistrationAutoConfiguration { - public static final String EUREKA_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"; + public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"; - public static final String CONSUL_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; + public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; - public static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; + public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; - public static final String ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration"; + public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration"; private static final Logger logger = LoggerFactory .getLogger(DubboServiceRegistrationAutoConfiguration.class); @@ -100,8 +100,26 @@ public class DubboServiceRegistrationAutoConfiguration { attachDubboMetadataServiceMetadata(registration); } + private void attachDubboMetadataServiceMetadata(Registration registration) { + if (registration == null) { + return; + } + synchronized (registration) { + Map metadata = registration.getMetadata(); + attachDubboMetadataServiceMetadata(metadata); + } + } + + private void attachDubboMetadataServiceMetadata(Map metadata) { + Map serviceMetadata = dubboServiceMetadataRepository + .getDubboMetadataServiceMetadata(); + if (!isEmpty(serviceMetadata)) { + metadata.putAll(serviceMetadata); + } + } + @Configuration - @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) @Aspect class EurekaConfiguration implements SmartInitializingSingleton { @@ -136,7 +154,7 @@ public class DubboServiceRegistrationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) @AutoConfigureOrder class ConsulConfiguration { @@ -151,7 +169,7 @@ public class DubboServiceRegistrationAutoConfiguration { Registration registration = event.getSource(); Class registrationClass = AopUtils.getTargetClass(registration); String registrationClassName = registrationClass.getName(); - if (CONSUL_AUTO_REGISTRATION_CLASS_NAME + if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME .equalsIgnoreCase(registrationClassName)) { ConsulRegistration consulRegistration = (ConsulRegistration) registration; attachURLsIntoMetadata(consulRegistration); @@ -170,22 +188,4 @@ public class DubboServiceRegistrationAutoConfiguration { } } } - - private void attachDubboMetadataServiceMetadata(Registration registration) { - if (registration == null) { - return; - } - synchronized (registration) { - Map metadata = registration.getMetadata(); - attachDubboMetadataServiceMetadata(metadata); - } - } - - private void attachDubboMetadataServiceMetadata(Map metadata) { - Map serviceMetadata = dubboServiceMetadataRepository - .getDubboMetadataServiceMetadata(); - if (!isEmpty(serviceMetadata)) { - metadata.putAll(serviceMetadata); - } - } } \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java index e7836044..9c8e209c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java @@ -16,13 +16,14 @@ */ package com.alibaba.cloud.dubbo.autoconfigure; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; import java.util.List; import org.apache.dubbo.common.URL; import org.apache.dubbo.config.spring.ServiceBean; + import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -44,7 +45,6 @@ import org.springframework.context.event.EventListener; import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; - import com.ecwid.consul.v1.agent.model.NewService; /** @@ -117,7 +117,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) class ZookeeperConfiguration implements SmartInitializingSingleton { @Autowired @@ -138,7 +138,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) class ConsulConfiguration { /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java index b5ac2720..3aa14cd7 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java @@ -34,6 +34,7 @@ import com.alibaba.cloud.dubbo.registry.SpringCloudRegistry; /** * Missing {@link SpringCloudRegistry} Property {@link Condition} * + * @author Mercy * @see SpringCloudRegistry * @see Condition */ diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java index be001896..27fc1c94 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import org.apache.dubbo.rpc.service.GenericException; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java index a99e21d0..561515f7 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.List; import org.apache.dubbo.rpc.service.GenericException; + import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.HttpMessageConverter; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java index ba7606b3..53bc6a3f 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java @@ -49,7 +49,7 @@ public class DubboMetadataInitializerInterceptor implements ClientHttpRequestInt String serviceName = originalUri.getHost(); - repository.initialize(serviceName); + repository.initializeMetadata(serviceName); // Execute next return execution.execute(request, body); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java index 2b356485..4d73112d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java @@ -25,6 +25,7 @@ import java.util.Map; import org.apache.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericService; + import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java index 8979a83d..90eae069 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java @@ -77,6 +77,10 @@ public class DubboNonWebApplicationEnvironmentPostProcessor private final Logger logger = LoggerFactory .getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class); + private static boolean isRestProtocol(String protocol) { + return REST_PROTOCOL.equalsIgnoreCase(protocol); + } + @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { @@ -219,8 +223,4 @@ public class DubboNonWebApplicationEnvironmentPostProcessor public int getOrder() { // Keep LOWEST_PRECEDENCE return LOWEST_PRECEDENCE; } - - private static boolean isRestProtocol(String protocol) { - return REST_PROTOCOL.equalsIgnoreCase(protocol); - } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java index c8f4cdb3..4484a580 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import org.apache.dubbo.common.io.UnsafeByteArrayInputStream; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java index 8d27c577..183c4096 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java @@ -49,6 +49,10 @@ public class DefaultHttpRequest implements HttpRequest { this.headers.putAll(headers); } + public static Builder builder() { + return new Builder(); + } + private URI buildURI(String path, Map> params) { UriComponentsBuilder builder = fromPath(path) .queryParams(new LinkedMultiValueMap<>(params)); @@ -60,6 +64,7 @@ public class DefaultHttpRequest implements HttpRequest { return HttpMethod.resolve(getMethodValue()); } + @Override public String getMethodValue() { return method; } @@ -74,10 +79,6 @@ public class DefaultHttpRequest implements HttpRequest { return headers; } - public static Builder builder() { - return new Builder(); - } - /** * {@link HttpRequest} Builder */ diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java index 9b1d9ee2..3348bd69 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java @@ -73,6 +73,7 @@ public class MutableHttpServerRequest implements HttpServerRequest { } // Override method since Spring Framework 5.0 + @Override public String getMethodValue() { return httpMethod.name(); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java index 3d341f5b..aa160e29 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestConsumersMatcher.java @@ -42,7 +42,7 @@ public class HttpRequestConsumersMatcher extends AbstractHttpRequestMatcher { * Creates a new instance from 0 or more "consumes" expressions. * * @param consumes consumes expressions if 0 expressions are provided, the condition - * will match to every request + * will match to every request */ public HttpRequestConsumersMatcher(String... consumes) { this(consumes, null); @@ -70,6 +70,26 @@ public class HttpRequestConsumersMatcher extends AbstractHttpRequestMatcher { Collections.sort(this.expressions); } + private static Set parseExpressions(String[] consumes, + String[] headers) { + Set result = new LinkedHashSet<>(); + if (headers != null) { + for (String header : headers) { + HeaderExpression expr = new HeaderExpression(header); + if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) { + for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) { + result.add( + new ConsumeMediaTypeExpression(mediaType, expr.negated)); + } + } + } + } + for (String consume : consumes) { + result.add(new ConsumeMediaTypeExpression(consume)); + } + return result; + } + @Override public boolean match(HttpRequest request) { @@ -94,26 +114,6 @@ public class HttpRequestConsumersMatcher extends AbstractHttpRequestMatcher { return true; } - private static Set parseExpressions(String[] consumes, - String[] headers) { - Set result = new LinkedHashSet<>(); - if (headers != null) { - for (String header : headers) { - HeaderExpression expr = new HeaderExpression(header); - if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) { - for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) { - result.add( - new ConsumeMediaTypeExpression(mediaType, expr.negated)); - } - } - } - } - for (String consume : consumes) { - result.add(new ConsumeMediaTypeExpression(consume)); - } - return result; - } - @Override protected Collection getContent() { return this.expressions; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java index 1db0cfd7..01cafdfd 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcher.java @@ -34,15 +34,23 @@ public class HttpRequestParamsMatcher extends AbstractHttpRequestMatcher { /** * @param params The pattern of params : - *

    - *
  • name=value
  • - *
  • name
  • - *
+ *
    + *
  • name=value
  • + *
  • name
  • + *
*/ public HttpRequestParamsMatcher(String... params) { this.expressions = parseExpressions(params); } + private static Set parseExpressions(String... params) { + Set expressions = new LinkedHashSet<>(); + for (String param : params) { + expressions.add(new ParamExpression(param)); + } + return expressions; + } + @Override public boolean match(HttpRequest request) { if (CollectionUtils.isEmpty(expressions)) { @@ -56,14 +64,6 @@ public class HttpRequestParamsMatcher extends AbstractHttpRequestMatcher { return false; } - private static Set parseExpressions(String... params) { - Set expressions = new LinkedHashSet<>(); - for (String param : params) { - expressions.add(new ParamExpression(param)); - } - return expressions; - } - @Override protected Collection getContent() { return this.expressions; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java index e67d3545..1d2a2264 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestPathMatcher.java @@ -45,6 +45,17 @@ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher { this.pathMatcher = new AntPathMatcher(); } + private static Set prependLeadingSlash(String[] patterns) { + Set result = new LinkedHashSet<>(patterns.length); + for (String pattern : patterns) { + if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) { + pattern = "/" + pattern; + } + result.add(pattern); + } + return result; + } + @Override public boolean match(HttpRequest request) { List matches = getMatchingPatterns(request); @@ -94,17 +105,6 @@ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher { return uri.getPath(); } - private static Set prependLeadingSlash(String[] patterns) { - Set result = new LinkedHashSet<>(patterns.length); - for (String pattern : patterns) { - if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) { - pattern = "/" + pattern; - } - result.add(pattern); - } - return result; - } - @Override protected Collection getContent() { return this.patterns; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java index a2fb5b80..ea949aed 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestProducesMatcher.java @@ -70,26 +70,6 @@ public class HttpRequestProducesMatcher extends AbstractHttpRequestMatcher { Collections.sort(this.expressions); } - @Override - public boolean match(HttpRequest request) { - - if (expressions.isEmpty()) { - return true; - } - - HttpHeaders httpHeaders = request.getHeaders(); - - List acceptedMediaTypes = httpHeaders.getAccept(); - - for (ProduceMediaTypeExpression expression : expressions) { - if (!expression.match(acceptedMediaTypes)) { - return false; - } - } - - return true; - } - private static Set parseExpressions(String[] produces, String[] headers) { Set result = new LinkedHashSet<>(); @@ -111,6 +91,26 @@ public class HttpRequestProducesMatcher extends AbstractHttpRequestMatcher { return result; } + @Override + public boolean match(HttpRequest request) { + + if (expressions.isEmpty()) { + return true; + } + + HttpHeaders httpHeaders = request.getHeaders(); + + List acceptedMediaTypes = httpHeaders.getAccept(); + + for (ProduceMediaTypeExpression expression : expressions) { + if (!expression.match(acceptedMediaTypes)) { + return false; + } + } + + return true; + } + @Override protected Collection getContent() { return expressions; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java index 30652613..3b8257b1 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboProtocolConfigSupplier.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.function.Supplier; import org.apache.dubbo.config.ProtocolConfig; + import org.springframework.beans.factory.ObjectProvider; /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java index 38b00da8..b02094b9 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboRestServiceMetadata.java @@ -45,10 +45,12 @@ public class DubboRestServiceMetadata { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (!(o instanceof DubboRestServiceMetadata)) + } + 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/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java index c9d8b55a..6ce0e24c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/DubboTransportedMethodMetadata.java @@ -77,10 +77,12 @@ public class DubboTransportedMethodMetadata { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (!(o instanceof DubboTransportedMethodMetadata)) + } + if (!(o instanceof DubboTransportedMethodMetadata)) { return false; + } DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o; return Objects.equals(methodMetadata, that.methodMetadata) && Objects.equals(attributes, that.attributes); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java index a5e3bcc9..5fbc3d20 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodMetadata.java @@ -111,10 +111,12 @@ public class MethodMetadata { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; + } MethodMetadata that = (MethodMetadata) o; return Objects.equals(name, that.name) && Objects.equals(returnType, that.returnType) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java index 2b6e723d..56b79b27 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/MethodParameterMetadata.java @@ -61,10 +61,12 @@ public class MethodParameterMetadata { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; + } MethodParameterMetadata that = (MethodParameterMetadata) o; return index == that.index && Objects.equals(name, that.name) && Objects.equals(type, that.type); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java index 012a3ad0..6f2a88f3 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RequestMetadata.java @@ -16,6 +16,7 @@ */ package com.alibaba.cloud.dubbo.metadata; +import static com.alibaba.cloud.dubbo.http.util.HttpUtils.normalizePath; import static org.springframework.http.MediaType.parseMediaTypes; import java.util.ArrayList; @@ -36,8 +37,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import com.alibaba.cloud.dubbo.http.util.HttpUtils; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -74,6 +73,67 @@ public class RequestMetadata { headers(requestTemplate.headers()); } + /** + * Get the best matched {@link RequestMetadata} via specified {@link RequestMetadata} + * + * @param requestMetadataMap the source of {@link NavigableMap} + * @param requestMetadata the match object + * @return if not matched, return null + */ + public static RequestMetadata getBestMatch( + NavigableMap requestMetadataMap, + RequestMetadata requestMetadata) { + + RequestMetadata key = requestMetadata; + + RequestMetadata result = requestMetadataMap.get(key); + + if (result == null) { + SortedMap headMap = requestMetadataMap + .headMap(key, true); + result = headMap.isEmpty() ? null : requestMetadataMap.get(headMap.lastKey()); + } + + return result; + } + + private static void add(String key, String value, + MultiValueMap destination) { + destination.add(key, value); + } + + private static > void addAll(Map source, + MultiValueMap destination) { + for (Map.Entry entry : source.entrySet()) { + String key = entry.getKey(); + for (String value : entry.getValue()) { + add(key, value, destination); + } + } + } + + private static void mediaTypes(HttpHeaders httpHeaders, String headerName, + Collection destination) { + List value = httpHeaders.get(headerName); + List mediaTypes = parseMediaTypes(value); + destination.addAll(toMediaTypeValues(mediaTypes)); + } + + private static List toMediaTypeValues(List mediaTypes) { + List list = new ArrayList<>(mediaTypes.size()); + for (MediaType mediaType : mediaTypes) { + list.add(mediaType.toString()); + } + return list; + } + + private static List toMediaTypes(Collection mediaTypeValues) { + if (mediaTypeValues.isEmpty()) { + return Collections.singletonList(MediaType.ALL); + } + return parseMediaTypes(new LinkedList<>(mediaTypeValues)); + } + public String getMethod() { return method; } @@ -87,7 +147,7 @@ public class RequestMetadata { } public void setPath(String path) { - this.path = HttpUtils.normalizePath(path); + this.path = normalizePath(path); } public MultiValueMap getParams() { @@ -180,73 +240,14 @@ public class RequestMetadata { return this; } - /** - * Get the best matched {@link RequestMetadata} via specified {@link RequestMetadata} - * - * @param requestMetadataMap the source of {@link NavigableMap} - * @param requestMetadata the match object - * @return if not matched, return null - */ - public static RequestMetadata getBestMatch( - NavigableMap requestMetadataMap, - RequestMetadata requestMetadata) { - - RequestMetadata key = requestMetadata; - - RequestMetadata result = requestMetadataMap.get(key); - - if (result == null) { - SortedMap headMap = requestMetadataMap - .headMap(key, true); - result = headMap.isEmpty() ? null : requestMetadataMap.get(headMap.lastKey()); - } - - return result; - } - - private static void add(String key, String value, - MultiValueMap destination) { - destination.add(key, value); - } - - private static > void addAll(Map source, - MultiValueMap destination) { - for (Map.Entry entry : source.entrySet()) { - String key = entry.getKey(); - for (String value : entry.getValue()) { - add(key, value, destination); - } - } - } - - private static void mediaTypes(HttpHeaders httpHeaders, String headerName, - Collection destination) { - List value = httpHeaders.get(headerName); - List mediaTypes = parseMediaTypes(value); - destination.addAll(toMediaTypeValues(mediaTypes)); - } - - private static List toMediaTypeValues(List mediaTypes) { - List list = new ArrayList<>(mediaTypes.size()); - for (MediaType mediaType : mediaTypes) { - list.add(mediaType.toString()); - } - return list; - } - - private static List toMediaTypes(Collection mediaTypeValues) { - if (mediaTypeValues.isEmpty()) { - return Collections.singletonList(MediaType.ALL); - } - return parseMediaTypes(new LinkedList<>(mediaTypeValues)); - } - @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (!(o instanceof RequestMetadata)) + } + if (!(o instanceof RequestMetadata)) { return false; + } RequestMetadata that = (RequestMetadata) o; return Objects.equals(method, that.method) && Objects.equals(path, that.path) && Objects.equals(consumes, that.consumes) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java index d74fce13..fceec4e6 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/RestMethodMetadata.java @@ -184,10 +184,12 @@ public class RestMethodMetadata { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (!(o instanceof RestMethodMetadata)) + } + if (!(o instanceof RestMethodMetadata)) { return false; + } RestMethodMetadata that = (RestMethodMetadata) o; return queryMapEncoded == that.queryMapEncoded && Objects.equals(method, that.method) diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java index 64389371..e0c93d69 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/ServiceRestMetadata.java @@ -52,10 +52,12 @@ public class ServiceRestMetadata { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (!(o instanceof ServiceRestMetadata)) + } + if (!(o instanceof ServiceRestMetadata)) { return false; + } ServiceRestMetadata that = (ServiceRestMetadata) o; return Objects.equals(url, that.url) && Objects.equals(meta, that.meta); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java index e6f8c6cb..2c48be6d 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/repository/DubboServiceMetadataRepository.java @@ -30,9 +30,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; import static org.springframework.util.CollectionUtils.isEmpty; import static org.springframework.util.StringUtils.hasText; -import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -40,20 +38,25 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.PostConstruct; import org.apache.dubbo.common.URL; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.http.HttpRequest; import org.springframework.stereotype.Repository; -import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -62,11 +65,11 @@ import com.alibaba.cloud.dubbo.http.matcher.RequestMetadataMatcher; import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; import com.alibaba.cloud.dubbo.metadata.RequestMetadata; import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; +import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; import com.alibaba.cloud.dubbo.service.DubboMetadataService; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; import com.alibaba.cloud.dubbo.util.JSONUtils; - import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; @@ -76,7 +79,8 @@ import com.fasterxml.jackson.databind.type.TypeFactory; * @author Mercy */ @Repository -public class DubboServiceMetadataRepository { +public class DubboServiceMetadataRepository + implements SmartInitializingSingleton, ApplicationEventPublisherAware { /** * The prefix of {@link DubboMetadataService} : "dubbo.metadata-service." @@ -99,9 +103,14 @@ public class DubboServiceMetadataRepository { private final ObjectMapper objectMapper = new ObjectMapper(); - // =================================== Registration - // =================================== // - + /** + * Monitor object for synchronization + */ + private final Object monitor = new Object(); + /** + * A {@link Set} of service names that had been initialized + */ + private final Set initializedServices = new LinkedHashSet<>(); /** * All exported {@link URL urls} {@link Map} whose key is the return value of * {@link URL#getServiceKey()} method and value is the {@link List} of {@link URL @@ -109,14 +118,8 @@ public class DubboServiceMetadataRepository { */ private final MultiValueMap allExportedURLs = new LinkedMultiValueMap<>(); - // ==================================================================================== - // // - - // =================================== Subscription + // =================================== Registration // =================================== // - - 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 @@ -127,16 +130,22 @@ public class DubboServiceMetadataRepository { // ==================================================================================== // // - // =================================== REST Metadata - // ================================== // - + // =================================== Subscription + // =================================== // /** * A Map to store REST metadata temporary, its' key is the special service name for a * Dubbo service, the value is a JSON content of JAX-RS or Spring MVC REST metadata * from the annotated methods. */ private final Set serviceRestMetadata = new LinkedHashSet<>(); + private ApplicationEventPublisher applicationEventPublisher; + // ==================================================================================== + // // + + // =================================== REST Metadata + // ================================== // + private volatile Set subscribedServices = emptySet(); /** * Key is application name Value is Map */ @@ -172,12 +181,114 @@ public class DubboServiceMetadataRepository { // ==================================================================================== // // + private static Map getMap(Map> repository, + String key) { + return getOrDefault(repository, key, newHashMap()); + } + + private static V getOrDefault(Map source, K key, V defaultValue) { + V value = source.get(key); + if (value == null) { + value = defaultValue; + source.put(key, value); + } + return value; + } + + private static Map newHashMap() { + return new LinkedHashMap<>(); + } + + /** + * Initialize {@link #subscribedServices the subscribed services} + * + * @return + */ @PostConstruct - public void init() { - // Keep the order in following invocations - initSubscribedServices(); - initSubscribedDubboMetadataServices(); - initDubboRestServiceMetadataRepository(); + public Stream initSubscribedServices() { + Set newSubscribedServices = new LinkedHashSet<>(); + + // If subscribes all services + if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) { + List services = discoveryClient.getServices(); + newSubscribedServices.addAll(services); + if (logger.isWarnEnabled()) { + logger.warn( + "Current application will subscribe all services(size:{}) in registry, " + + "a lot of memory and CPU cycles may be used, " + + "thus it's strongly recommend you using the externalized property '{}' " + + "to specify the services", + newSubscribedServices.size(), "dubbo.cloud.subscribed-services"); + } + } + else { + newSubscribedServices.addAll(dubboCloudProperties.subscribedServices()); + } + + // exclude current application name + excludeSelf(newSubscribedServices); + + // copy from subscribedServices + Set oldSubscribedServices = this.subscribedServices; + + // volatile update subscribedServices to be new one + this.subscribedServices = newSubscribedServices; + + // dispatch SubscribedServicesChangedEvent + dispatchEvent(new SubscribedServicesChangedEvent(this, oldSubscribedServices, + newSubscribedServices)); + + // clear old one, help GC + oldSubscribedServices.clear(); + + return newSubscribedServices.stream(); + } + + private void dispatchEvent(ApplicationEvent event) { + applicationEventPublisher.publishEvent(event); + } + + @Override + public void afterSingletonsInstantiated() { + initializeMetadata(); + } + + /** + * Initialize the metadata + */ + private void initializeMetadata() { + doGetSubscribedServices().forEach(this::initializeMetadata); + if (logger.isInfoEnabled()) { + logger.info("The metadata of Dubbo services has been initialized"); + } + } + + /** + * Initialize the metadata of Dubbo Services + */ + public void initializeMetadata(String serviceName) { + synchronized (monitor) { + if (initializedServices.contains(serviceName)) { + if (logger.isDebugEnabled()) { + logger.debug( + "The metadata of Dubbo service[name : {}] has been initialized", + serviceName); + } + } + else { + if (logger.isInfoEnabled()) { + logger.info( + "The metadata of Dubbo service[name : {}] is about to be initialized", + serviceName); + } + + // Keep the order in following invocations + initSubscribedDubboMetadataService(serviceName); + initDubboRestServiceMetadataRepository(serviceName); + // mark this service name having been initialized + initializedServices.add(serviceName); + } + } } /** @@ -254,19 +365,15 @@ public class DubboServiceMetadataRepository { 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); + + List urls = null; + + synchronized (monitor) { + urls = subscribedDubboMetadataServiceURLs.get(serviceKey); + } if (isEmpty(urls)) { return emptyList(); @@ -286,7 +393,7 @@ public class DubboServiceMetadataRepository { * @return */ public boolean isSubscribedService(String serviceName) { - return subscribedServices.contains(serviceName); + return doGetSubscribedServices().contains(serviceName); } public void exportURL(URL url) { @@ -363,7 +470,7 @@ public class DubboServiceMetadataRepository { * * @param serviceName the service name */ - public void initialize(String serviceName) { + protected void initDubboRestServiceMetadataRepository(String serviceName) { if (dubboRestServiceMetadataRepository.containsKey(serviceName)) { return; @@ -416,8 +523,16 @@ public class DubboServiceMetadataRepository { return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata); } + /** + * @return not-null + */ + protected Set doGetSubscribedServices() { + Set subscribedServices = this.subscribedServices; + return subscribedServices == null ? emptySet() : subscribedServices; + } + public Set getSubscribedServices() { - return Collections.unmodifiableSet(subscribedServices); + return unmodifiableSet(doGetSubscribedServices()); } private T match(Map> repository, @@ -489,66 +604,30 @@ public class DubboServiceMetadataRepository { return metadata; } - private static Map getMap(Map> repository, - String key) { - return getOrDefault(repository, key, newHashMap()); - } - - private static V getOrDefault(Map source, K key, V defaultValue) { - V value = source.get(key); - if (value == null) { - value = defaultValue; - source.put(key, value); - } - return value; - } - - private static Map newHashMap() { - return new LinkedHashMap<>(); - } - - private void initSubscribedServices() { - // If subscribes all services - 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()); - } - - excludeSelf(subscribedServices); - } - private void excludeSelf(Set subscribedServices) { subscribedServices.remove(currentApplicationName); } - private void initSubscribedDubboMetadataServices() { - // clear subscribedDubboMetadataServiceURLs - subscribedDubboMetadataServiceURLs.clear(); - - subscribedServices.stream().map(discoveryClient::getInstances) - .filter(this::isNotEmpty).forEach(serviceInstances -> { - ServiceInstance serviceInstance = serviceInstances.get(0); - getDubboMetadataServiceURLs(serviceInstance) - .forEach(dubboMetadataServiceURL -> { - initSubscribedDubboMetadataServiceURLs( - dubboMetadataServiceURL); - initDubboMetadataServiceProxy(dubboMetadataServiceURL); - }); + protected void initSubscribedDubboMetadataService(String serviceName) { + discoveryClient.getInstances(serviceName).stream().findAny() + .map(this::getDubboMetadataServiceURLs) + .ifPresent(dubboMetadataServiceURLs -> { + dubboMetadataServiceURLs.forEach(dubboMetadataServiceURL -> { + try { + initSubscribedDubboMetadataServiceURL( + dubboMetadataServiceURL); + initDubboMetadataServiceProxy(dubboMetadataServiceURL); + } + catch (Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + }); }); } - private void initSubscribedDubboMetadataServiceURLs(URL dubboMetadataServiceURL) { + private void initSubscribedDubboMetadataServiceURL(URL dubboMetadataServiceURL) { // add subscriptions String serviceKey = dubboMetadataServiceURL.getServiceKey(); subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL); @@ -561,11 +640,9 @@ public class DubboServiceMetadataRepository { dubboMetadataConfigServiceProxy.initProxy(serviceName, version); } - private void initDubboRestServiceMetadataRepository() { - subscribedServices.forEach(this::initialize); - } - - private boolean isNotEmpty(Collection collection) { - return !CollectionUtils.isEmpty(collection); + @Override + public void setApplicationEventPublisher( + ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java index 5dd97023..ce5c0d30 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboServiceBeanMetadataResolver.java @@ -29,6 +29,7 @@ import java.util.stream.Stream; import org.apache.dubbo.common.URL; import org.apache.dubbo.config.spring.ServiceBean; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.ObjectProvider; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java index 48dbe609..3242dc85 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/DubboInvocationHandler.java @@ -23,6 +23,7 @@ import java.lang.reflect.Method; import java.util.Map; import org.apache.dubbo.rpc.service.GenericService; + import org.springframework.util.ClassUtils; import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java index b3220653..c2b335d5 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/openfeign/TargeterInvocationHandler.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.dubbo.rpc.service.GenericService; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FeignContext; @@ -77,6 +78,10 @@ class TargeterInvocationHandler implements InvocationHandler { this.contextFactory = contextFactory; } + private static T cast(Object object) { + return (T) object; + } + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /** @@ -134,7 +139,7 @@ class TargeterInvocationHandler implements InvocationHandler { } // Update Metadata - repository.initialize(serviceName); + repository.initializeMetadata(serviceName); Map feignMethodMetadataMap = getFeignMethodMetadataMap( serviceName, feignRestMethodMetadataMap); @@ -180,8 +185,4 @@ class TargeterInvocationHandler implements InvocationHandler { return feignMethodMetadataMap; } - - private static T cast(Object object) { - return (T) object; - } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java index 8cc800ab..922553ab 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java @@ -16,36 +16,41 @@ */ package com.alibaba.cloud.dubbo.registry; +import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; +import static org.apache.dubbo.common.URLBuilder.from; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL; import static org.springframework.util.StringUtils.hasText; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.Set; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.RegistryFactory; import org.apache.dubbo.registry.support.FailbackRegistry; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.util.CollectionUtils; import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; import com.alibaba.cloud.dubbo.service.DubboMetadataService; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; import com.alibaba.cloud.dubbo.util.JSONUtils; @@ -65,8 +70,10 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class .getName(); - - private static final Set SCHEDULER_TASKS = new HashSet<>(); + /** + * Caches the IDs of {@link ApplicationListener} + */ + private static final Set registerListeners = new HashSet<>(); protected final Logger logger = LoggerFactory.getLogger(getClass()); @@ -83,12 +90,12 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { private final JSONUtils jsonUtils; - protected final ScheduledExecutorService servicesLookupScheduler; + private final ConfigurableApplicationContext applicationContext; public AbstractSpringCloudRegistry(URL url, DiscoveryClient discoveryClient, DubboServiceMetadataRepository dubboServiceMetadataRepository, DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, - JSONUtils jsonUtils, ScheduledExecutorService servicesLookupScheduler) { + JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) { super(url); this.servicesLookupInterval = url .getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L); @@ -96,7 +103,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { this.repository = dubboServiceMetadataRepository; this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy; this.jsonUtils = jsonUtils; - this.servicesLookupScheduler = servicesLookupScheduler; + this.applicationContext = applicationContext; } protected boolean shouldRegister(URL url) { @@ -161,60 +168,137 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { doSubscribeDubboServiceURLs(url, listener); - submitSchedulerTaskIfAbsent(url, listener); + registerServiceInstancesChangedEventListener(url, listener); } - private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) { - String taskId = url.toIdentityString(); - if (SCHEDULER_TASKS.add(taskId)) { - schedule(() -> doSubscribeDubboServiceURLs(url, listener)); + /** + * Register a {@link ApplicationListener listener} for + * {@link ServiceInstancesChangedEvent} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + */ + private void registerServiceInstancesChangedEventListener(URL url, + NotifyListener listener) { + String listenerId = generateId(url); + if (registerListeners.add(listenerId)) { + applicationContext.addApplicationListener( + new ApplicationListener() { + @Override + public void onApplicationEvent( + ServiceInstancesChangedEvent event) { + String serviceName = event.getServiceName(); + Collection serviceInstances = event + .getServiceInstances(); + subscribeDubboServiceURL(url, listener, serviceName, + s -> serviceInstances); + } + }); } } - protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { + private void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { Set subscribedServices = repository.getSubscribedServices(); + // Sync + subscribedServices.forEach(service -> subscribeDubboServiceURL(url, listener, + service, this::getServiceInstances)); + } - subscribedServices.stream().map(dubboMetadataConfigServiceProxy::getProxy) - .filter(Objects::nonNull).forEach(dubboMetadataService -> { - List exportedURLs = getExportedURLs(dubboMetadataService, url); - List allSubscribedURLs = new LinkedList<>(); - for (URL exportedURL : exportedURLs) { - String serviceName = exportedURL.getParameter(APPLICATION_KEY); - List serviceInstances = getServiceInstances( - 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); - } - }); + protected void subscribeDubboServiceURL(URL url, NotifyListener listener, + String serviceName, + Function> serviceInstancesFunction) { - if (logger.isDebugEnabled()) { - logger.debug( - "The subscribed URL[{}] will notify all URLs : {}", - url, subscribedURLs); + if (logger.isInfoEnabled()) { + logger.info( + "The Dubbo Service URL[ID : {}] is being subscribed for service[name : {}]", + generateId(url), serviceName); + } + + DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy + .getProxy(serviceName); + + if (dubboMetadataService == null) { // If not found, try to initialize + if (logger.isInfoEnabled()) { + logger.info( + "The metadata of Dubbo service[key : {}] can't be found when the subscribed service[name : {}], " + + "and then try to initialize it", + url.getServiceKey(), serviceName); + } + repository.initializeMetadata(serviceName); + dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName); + } + + if (dubboMetadataService == null) { // It makes sure not-found, return immediately + if (logger.isWarnEnabled()) { + logger.warn( + "The metadata of Dubbo service[key : {}] still can't be found, it could effect the further " + + "Dubbo service invocation", + url.getServiceKey()); + } + return; + } + + Collection serviceInstances = serviceInstancesFunction + .apply(serviceName); + + List allSubscribedURLs = new LinkedList<>(); + + if (CollectionUtils.isEmpty(serviceInstances)) { + if (logger.isWarnEnabled()) { + logger.warn( + "There is no instance from service[name : {}], and then Dubbo Service[key : {}] will not be " + + "available , please make sure the further impact", + serviceName, url.getServiceKey()); + } + /** + * URLs with {@link RegistryConstants#EMPTY_PROTOCOL} + */ + allSubscribedURLs.addAll(emptyURLs(url)); + } + else { + List exportedURLs = getExportedURLs(dubboMetadataService, url); + + for (URL exportedURL : exportedURLs) { + String protocol = exportedURL.getProtocol(); + List subscribedURLs = new LinkedList<>(); + serviceInstances.forEach(serviceInstance -> { + Integer port = repository.getDubboProtocolPort(serviceInstance, + protocol); + String host = serviceInstance.getHost(); + if (port == null) { + if (logger.isWarnEnabled()) { + logger.warn( + "The protocol[{}] port of Dubbo service instance[host : {}] " + + "can't be resolved", + protocol, host); } - - allSubscribedURLs.addAll(subscribedURLs); } - - listener.notify(allSubscribedURLs); + else { + URL subscribedURL = new URL(protocol, host, port, + exportedURL.getParameters()); + subscribedURLs.add(subscribedURL); + } }); + + allSubscribedURLs.addAll(subscribedURLs); + } + } + + if (logger.isDebugEnabled()) { + logger.debug("The subscribed URL[{}] will notify all URLs : {}", url, + allSubscribedURLs); + } + + listener.notify(allSubscribedURLs); + } + + private String generateId(URL url) { + return url.toString(VERSION_KEY, GROUP_KEY, PROTOCOL_KEY); + } + + private List emptyURLs(URL url) { + return asList(from(url).setProtocol(EMPTY_PROTOCOL).build()); } private List getServiceInstances(String serviceName) { @@ -262,7 +346,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { @Override public final void doUnsubscribe(URL url, NotifyListener listener) { if (isAdminURL(url)) { - shutdownServiceNamesLookup(); } } @@ -271,12 +354,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { return !discoveryClient.getServices().isEmpty(); } - protected void shutdownServiceNamesLookup() { - if (servicesLookupScheduler != null) { - servicesLookupScheduler.shutdown(); - } - } - protected boolean isAdminURL(URL url) { return ADMIN_PROTOCOL.equals(url.getProtocol()); } @@ -284,9 +361,4 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { protected boolean isDubboMetadataServiceURL(URL url) { return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); } - - protected ScheduledFuture schedule(Runnable runnable) { - return this.servicesLookupScheduler.scheduleAtFixedRate(runnable, - servicesLookupInterval, servicesLookupInterval, TimeUnit.SECONDS); - } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java index 72b33545..be9039ae 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java @@ -16,11 +16,11 @@ */ package com.alibaba.cloud.dubbo.registry; -import java.util.concurrent.ScheduledExecutorService; - import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.RegistryFactory; + import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.ConfigurableApplicationContext; import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; @@ -39,9 +39,9 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient, DubboServiceMetadataRepository dubboServiceMetadataRepository, DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, - JSONUtils jsonUtils, ScheduledExecutorService servicesLookupScheduler) { + JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) { super(url, discoveryClient, dubboServiceMetadataRepository, - dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler); + dubboMetadataConfigServiceProxy, jsonUtils, applicationContext); this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java index 0911701e..ca0e1dc1 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java @@ -17,14 +17,11 @@ package com.alibaba.cloud.dubbo.registry; import static java.lang.System.getProperty; -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; - -import java.util.concurrent.ScheduledExecutorService; 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.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.ConfigurableApplicationContext; @@ -52,8 +49,6 @@ public class SpringCloudRegistryFactory implements RegistryFactory { private static ConfigurableApplicationContext applicationContext; - private final ScheduledExecutorService servicesLookupScheduler; - private DiscoveryClient discoveryClient; private DubboServiceMetadataRepository dubboServiceMetadataRepository; @@ -65,8 +60,11 @@ public class SpringCloudRegistryFactory implements RegistryFactory { private volatile boolean initialized = false; public SpringCloudRegistryFactory() { - servicesLookupScheduler = newSingleThreadScheduledExecutor( - new NamedThreadFactory(SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX)); + } + + public static void setApplicationContext( + ConfigurableApplicationContext applicationContext) { + SpringCloudRegistryFactory.applicationContext = applicationContext; } protected void init() { @@ -86,11 +84,6 @@ public class SpringCloudRegistryFactory implements RegistryFactory { init(); return new SpringCloudRegistry(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, - jsonUtils, servicesLookupScheduler); - } - - public static void setApplicationContext( - ConfigurableApplicationContext applicationContext) { - SpringCloudRegistryFactory.applicationContext = applicationContext; + jsonUtils, applicationContext); } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java index 46833d95..0e5a0a2a 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java @@ -16,10 +16,9 @@ */ package com.alibaba.cloud.dubbo.registry.event; -import java.util.EventObject; - import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationEvent; /** * The after-{@link ServiceRegistry#register(Registration) register} event for @@ -27,7 +26,7 @@ import org.springframework.cloud.client.serviceregistry.ServiceRegistry; * * @author Mercy */ -public class ServiceInstanceRegisteredEvent extends EventObject { +public class ServiceInstanceRegisteredEvent extends ApplicationEvent { public ServiceInstanceRegisteredEvent(Registration source) { super(source); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java new file mode 100644 index 00000000..2123b485 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java @@ -0,0 +1,89 @@ +/* + * 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 com.alibaba.cloud.dubbo.registry.event; + +import static java.util.Collections.unmodifiableCollection; + +import java.util.Collection; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.event.ApplicationEventMulticaster; +import org.springframework.context.event.SimpleApplicationEventMulticaster; + +/** + * An event raised after the {@link ServiceInstance instances} of one service has been + * changed. + * + * @author Mercy + */ +public class ServiceInstancesChangedEvent extends ApplicationEvent { + + private final String serviceName; + + private final Collection serviceInstances; + + /** + * Current event has been processed or not. Typically, Spring Event was based on sync + * {@link ApplicationEventMulticaster} + * + * @see SimpleApplicationEventMulticaster + */ + private boolean processed = false; + + /** + * @param serviceName The name of service that was changed + * @param serviceInstances all {@link ServiceInstance service instances} + * @throws IllegalArgumentException if source is null. + */ + public ServiceInstancesChangedEvent(String serviceName, + Collection serviceInstances) { + super(serviceName); + this.serviceName = serviceName; + this.serviceInstances = unmodifiableCollection(serviceInstances); + } + + /** + * @return The name of service that was changed + */ + public String getServiceName() { + return serviceName; + } + + /** + * @return all {@link ServiceInstance service instances} + */ + public Collection getServiceInstances() { + return serviceInstances; + } + + /** + * Mark current event being processed + */ + public void processed() { + processed = true; + } + + /** + * Current event has been processed or not + * + * @return if processed, return true, or false + */ + public boolean isProcessed() { + return processed; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java new file mode 100644 index 00000000..384d8a1c --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/SubscribedServicesChangedEvent.java @@ -0,0 +1,66 @@ +/* + * 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 com.alibaba.cloud.dubbo.registry.event; + +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; + +import org.springframework.context.ApplicationEvent; + +/** + * {@link ApplicationEvent Event} raised when the subscribed services are changed + *

+ * + * @author Mercy + * @see ApplicationEvent + */ +public class SubscribedServicesChangedEvent extends ApplicationEvent { + + private final Set oldSubscribedServices; + + private final Set newSubscribedServices; + + private final boolean changed; + + /** + * Create a new ApplicationEvent. + * + * @param source the object on which the event initially occurred (never {@code null}) + * @param oldSubscribedServices the subscribed services before changed + * @param newSubscribedServices the subscribed services after changed + */ + public SubscribedServicesChangedEvent(Object source, + Set oldSubscribedServices, Set newSubscribedServices) { + super(source); + this.oldSubscribedServices = new LinkedHashSet<>(oldSubscribedServices); + this.newSubscribedServices = new LinkedHashSet<>(newSubscribedServices); + this.changed = !Objects.equals(oldSubscribedServices, newSubscribedServices); + } + + public Set getOldSubscribedServices() { + return oldSubscribedServices; + } + + public Set getNewSubscribedServices() { + return newSubscribedServices; + } + + public boolean isChanged() { + return changed; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java index 1ebe05cc..b96ce36c 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboGenericServiceFactory.java @@ -36,6 +36,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.rpc.service.GenericService; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.MutablePropertyValues; @@ -118,6 +119,7 @@ public class DubboGenericServiceFactory { dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() { + @Override public void setAsText(String text) throws java.lang.IllegalArgumentException { // Trim all whitespace @@ -164,4 +166,4 @@ public class DubboGenericServiceFactory { } } -} \ No newline at end of file +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java index b2be876b..d8a248e2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceExporter.java @@ -25,6 +25,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ServiceConfig; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java index c634a8c0..ca4b05f6 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceInvocationHandler.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.util.stream.Stream; import org.apache.dubbo.rpc.service.GenericService; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java index bd19d0af..21c019c2 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/DubboMetadataServiceProxy.java @@ -26,14 +26,14 @@ import org.springframework.beans.factory.DisposableBean; /** * The proxy of {@link DubboMetadataService} + * + * @author Mercy */ public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean { private final DubboGenericServiceFactory dubboGenericServiceFactory; - - private ClassLoader classLoader; - private final Map dubboMetadataServiceCache = new ConcurrentHashMap<>(); + private ClassLoader classLoader; public DubboMetadataServiceProxy( DubboGenericServiceFactory dubboGenericServiceFactory) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java index 400f6a63..b4d8cc20 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/IntrospectiveDubboMetadataService.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import org.apache.dubbo.common.URL; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -95,4 +96,4 @@ public class IntrospectiveDubboMetadataService implements DubboMetadataService { private DubboServiceMetadataRepository getRepository() { return dubboServiceMetadataRepository.getIfAvailable(); } -} \ No newline at end of file +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java index 8b6b1d6b..4d63363e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/AbstractDubboGenericServiceParameterResolver.java @@ -58,15 +58,15 @@ public abstract class AbstractDubboGenericServiceParameterResolver this.classLoader = classLoader; } - public void setOrder(int order) { - this.order = order; - } - @Override public int getOrder() { return order; } + public void setOrder(int order) { + this.order = order; + } + protected Class resolveClass(String className) { return resolveClassName(className, classLoader); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java index c04f687f..9fc4a609 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/service/parameter/DubboGenericServiceParameterResolver.java @@ -17,6 +17,7 @@ package com.alibaba.cloud.dubbo.service.parameter; import org.apache.dubbo.rpc.service.GenericService; + import org.springframework.core.Ordered; import com.alibaba.cloud.dubbo.http.HttpServerRequest; diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java index 1aa8ce64..94071d03 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/util/JSONUtils.java @@ -25,6 +25,7 @@ import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.apache.dubbo.common.URL; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; 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 dbaa6c57..5969971e 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 @@ -4,7 +4,8 @@ com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\ com.alibaba.cloud.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\ -com.alibaba.cloud.dubbo.autoconfigure.DubboServiceAutoConfiguration +com.alibaba.cloud.dubbo.autoconfigure.DubboServiceAutoConfiguration,\ +com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\ com.alibaba.cloud.dubbo.actuate.DubboMetadataEndpointAutoConfiguration diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpressionTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpressionTest.java index 996ce682..dcdc92ed 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpressionTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpressionTest.java @@ -16,14 +16,14 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import java.lang.reflect.Constructor; - import org.junit.Assert; import org.junit.Test; import org.springframework.beans.BeanUtils; import org.springframework.core.ResolvableType; import org.springframework.http.MediaType; +import java.lang.reflect.Constructor; + /** * {@link AbstractMediaTypeExpression} Test * @@ -31,45 +31,41 @@ import org.springframework.http.MediaType; */ public abstract class AbstractMediaTypeExpressionTest { - protected T createExpression(String expression) { - ResolvableType resolvableType = ResolvableType - .forType(getClass().getGenericSuperclass()); - Class firstGenericType = (Class) resolvableType.resolveGeneric(0); - Constructor constructor = null; - try { - constructor = firstGenericType.getDeclaredConstructor(String.class); - } - catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - return BeanUtils.instantiateClass(constructor, expression); - } + protected T createExpression(String expression) { + ResolvableType resolvableType = ResolvableType.forType(getClass().getGenericSuperclass()); + Class firstGenericType = (Class) resolvableType.resolveGeneric(0); + Constructor constructor = null; + try { + constructor = firstGenericType.getDeclaredConstructor(String.class); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + return BeanUtils.instantiateClass(constructor, expression); + } - @Test - public void testGetMediaTypeAndNegated() { - // Normal - AbstractMediaTypeExpression expression = createExpression( - MediaType.APPLICATION_JSON_VALUE); - Assert.assertEquals(MediaType.APPLICATION_JSON, expression.getMediaType()); - Assert.assertFalse(expression.isNegated()); + @Test + public void testGetMediaTypeAndNegated() { + // Normal + AbstractMediaTypeExpression expression = createExpression(MediaType.APPLICATION_JSON_VALUE); + Assert.assertEquals(MediaType.APPLICATION_JSON, expression.getMediaType()); + Assert.assertFalse(expression.isNegated()); - // Negated - expression = createExpression("!" + MediaType.APPLICATION_JSON_VALUE); - Assert.assertEquals(MediaType.APPLICATION_JSON, expression.getMediaType()); - Assert.assertTrue(expression.isNegated()); - } + // Negated + expression = createExpression("!" + MediaType.APPLICATION_JSON_VALUE); + Assert.assertEquals(MediaType.APPLICATION_JSON, expression.getMediaType()); + Assert.assertTrue(expression.isNegated()); + } - @Test - public void testEqualsAndHashCode() { - Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE), - createExpression(MediaType.APPLICATION_JSON_VALUE)); - Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode(), - createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode()); - } + @Test + public void testEqualsAndHashCode() { + Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE), createExpression(MediaType.APPLICATION_JSON_VALUE)); + Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode(), + createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode()); + } - @Test - public void testCompareTo() { - Assert.assertEquals(0, createExpression(MediaType.APPLICATION_JSON_VALUE) - .compareTo(createExpression(MediaType.APPLICATION_JSON_VALUE))); - } + @Test + public void testCompareTo() { + Assert.assertEquals(0, + createExpression(MediaType.APPLICATION_JSON_VALUE).compareTo(createExpression(MediaType.APPLICATION_JSON_VALUE))); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpressionTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpressionTest.java index e59b4b47..336d8843 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpressionTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpressionTest.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import java.lang.reflect.Constructor; - import org.junit.Assert; import org.junit.Test; import org.springframework.beans.BeanUtils; import org.springframework.core.ResolvableType; +import java.lang.reflect.Constructor; + /** * {@link AbstractNameValueExpression} Test * @@ -30,53 +30,48 @@ import org.springframework.core.ResolvableType; */ public abstract class AbstractNameValueExpressionTest { - protected T createExpression(String expression) { - ResolvableType resolvableType = ResolvableType - .forType(getClass().getGenericSuperclass()); - Class firstGenericType = (Class) resolvableType.resolveGeneric(0); - Constructor constructor = null; - try { - constructor = firstGenericType.getDeclaredConstructor(String.class); - } - catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - return BeanUtils.instantiateClass(constructor, expression); - } + protected T createExpression(String expression) { + ResolvableType resolvableType = ResolvableType.forType(getClass().getGenericSuperclass()); + Class firstGenericType = (Class) resolvableType.resolveGeneric(0); + Constructor constructor = null; + try { + constructor = firstGenericType.getDeclaredConstructor(String.class); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + return BeanUtils.instantiateClass(constructor, expression); + } - @Test - public void testGetNameAndValue() { - // Normal Name and value - AbstractNameValueExpression expression = createExpression("a=1"); - Assert.assertEquals("a", expression.getName()); - Assert.assertFalse(expression.isNegated()); + @Test + public void testGetNameAndValue() { + // Normal Name and value + AbstractNameValueExpression expression = createExpression("a=1"); + Assert.assertEquals("a", expression.getName()); + Assert.assertFalse(expression.isNegated()); - expression = createExpression("a=1"); - Assert.assertEquals("a", expression.getName()); - Assert.assertEquals("1", expression.getValue()); - Assert.assertFalse(expression.isNegated()); + expression = createExpression("a=1"); + Assert.assertEquals("a", expression.getName()); + Assert.assertEquals("1", expression.getValue()); + Assert.assertFalse(expression.isNegated()); - // Negated Name - expression = createExpression("!a"); - Assert.assertEquals("a", expression.getName()); - Assert.assertTrue(expression.isNegated()); + // Negated Name + expression = createExpression("!a"); + Assert.assertEquals("a", expression.getName()); + Assert.assertTrue(expression.isNegated()); - expression = createExpression("a!=1"); - Assert.assertEquals("a", expression.getName()); - Assert.assertEquals("1", expression.getValue()); - Assert.assertTrue(expression.isNegated()); - } + expression = createExpression("a!=1"); + Assert.assertEquals("a", expression.getName()); + Assert.assertEquals("1", expression.getValue()); + Assert.assertTrue(expression.isNegated()); + } - @Test - public void testEqualsAndHashCode() { - Assert.assertEquals(createExpression("a"), createExpression("a")); - Assert.assertEquals(createExpression("a").hashCode(), - createExpression("a").hashCode()); - Assert.assertEquals(createExpression("a=1"), createExpression("a = 1 ")); - Assert.assertEquals(createExpression("a=1").hashCode(), - createExpression("a = 1 ").hashCode()); - Assert.assertNotEquals(createExpression("a"), createExpression("b")); - Assert.assertNotEquals(createExpression("a").hashCode(), - createExpression("b").hashCode()); - } + @Test + public void testEqualsAndHashCode() { + Assert.assertEquals(createExpression("a"), createExpression("a")); + Assert.assertEquals(createExpression("a").hashCode(), createExpression("a").hashCode()); + Assert.assertEquals(createExpression("a=1"), createExpression("a = 1 ")); + Assert.assertEquals(createExpression("a=1").hashCode(), createExpression("a = 1 ").hashCode()); + Assert.assertNotEquals(createExpression("a"), createExpression("b")); + Assert.assertNotEquals(createExpression("a").hashCode(), createExpression("b").hashCode()); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpressionTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpressionTest.java index 93d4eefd..144332c8 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpressionTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ConsumeMediaTypeExpressionTest.java @@ -25,22 +25,21 @@ import org.springframework.http.MediaType; * * @author Mercy */ -public class ConsumeMediaTypeExpressionTest - extends AbstractMediaTypeExpressionTest { +public class ConsumeMediaTypeExpressionTest extends AbstractMediaTypeExpressionTest { - @Test - public void testMatch() { - ConsumeMediaTypeExpression expression = createExpression(MediaType.ALL_VALUE); + @Test + public void testMatch() { + ConsumeMediaTypeExpression expression = createExpression(MediaType.ALL_VALUE); - Assert.assertTrue(expression.match(MediaType.APPLICATION_JSON_UTF8)); + Assert.assertTrue(expression.match(MediaType.APPLICATION_JSON_UTF8)); - expression = createExpression(MediaType.APPLICATION_JSON_VALUE); - Assert.assertTrue(expression.match(MediaType.APPLICATION_JSON_UTF8)); + expression = createExpression(MediaType.APPLICATION_JSON_VALUE); + Assert.assertTrue(expression.match(MediaType.APPLICATION_JSON_UTF8)); - expression = createExpression(MediaType.APPLICATION_JSON_VALUE + ";q=0.7"); - Assert.assertTrue(expression.match(MediaType.APPLICATION_JSON_UTF8)); + expression = createExpression(MediaType.APPLICATION_JSON_VALUE + ";q=0.7"); + Assert.assertTrue(expression.match(MediaType.APPLICATION_JSON_UTF8)); - expression = createExpression(MediaType.TEXT_HTML_VALUE); - Assert.assertFalse(expression.match(MediaType.APPLICATION_JSON_UTF8)); - } + expression = createExpression(MediaType.TEXT_HTML_VALUE); + Assert.assertFalse(expression.match(MediaType.APPLICATION_JSON_UTF8)); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpressionTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpressionTest.java index 27f8ddad..69ff08ab 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpressionTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HeaderExpressionTest.java @@ -20,42 +20,41 @@ import org.junit.Assert; import org.junit.Test; import org.springframework.http.HttpRequest; -import com.alibaba.cloud.dubbo.http.DefaultHttpRequest; +import static com.alibaba.cloud.dubbo.http.DefaultHttpRequest.builder; /** * {@link HeaderExpression} Test * * @author Mercy */ -public class HeaderExpressionTest - extends AbstractNameValueExpressionTest { +public class HeaderExpressionTest extends AbstractNameValueExpressionTest { - @Test - public void testIsCaseSensitiveName() { - Assert.assertFalse(createExpression("a=1").isCaseSensitiveName()); - Assert.assertFalse(createExpression("a=!1").isCaseSensitiveName()); - Assert.assertFalse(createExpression("b=1").isCaseSensitiveName()); - } + @Test + public void testIsCaseSensitiveName() { + Assert.assertFalse(createExpression("a=1").isCaseSensitiveName()); + Assert.assertFalse(createExpression("a=!1").isCaseSensitiveName()); + Assert.assertFalse(createExpression("b=1").isCaseSensitiveName()); + } - @Test - public void testMatch() { + @Test + public void testMatch() { - HeaderExpression expression = createExpression("a=1"); - HttpRequest request = DefaultHttpRequest.builder().build(); + HeaderExpression expression = createExpression("a=1"); + HttpRequest request = builder().build(); - Assert.assertFalse(expression.match(request)); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().header("a", "").build(); - Assert.assertFalse(expression.match(request)); + request = builder().header("a", "").build(); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().header("a", "2").build(); - Assert.assertFalse(expression.match(request)); + request = builder().header("a", "2").build(); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().header("", "1").build(); - Assert.assertFalse(expression.match(request)); + request = builder().header("", "1").build(); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().header("a", "1").build(); - Assert.assertTrue(expression.match(request)); - } + request = builder().header("a", "1").build(); + Assert.assertTrue(expression.match(request)); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcherTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcherTest.java index 95e2cad4..1da5db43 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcherTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestMethodsMatcherTest.java @@ -16,37 +16,34 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import java.util.Arrays; -import java.util.HashSet; - import org.junit.Assert; import org.springframework.http.HttpMethod; +import java.util.Arrays; +import java.util.HashSet; + /** * {@link HttpRequestMethodsMatcher} Test * * @author Mercy */ -public class HttpRequestMethodsMatcherTest - extends AbstractHttpRequestMatcherTest { +public class HttpRequestMethodsMatcherTest extends AbstractHttpRequestMatcherTest { - HttpRequestMethodsMatcher matcher = new HttpRequestMethodsMatcher("GET"); + HttpRequestMethodsMatcher matcher = new HttpRequestMethodsMatcher("GET"); - @Override - public void testEqualsAndHashCode() { - Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)), - matcher.getMethods()); - } + @Override + public void testEqualsAndHashCode() { + Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)), matcher.getMethods()); + } - @Override - public void testGetContent() { - Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)), - matcher.getContent()); - } + @Override + public void testGetContent() { + Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)), matcher.getContent()); + } - @Override - public void testGetToStringInfix() { - Assert.assertEquals(" || ", matcher.getToStringInfix()); - } + @Override + public void testGetToStringInfix() { + Assert.assertEquals(" || ", matcher.getToStringInfix()); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcherTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcherTest.java index d0d53561..38146434 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcherTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/HttpRequestParamsMatcherTest.java @@ -16,12 +16,12 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import java.net.URI; - import org.junit.Assert; import org.junit.Test; import org.springframework.mock.http.client.MockClientHttpRequest; +import java.net.URI; + /** * {@link HttpRequestParamsMatcher} Test * @@ -29,68 +29,68 @@ import org.springframework.mock.http.client.MockClientHttpRequest; */ public class HttpRequestParamsMatcherTest { - // @Test - // public void testGetParams() { - // - // HttpRequestParamsMatcher matcher = new HttpRequestParamsMatcher( - // "a ", - // "a =1", - // "b = 2", - // "b = 3 ", - // " c = 4 ", - // " d" - // ); - // - // Map> params = matcher.getParams(); - // Assert.assertEquals(4, params.size()); - // Assert.assertTrue(params.containsKey("a")); - // Assert.assertTrue(params.containsKey("b")); - // Assert.assertTrue(params.containsKey("c")); - // Assert.assertTrue(params.containsKey("d")); - // Assert.assertFalse(params.containsKey("e")); - // - // List values = params.get("a"); - // Assert.assertEquals(2, values.size()); - // Assert.assertEquals("", values.get(0)); - // Assert.assertEquals("1", values.get(1)); - // - // values = params.get("b"); - // Assert.assertEquals(2, values.size()); - // Assert.assertEquals("2", values.get(0)); - // Assert.assertEquals("3", values.get(1)); - // - // values = params.get("c"); - // Assert.assertEquals(1, values.size()); - // Assert.assertEquals("4", values.get(0)); - // - // values = params.get("d"); - // Assert.assertEquals(1, values.size()); - // Assert.assertEquals("", values.get(0)); - // } +// @Test +// public void testGetParams() { +// +// HttpRequestParamsMatcher matcher = new HttpRequestParamsMatcher( +// "a ", +// "a =1", +// "b = 2", +// "b = 3 ", +// " c = 4 ", +// " d" +// ); +// +// Map> params = matcher.getParams(); +// Assert.assertEquals(4, params.size()); +// Assert.assertTrue(params.containsKey("a")); +// Assert.assertTrue(params.containsKey("b")); +// Assert.assertTrue(params.containsKey("c")); +// Assert.assertTrue(params.containsKey("d")); +// Assert.assertFalse(params.containsKey("e")); +// +// List values = params.get("a"); +// Assert.assertEquals(2, values.size()); +// Assert.assertEquals("", values.get(0)); +// Assert.assertEquals("1", values.get(1)); +// +// values = params.get("b"); +// Assert.assertEquals(2, values.size()); +// Assert.assertEquals("2", values.get(0)); +// Assert.assertEquals("3", values.get(1)); +// +// values = params.get("c"); +// Assert.assertEquals(1, values.size()); +// Assert.assertEquals("4", values.get(0)); +// +// values = params.get("d"); +// Assert.assertEquals(1, values.size()); +// Assert.assertEquals("", values.get(0)); +// } - @Test - public void testEquals() { + @Test + public void testEquals() { - HttpRequestParamsMatcher matcher = new HttpRequestParamsMatcher("a ", "a = 1"); + HttpRequestParamsMatcher matcher = new HttpRequestParamsMatcher("a ", "a = 1"); - MockClientHttpRequest request = new MockClientHttpRequest(); + MockClientHttpRequest request = new MockClientHttpRequest(); - request.setURI(URI.create("http://dummy/?a")); - Assert.assertTrue(matcher.match(request)); - request.setURI(URI.create("http://dummy/?a&a=1")); - Assert.assertTrue(matcher.match(request)); + request.setURI(URI.create("http://dummy/?a")); + Assert.assertTrue(matcher.match(request)); + request.setURI(URI.create("http://dummy/?a&a=1")); + Assert.assertTrue(matcher.match(request)); - matcher = new HttpRequestParamsMatcher("a ", "a =1", "b", "b=2"); - request.setURI(URI.create("http://dummy/?a&a=1&b")); - Assert.assertTrue(matcher.match(request)); - request.setURI(URI.create("http://dummy/?a&a=1&b&b=2")); - Assert.assertTrue(matcher.match(request)); + matcher = new HttpRequestParamsMatcher("a ", "a =1", "b", "b=2"); + request.setURI(URI.create("http://dummy/?a&a=1&b")); + Assert.assertTrue(matcher.match(request)); + request.setURI(URI.create("http://dummy/?a&a=1&b&b=2")); + Assert.assertTrue(matcher.match(request)); - matcher = new HttpRequestParamsMatcher("a ", "a =1", "b", "b=2", "b = 3 "); - request.setURI(URI.create("http://dummy/?a&a=1&b&b=2&b=3")); - Assert.assertTrue(matcher.match(request)); + matcher = new HttpRequestParamsMatcher("a ", "a =1", "b", "b=2", "b = 3 "); + request.setURI(URI.create("http://dummy/?a&a=1&b&b=2&b=3")); + Assert.assertTrue(matcher.match(request)); - request.setURI(URI.create("http://dummy/?d=1")); - Assert.assertFalse(matcher.match(request)); - } + request.setURI(URI.create("http://dummy/?d=1")); + Assert.assertFalse(matcher.match(request)); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpressionTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpressionTest.java index 00545b94..f512bdd9 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpressionTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ParamExpressionTest.java @@ -20,42 +20,41 @@ import org.junit.Assert; import org.junit.Test; import org.springframework.http.HttpRequest; -import com.alibaba.cloud.dubbo.http.DefaultHttpRequest; +import static com.alibaba.cloud.dubbo.http.DefaultHttpRequest.builder; /** * {@link ParamExpression} Test * * @author Mercy */ -public class ParamExpressionTest - extends AbstractNameValueExpressionTest { +public class ParamExpressionTest extends AbstractNameValueExpressionTest { - @Test - public void testIsCaseSensitiveName() { - Assert.assertTrue(createExpression("a=1").isCaseSensitiveName()); - Assert.assertTrue(createExpression("a=!1").isCaseSensitiveName()); - Assert.assertTrue(createExpression("b=1").isCaseSensitiveName()); - } + @Test + public void testIsCaseSensitiveName() { + Assert.assertTrue(createExpression("a=1").isCaseSensitiveName()); + Assert.assertTrue(createExpression("a=!1").isCaseSensitiveName()); + Assert.assertTrue(createExpression("b=1").isCaseSensitiveName()); + } - @Test - public void testMatch() { + @Test + public void testMatch() { - ParamExpression expression = createExpression("a=1"); - HttpRequest request = DefaultHttpRequest.builder().build(); + ParamExpression expression = createExpression("a=1"); + HttpRequest request = builder().build(); - Assert.assertFalse(expression.match(request)); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().param("a", "").build(); - Assert.assertFalse(expression.match(request)); + request = builder().param("a", "").build(); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().param("a", "2").build(); - Assert.assertFalse(expression.match(request)); + request = builder().param("a", "2").build(); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().param("", "1").build(); - Assert.assertFalse(expression.match(request)); + request = builder().param("", "1").build(); + Assert.assertFalse(expression.match(request)); - request = DefaultHttpRequest.builder().param("a", "1").build(); - Assert.assertTrue(expression.match(request)); - } + request = builder().param("a", "1").build(); + Assert.assertTrue(expression.match(request)); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpressionTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpressionTest.java index e1fb4522..1df8fdd8 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpressionTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/matcher/ProduceMediaTypeExpressionTest.java @@ -16,28 +16,25 @@ */ package com.alibaba.cloud.dubbo.http.matcher; -import java.util.Arrays; - import org.junit.Assert; import org.junit.Test; import org.springframework.http.MediaType; +import java.util.Arrays; + /** * {@link ProduceMediaTypeExpression} Test * * @author Mercy */ -public class ProduceMediaTypeExpressionTest - extends AbstractMediaTypeExpressionTest { +public class ProduceMediaTypeExpressionTest extends AbstractMediaTypeExpressionTest { - @Test - public void testMatch() { - ProduceMediaTypeExpression expression = createExpression( - MediaType.APPLICATION_JSON_VALUE); - Assert.assertTrue(expression.match( - Arrays.asList(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON))); + @Test + public void testMatch() { + ProduceMediaTypeExpression expression = createExpression(MediaType.APPLICATION_JSON_VALUE); + Assert.assertTrue(expression.match(Arrays.asList(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON))); - expression = createExpression(MediaType.APPLICATION_JSON_VALUE); - Assert.assertFalse(expression.match(Arrays.asList(MediaType.APPLICATION_XML))); - } + expression = createExpression(MediaType.APPLICATION_JSON_VALUE); + Assert.assertFalse(expression.match(Arrays.asList(MediaType.APPLICATION_XML))); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/util/HttpUtilsTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/util/HttpUtilsTest.java index e92e48e7..322d6e1f 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/util/HttpUtilsTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/http/util/HttpUtilsTest.java @@ -26,16 +26,16 @@ import org.junit.Test; */ public class HttpUtilsTest { - @Test - public void testEncodeAndDecode() { + @Test + public void testEncodeAndDecode() { - String whitespace = " "; + String whitespace = " "; - String encodedValue = HttpUtils.encode(" "); + String encodedValue = HttpUtils.encode(" "); - String decodedValue = HttpUtils.decode(encodedValue); + String decodedValue = HttpUtils.decode(encodedValue); - Assert.assertEquals(whitespace, decodedValue); - } + Assert.assertEquals(whitespace, decodedValue); + } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/RequestMetadataTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/RequestMetadataTest.java index 0c568e9c..84992422 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/RequestMetadataTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/RequestMetadataTest.java @@ -16,13 +16,13 @@ */ package com.alibaba.cloud.dubbo.metadata; +import org.junit.Assert; +import org.junit.Test; + import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; -import org.junit.Assert; -import org.junit.Test; - /** * {@link RequestMetadata} Test * @@ -30,108 +30,107 @@ import org.junit.Test; */ public class RequestMetadataTest { - private String method = "GET"; + private String method = "GET"; - private String url = "/param"; + private String url = "/param"; - private Set paramNames = new LinkedHashSet<>(Arrays.asList("a", "b", "c")); + private Set paramNames = new LinkedHashSet<>(Arrays.asList("a", "b", "c")); - private Set headerNames = new LinkedHashSet<>(Arrays.asList("d", "e", "f")); + private Set headerNames = new LinkedHashSet<>(Arrays.asList("d", "e", "f")); - @Test - public void testEqualsAndHashCodeAndCompareTo() { + @Test + public void testEqualsAndHashCodeAndCompareTo() { - RequestMetadata metadata = new RequestMetadata(); - RequestMetadata metadata2 = new RequestMetadata(); + RequestMetadata metadata = new RequestMetadata(); + RequestMetadata metadata2 = new RequestMetadata(); - Assert.assertEquals(metadata, metadata2); - Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); + Assert.assertEquals(metadata, metadata2); + Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); - metadata.setMethod(method); - metadata2.setMethod(method); + metadata.setMethod(method); + metadata2.setMethod(method); - Assert.assertEquals(metadata, metadata2); - Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); + Assert.assertEquals(metadata, metadata2); + Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); - metadata.setPath(url); - metadata2.setPath(url); + metadata.setPath(url); + metadata2.setPath(url); - Assert.assertEquals(metadata, metadata2); - Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); + Assert.assertEquals(metadata, metadata2); + Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); - metadata.addParam("a", "1").addParam("b", "2").addParam("c", "3"); - metadata2.addParam("a", "1a").addParam("b", "2b").addParam("c", "3c"); + metadata.addParam("a", "1").addParam("b", "2").addParam("c", "3"); + metadata2.addParam("a", "1a").addParam("b", "2b").addParam("c", "3c"); - Assert.assertEquals(metadata, metadata2); - Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); + Assert.assertEquals(metadata, metadata2); + Assert.assertEquals(metadata.hashCode(), metadata2.hashCode()); - metadata.addHeader("d", "1").addHeader("e", "2").addHeader("f", "3"); - metadata2.addHeader("d", "1").addHeader("e", "2"); + metadata.addHeader("d", "1").addHeader("e", "2").addHeader("f", "3"); + metadata2.addHeader("d", "1").addHeader("e", "2"); - Assert.assertNotEquals(metadata, metadata2); - Assert.assertNotEquals(metadata.hashCode(), metadata2.hashCode()); - } + Assert.assertNotEquals(metadata, metadata2); + Assert.assertNotEquals(metadata.hashCode(), metadata2.hashCode()); + } - // @Test - // public void testBestMatch() { - // - // NavigableMap requestMetadataMap = new - // TreeMap<>(); - // - // RequestMetadata metadata = new RequestMetadata(); - // metadata.setMethod(method); - // - // RequestMetadata metadata1 = new RequestMetadata(); - // metadata1.setMethod(method); - // metadata1.setPath(url); - // - // RequestMetadata metadata2 = new RequestMetadata(); - // metadata2.setMethod(method); - // metadata2.setPath(url); - // metadata2.setParams(paramNames); - // - // RequestMetadata metadata3 = new RequestMetadata(); - // metadata3.setMethod(method); - // metadata3.setPath(url); - // metadata3.setParams(paramNames); - // metadata3.setHeaders(headerNames); - // - // requestMetadataMap.put(metadata, metadata); - // requestMetadataMap.put(metadata1, metadata1); - // requestMetadataMap.put(metadata2, metadata2); - // requestMetadataMap.put(metadata3, metadata3); - // - // RequestMetadata result = getBestMatch(requestMetadataMap, metadata); - // Assert.assertEquals(result, metadata); - // - // result = getBestMatch(requestMetadataMap, metadata1); - // Assert.assertEquals(result, metadata1); - // - // result = getBestMatch(requestMetadataMap, metadata2); - // Assert.assertEquals(result, metadata2); - // - // result = getBestMatch(requestMetadataMap, metadata3); - // Assert.assertEquals(result, metadata3); - // - // // REDO - // requestMetadataMap.clear(); - // - // requestMetadataMap.put(metadata1, metadata1); - // - // result = getBestMatch(requestMetadataMap, metadata2); - // Assert.assertEquals(metadata1, result); - // - // requestMetadataMap.put(metadata2, metadata2); - // - // result = getBestMatch(requestMetadataMap, metadata3); - // Assert.assertEquals(metadata2, result); - // - // result = getBestMatch(requestMetadataMap, new RequestMetadata()); - // Assert.assertNull(result); - // - // result = getBestMatch(requestMetadataMap, metadata); - // Assert.assertNull(result); - // - // } +// @Test +// public void testBestMatch() { +// +// NavigableMap requestMetadataMap = new TreeMap<>(); +// +// RequestMetadata metadata = new RequestMetadata(); +// metadata.setMethod(method); +// +// RequestMetadata metadata1 = new RequestMetadata(); +// metadata1.setMethod(method); +// metadata1.setPath(url); +// +// RequestMetadata metadata2 = new RequestMetadata(); +// metadata2.setMethod(method); +// metadata2.setPath(url); +// metadata2.setParams(paramNames); +// +// RequestMetadata metadata3 = new RequestMetadata(); +// metadata3.setMethod(method); +// metadata3.setPath(url); +// metadata3.setParams(paramNames); +// metadata3.setHeaders(headerNames); +// +// requestMetadataMap.put(metadata, metadata); +// requestMetadataMap.put(metadata1, metadata1); +// requestMetadataMap.put(metadata2, metadata2); +// requestMetadataMap.put(metadata3, metadata3); +// +// RequestMetadata result = getBestMatch(requestMetadataMap, metadata); +// Assert.assertEquals(result, metadata); +// +// result = getBestMatch(requestMetadataMap, metadata1); +// Assert.assertEquals(result, metadata1); +// +// result = getBestMatch(requestMetadataMap, metadata2); +// Assert.assertEquals(result, metadata2); +// +// result = getBestMatch(requestMetadataMap, metadata3); +// Assert.assertEquals(result, metadata3); +// +// // REDO +// requestMetadataMap.clear(); +// +// requestMetadataMap.put(metadata1, metadata1); +// +// result = getBestMatch(requestMetadataMap, metadata2); +// Assert.assertEquals(metadata1, result); +// +// requestMetadataMap.put(metadata2, metadata2); +// +// result = getBestMatch(requestMetadataMap, metadata3); +// Assert.assertEquals(metadata2, result); +// +// result = getBestMatch(requestMetadataMap, new RequestMetadata()); +// Assert.assertNull(result); +// +// result = getBestMatch(requestMetadataMap, metadata); +// Assert.assertNull(result); +// +// } } diff --git a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolverTest.java b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolverTest.java index 467cc7db..b1cc3a74 100644 --- a/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolverTest.java +++ b/spring-cloud-alibaba-dubbo/src/test/java/com/alibaba/cloud/dubbo/metadata/resolver/DubboTransportedMethodMetadataResolverTest.java @@ -16,16 +16,15 @@ */ package com.alibaba.cloud.dubbo.metadata.resolver; -import java.util.Set; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.alibaba.cloud.dubbo.annotation.DubboTransported; +import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata; import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.mock.env.MockEnvironment; -import com.alibaba.cloud.dubbo.annotation.DubboTransported; -import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata; +import java.util.Set; /** * {@link DubboTransportedMethodMetadataResolver} Test @@ -34,28 +33,27 @@ import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata; */ public class DubboTransportedMethodMetadataResolverTest { - private DubboTransportedMethodMetadataResolver resolver; + private DubboTransportedMethodMetadataResolver resolver; - private MockEnvironment environment; + private MockEnvironment environment; - @Before - public void init() { - environment = new MockEnvironment(); - resolver = new DubboTransportedMethodMetadataResolver(environment, - new SpringMvcContract()); - } + @Before + public void init() { + environment = new MockEnvironment(); + resolver = new DubboTransportedMethodMetadataResolver(environment, new SpringMvcContract()); + } - @Test - public void testResolve() { - Set metadataSet = resolver - .resolveDubboTransportedMethodMetadataSet(TestDefaultService.class); - Assert.assertEquals(1, metadataSet.size()); - } + @Test + public void testResolve() { + Set metadataSet = resolver.resolveDubboTransportedMethodMetadataSet(TestDefaultService.class); + Assert.assertEquals(1, metadataSet.size()); + } - @DubboTransported - interface TestDefaultService { - String test(String message); + @DubboTransported + interface TestDefaultService { - } + String test(String message); + + } } diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClient.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClient.java index 941a2319..0a3ad891 100644 --- a/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClient.java +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClient.java @@ -65,8 +65,11 @@ public class NacosDiscoveryClient implements DiscoveryClient { } } - private static ServiceInstance hostToServiceInstance(Instance instance, + public static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) { + if (instance == null || !instance.isEnabled() || !instance.isHealthy()) { + return null; + } NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); nacosServiceInstance.setHost(instance.getIp()); nacosServiceInstance.setPort(instance.getPort()); @@ -87,11 +90,14 @@ public class NacosDiscoveryClient implements DiscoveryClient { return nacosServiceInstance; } - private static List hostToServiceInstanceList( + public static List hostToServiceInstanceList( List instances, String serviceId) { List result = new ArrayList<>(instances.size()); for (Instance instance : instances) { - result.add(hostToServiceInstance(instance, serviceId)); + ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId); + if (serviceInstance != null) { + result.add(serviceInstance); + } } return result; }