mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
finchley dubbo sync
This commit is contained in:
parent
7914702ef9
commit
c7e80a847b
@ -28,6 +28,8 @@ import com.alibaba.cloud.dubbo.actuate.endpoint.DubboRestMetadataEndpoint;
|
||||
|
||||
/**
|
||||
* Dubbo Metadata Endpoints Auto-{@link Configuration}
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
@ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.annotation.Endpoint")
|
||||
@PropertySource(value = "classpath:/META-INF/dubbo/default/actuator-endpoints.properties")
|
||||
|
@ -26,6 +26,8 @@ import com.alibaba.cloud.dubbo.service.DubboMetadataService;
|
||||
|
||||
/**
|
||||
* Dubbo Rest Metadata {@link Endpoint}
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
@Endpoint(id = "dubborestmetadata")
|
||||
public class DubboRestMetadataEndpoint {
|
||||
|
@ -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;
|
||||
* </ol>
|
||||
* <p>
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @see FeignClient
|
||||
* @see LoadBalanced
|
||||
*/
|
||||
|
@ -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<String, Object> dubboTranslatedAttributes) {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @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<Object> heartbeatState = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* @see #defaultHeartbeatEventChangePredicate()
|
||||
*/
|
||||
private final ObjectProvider<Predicate<HeartbeatEvent>> heartbeatEventChangedPredicate;
|
||||
|
||||
public DubboServiceDiscoveryAutoConfiguration(
|
||||
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||
ApplicationEventPublisher applicationEventPublisher,
|
||||
DiscoveryClient discoveryClient,
|
||||
ObjectProvider<Predicate<HeartbeatEvent>> 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<ServiceInstance> 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<ServiceInstance> getInstances(String serviceName) {
|
||||
return discoveryClient.getInstances(serviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a {@link ServiceInstancesChangedEvent} when the {@link HeartbeatEvent}
|
||||
* raised, use for these scenarios:
|
||||
* <ul>
|
||||
* <li>Eureka : {@link CloudEurekaClient#onCacheRefreshed()} publishes a
|
||||
* {@link HeartbeatEvent} instead of {@link CacheRefreshedEvent}</li>
|
||||
* <li>Zookeeper :
|
||||
* {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)}
|
||||
* publishes a {@link HeartbeatEvent} when
|
||||
* {@link ZookeeperDiscoveryProperties#getRoot() the services' root path} has been
|
||||
* changed</li>
|
||||
* <li>Consul : {@link ConsulCatalogWatch#catalogServicesWatch()} publishes a
|
||||
* {@link HeartbeatEvent} when
|
||||
* <a href="https://www.consul.io/api/features/blocking.html">Consul's Blocking
|
||||
* Queries response</a></li>
|
||||
* <li>Nacos : {@link NacosWatch#nacosServicesWatch()} publishes a
|
||||
* {@link HeartbeatEvent} under a {@link TaskScheduler} every
|
||||
* {@link NacosDiscoveryProperties#getWatchDelay()} milliseconds</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* <b>Note : </b> 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:
|
||||
* <ul>
|
||||
* <li>Zookeeper : {@link Watcher}, see
|
||||
* {@link ZookeeperConfiguration#heartbeatEventChangedPredicate()}</li>
|
||||
* <li>Nacos : {@link com.alibaba.nacos.api.naming.listener.EventListener} , see
|
||||
* {@link NacosConfiguration#heartbeatEventChangedPredicate()}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 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<String> subscribedServices = dubboServiceMetadataRepository
|
||||
.initSubscribedServices();
|
||||
|
||||
heartbeatEventChangedPredicate.ifAvailable(predicate -> {
|
||||
if (predicate.test(event)) {
|
||||
// Dispatch ServiceInstancesChangedEvent for each service
|
||||
subscribedServices.forEach(serviceName -> {
|
||||
List<ServiceInstance> 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<HeartbeatEvent>}
|
||||
* @see EurekaConfiguration#heartbeatEventChangedPredicate()
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Predicate<HeartbeatEvent> 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<String> appsHashCodeCache = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Compare {@link Applications#getAppsHashCode() apps hash code} between last
|
||||
* {@link Applications} and current.
|
||||
*
|
||||
* @see Applications#getAppsHashCode()
|
||||
*/
|
||||
@Bean
|
||||
public Predicate<HeartbeatEvent> 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<InstanceRegisteredEvent> {
|
||||
/**
|
||||
* 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} :
|
||||
* <p>
|
||||
* <p>
|
||||
* ${{@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<String> 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 <code>false</code> forever
|
||||
*/
|
||||
@Bean
|
||||
public Predicate<HeartbeatEvent> 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<TreeCacheListener> 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<TreeCacheListener> otherListeners = new LinkedList<>();
|
||||
|
||||
if (listenable instanceof ListenerContainer) {
|
||||
ListenerContainer<TreeCacheListener> 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 <code>null</code>
|
||||
*/
|
||||
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<String, String> 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<String> 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 <code>false</code> forever
|
||||
*/
|
||||
@Bean
|
||||
public Predicate<HeartbeatEvent> 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<ServiceInstance> serviceInstances = hostToServiceInstanceList(
|
||||
namingEvent.getInstances(), serviceName);
|
||||
dispatchServiceInstancesChangedEvent(serviceName,
|
||||
serviceInstances);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (NacosException e) {
|
||||
ReflectionUtils.rethrowRuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, String> metadata = registration.getMetadata();
|
||||
attachDubboMetadataServiceMetadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
|
||||
Map<String, String> 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<String, String> metadata = registration.getMetadata();
|
||||
attachDubboMetadataServiceMetadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
|
||||
Map<String, String> serviceMetadata = dubboServiceMetadataRepository
|
||||
.getDubboMetadataServiceMetadata();
|
||||
if (!isEmpty(serviceMetadata)) {
|
||||
metadata.putAll(serviceMetadata);
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,7 @@ import com.alibaba.cloud.dubbo.registry.SpringCloudRegistry;
|
||||
/**
|
||||
* Missing {@link SpringCloudRegistry} Property {@link Condition}
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @see SpringCloudRegistry
|
||||
* @see Condition
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<String, List<String>> 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
|
||||
*/
|
||||
|
@ -73,6 +73,7 @@ public class MutableHttpServerRequest implements HttpServerRequest {
|
||||
}
|
||||
|
||||
// Override method since Spring Framework 5.0
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return httpMethod.name();
|
||||
}
|
||||
|
@ -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<ConsumeMediaTypeExpression> parseExpressions(String[] consumes,
|
||||
String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> 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<ConsumeMediaTypeExpression> parseExpressions(String[] consumes,
|
||||
String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> 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<ConsumeMediaTypeExpression> getContent() {
|
||||
return this.expressions;
|
||||
|
@ -34,15 +34,23 @@ public class HttpRequestParamsMatcher extends AbstractHttpRequestMatcher {
|
||||
|
||||
/**
|
||||
* @param params The pattern of params :
|
||||
* <ul>
|
||||
* <li>name=value</li>
|
||||
* <li>name</li>
|
||||
* </ul>
|
||||
* <ul>
|
||||
* <li>name=value</li>
|
||||
* <li>name</li>
|
||||
* </ul>
|
||||
*/
|
||||
public HttpRequestParamsMatcher(String... params) {
|
||||
this.expressions = parseExpressions(params);
|
||||
}
|
||||
|
||||
private static Set<ParamExpression> parseExpressions(String... params) {
|
||||
Set<ParamExpression> 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<ParamExpression> parseExpressions(String... params) {
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<>();
|
||||
for (String param : params) {
|
||||
expressions.add(new ParamExpression(param));
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<ParamExpression> getContent() {
|
||||
return this.expressions;
|
||||
|
@ -45,6 +45,17 @@ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher {
|
||||
this.pathMatcher = new AntPathMatcher();
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(String[] patterns) {
|
||||
Set<String> 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<String> matches = getMatchingPatterns(request);
|
||||
@ -94,17 +105,6 @@ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher {
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(String[] patterns) {
|
||||
Set<String> 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<String> getContent() {
|
||||
return this.patterns;
|
||||
|
@ -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<MediaType> acceptedMediaTypes = httpHeaders.getAccept();
|
||||
|
||||
for (ProduceMediaTypeExpression expression : expressions) {
|
||||
if (!expression.match(acceptedMediaTypes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Set<ProduceMediaTypeExpression> parseExpressions(String[] produces,
|
||||
String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> 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<MediaType> acceptedMediaTypes = httpHeaders.getAccept();
|
||||
|
||||
for (ProduceMediaTypeExpression expression : expressions) {
|
||||
if (!expression.match(acceptedMediaTypes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<ProduceMediaTypeExpression> getContent() {
|
||||
return expressions;
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 <code>null</code>
|
||||
*/
|
||||
public static RequestMetadata getBestMatch(
|
||||
NavigableMap<RequestMetadata, RequestMetadata> requestMetadataMap,
|
||||
RequestMetadata requestMetadata) {
|
||||
|
||||
RequestMetadata key = requestMetadata;
|
||||
|
||||
RequestMetadata result = requestMetadataMap.get(key);
|
||||
|
||||
if (result == null) {
|
||||
SortedMap<RequestMetadata, RequestMetadata> headMap = requestMetadataMap
|
||||
.headMap(key, true);
|
||||
result = headMap.isEmpty() ? null : requestMetadataMap.get(headMap.lastKey());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void add(String key, String value,
|
||||
MultiValueMap<String, String> destination) {
|
||||
destination.add(key, value);
|
||||
}
|
||||
|
||||
private static <T extends Collection<String>> void addAll(Map<String, T> source,
|
||||
MultiValueMap<String, String> destination) {
|
||||
for (Map.Entry<String, T> 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<String> destination) {
|
||||
List<String> value = httpHeaders.get(headerName);
|
||||
List<MediaType> mediaTypes = parseMediaTypes(value);
|
||||
destination.addAll(toMediaTypeValues(mediaTypes));
|
||||
}
|
||||
|
||||
private static List<String> toMediaTypeValues(List<MediaType> mediaTypes) {
|
||||
List<String> list = new ArrayList<>(mediaTypes.size());
|
||||
for (MediaType mediaType : mediaTypes) {
|
||||
list.add(mediaType.toString());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<MediaType> toMediaTypes(Collection<String> 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<String, String> 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 <code>null</code>
|
||||
*/
|
||||
public static RequestMetadata getBestMatch(
|
||||
NavigableMap<RequestMetadata, RequestMetadata> requestMetadataMap,
|
||||
RequestMetadata requestMetadata) {
|
||||
|
||||
RequestMetadata key = requestMetadata;
|
||||
|
||||
RequestMetadata result = requestMetadataMap.get(key);
|
||||
|
||||
if (result == null) {
|
||||
SortedMap<RequestMetadata, RequestMetadata> headMap = requestMetadataMap
|
||||
.headMap(key, true);
|
||||
result = headMap.isEmpty() ? null : requestMetadataMap.get(headMap.lastKey());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void add(String key, String value,
|
||||
MultiValueMap<String, String> destination) {
|
||||
destination.add(key, value);
|
||||
}
|
||||
|
||||
private static <T extends Collection<String>> void addAll(Map<String, T> source,
|
||||
MultiValueMap<String, String> destination) {
|
||||
for (Map.Entry<String, T> 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<String> destination) {
|
||||
List<String> value = httpHeaders.get(headerName);
|
||||
List<MediaType> mediaTypes = parseMediaTypes(value);
|
||||
destination.addAll(toMediaTypeValues(mediaTypes));
|
||||
}
|
||||
|
||||
private static List<String> toMediaTypeValues(List<MediaType> mediaTypes) {
|
||||
List<String> list = new ArrayList<>(mediaTypes.size());
|
||||
for (MediaType mediaType : mediaTypes) {
|
||||
list.add(mediaType.toString());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<MediaType> toMediaTypes(Collection<String> 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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
@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<String> 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<String, URL> allExportedURLs = new LinkedMultiValueMap<>();
|
||||
|
||||
// ====================================================================================
|
||||
// //
|
||||
|
||||
// =================================== Subscription
|
||||
// =================================== Registration
|
||||
// =================================== //
|
||||
|
||||
private Set<String> 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> serviceRestMetadata = new LinkedHashSet<>();
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
// ====================================================================================
|
||||
// //
|
||||
|
||||
// =================================== REST Metadata
|
||||
// ================================== //
|
||||
private volatile Set<String> subscribedServices = emptySet();
|
||||
/**
|
||||
* Key is application name Value is Map<RequestMetadata, DubboRestServiceMetadata>
|
||||
*/
|
||||
@ -172,12 +181,114 @@ public class DubboServiceMetadataRepository {
|
||||
// ====================================================================================
|
||||
// //
|
||||
|
||||
private static <K, V> Map<K, V> getMap(Map<String, Map<K, V>> repository,
|
||||
String key) {
|
||||
return getOrDefault(repository, key, newHashMap());
|
||||
}
|
||||
|
||||
private static <K, V> V getOrDefault(Map<K, V> source, K key, V defaultValue) {
|
||||
V value = source.get(key);
|
||||
if (value == null) {
|
||||
value = defaultValue;
|
||||
source.put(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> 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<String> initSubscribedServices() {
|
||||
Set<String> newSubscribedServices = new LinkedHashSet<>();
|
||||
|
||||
// If subscribes all services
|
||||
if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) {
|
||||
List<String> 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<String> 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<URL> getSubscribedDubboMetadataServiceURLs() {
|
||||
// return Collections.unmodifiableList(subscribedDubboMetadataServiceURLs);
|
||||
// }
|
||||
|
||||
public List<URL> findSubscribedDubboMetadataServiceURLs(String serviceName,
|
||||
String group, String version, String protocol) {
|
||||
String serviceKey = URL.buildKey(serviceName, group, version);
|
||||
List<URL> urls = subscribedDubboMetadataServiceURLs.get(serviceKey);
|
||||
|
||||
List<URL> 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<String> doGetSubscribedServices() {
|
||||
Set<String> subscribedServices = this.subscribedServices;
|
||||
return subscribedServices == null ? emptySet() : subscribedServices;
|
||||
}
|
||||
|
||||
public Set<String> getSubscribedServices() {
|
||||
return Collections.unmodifiableSet(subscribedServices);
|
||||
return unmodifiableSet(doGetSubscribedServices());
|
||||
}
|
||||
|
||||
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository,
|
||||
@ -489,66 +604,30 @@ public class DubboServiceMetadataRepository {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> getMap(Map<String, Map<K, V>> repository,
|
||||
String key) {
|
||||
return getOrDefault(repository, key, newHashMap());
|
||||
}
|
||||
|
||||
private static <K, V> V getOrDefault(Map<K, V> source, K key, V defaultValue) {
|
||||
V value = source.get(key);
|
||||
if (value == null) {
|
||||
value = defaultValue;
|
||||
source.put(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> newHashMap() {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
private void initSubscribedServices() {
|
||||
// If subscribes all services
|
||||
if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) {
|
||||
List<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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> 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<Method, FeignMethodMetadata> feignMethodMetadataMap = getFeignMethodMetadataMap(
|
||||
serviceName, feignRestMethodMetadataMap);
|
||||
@ -180,8 +185,4 @@ class TargeterInvocationHandler implements InvocationHandler {
|
||||
|
||||
return feignMethodMetadataMap;
|
||||
}
|
||||
|
||||
private static <T> T cast(Object object) {
|
||||
return (T) object;
|
||||
}
|
||||
}
|
||||
|
@ -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<String> SCHEDULER_TASKS = new HashSet<>();
|
||||
/**
|
||||
* Caches the IDs of {@link ApplicationListener}
|
||||
*/
|
||||
private static final Set<String> 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<ServiceInstancesChangedEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(
|
||||
ServiceInstancesChangedEvent event) {
|
||||
String serviceName = event.getServiceName();
|
||||
Collection<ServiceInstance> serviceInstances = event
|
||||
.getServiceInstances();
|
||||
subscribeDubboServiceURL(url, listener, serviceName,
|
||||
s -> serviceInstances);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) {
|
||||
private void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) {
|
||||
|
||||
Set<String> subscribedServices = repository.getSubscribedServices();
|
||||
// Sync
|
||||
subscribedServices.forEach(service -> subscribeDubboServiceURL(url, listener,
|
||||
service, this::getServiceInstances));
|
||||
}
|
||||
|
||||
subscribedServices.stream().map(dubboMetadataConfigServiceProxy::getProxy)
|
||||
.filter(Objects::nonNull).forEach(dubboMetadataService -> {
|
||||
List<URL> exportedURLs = getExportedURLs(dubboMetadataService, url);
|
||||
List<URL> allSubscribedURLs = new LinkedList<>();
|
||||
for (URL exportedURL : exportedURLs) {
|
||||
String serviceName = exportedURL.getParameter(APPLICATION_KEY);
|
||||
List<ServiceInstance> serviceInstances = getServiceInstances(
|
||||
serviceName);
|
||||
String protocol = exportedURL.getProtocol();
|
||||
List<URL> 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<String, Collection<ServiceInstance>> 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<ServiceInstance> serviceInstances = serviceInstancesFunction
|
||||
.apply(serviceName);
|
||||
|
||||
List<URL> 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<URL> exportedURLs = getExportedURLs(dubboMetadataService, url);
|
||||
|
||||
for (URL exportedURL : exportedURLs) {
|
||||
String protocol = exportedURL.getProtocol();
|
||||
List<URL> 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<URL> emptyURLs(URL url) {
|
||||
return asList(from(url).setProtocol(EMPTY_PROTOCOL).build());
|
||||
}
|
||||
|
||||
private List<ServiceInstance> 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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class ServiceInstanceRegisteredEvent extends EventObject {
|
||||
public class ServiceInstanceRegisteredEvent extends ApplicationEvent {
|
||||
|
||||
public ServiceInstanceRegisteredEvent(Registration source) {
|
||||
super(source);
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class ServiceInstancesChangedEvent extends ApplicationEvent {
|
||||
|
||||
private final String serviceName;
|
||||
|
||||
private final Collection<ServiceInstance> 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<ServiceInstance> 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<ServiceInstance> getServiceInstances() {
|
||||
return serviceInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark current event being processed
|
||||
*/
|
||||
public void processed() {
|
||||
processed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current event has been processed or not
|
||||
*
|
||||
* @return if processed, return <code>true</code>, or <code>false</code>
|
||||
*/
|
||||
public boolean isProcessed() {
|
||||
return processed;
|
||||
}
|
||||
}
|
@ -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
|
||||
* <p>
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
* @see ApplicationEvent
|
||||
*/
|
||||
public class SubscribedServicesChangedEvent extends ApplicationEvent {
|
||||
|
||||
private final Set<String> oldSubscribedServices;
|
||||
|
||||
private final Set<String> 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<String> oldSubscribedServices, Set<String> newSubscribedServices) {
|
||||
super(source);
|
||||
this.oldSubscribedServices = new LinkedHashSet<>(oldSubscribedServices);
|
||||
this.newSubscribedServices = new LinkedHashSet<>(newSubscribedServices);
|
||||
this.changed = !Objects.equals(oldSubscribedServices, newSubscribedServices);
|
||||
}
|
||||
|
||||
public Set<String> getOldSubscribedServices() {
|
||||
return oldSubscribedServices;
|
||||
}
|
||||
|
||||
public Set<String> getNewSubscribedServices() {
|
||||
return newSubscribedServices;
|
||||
}
|
||||
|
||||
public boolean isChanged() {
|
||||
return changed;
|
||||
}
|
||||
}
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -26,14 +26,14 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
|
||||
/**
|
||||
* The proxy of {@link DubboMetadataService}
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean {
|
||||
|
||||
private final DubboGenericServiceFactory dubboGenericServiceFactory;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private final Map<String, DubboMetadataService> dubboMetadataServiceCache = new ConcurrentHashMap<>();
|
||||
private ClassLoader classLoader;
|
||||
|
||||
public DubboMetadataServiceProxy(
|
||||
DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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<T extends AbstractMediaTypeExpression> {
|
||||
|
||||
protected T createExpression(String expression) {
|
||||
ResolvableType resolvableType = ResolvableType
|
||||
.forType(getClass().getGenericSuperclass());
|
||||
Class<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
||||
Constructor<T> 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<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
||||
Constructor<T> 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)));
|
||||
}
|
||||
}
|
||||
|
@ -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<T extends AbstractNameValueExpression> {
|
||||
|
||||
protected T createExpression(String expression) {
|
||||
ResolvableType resolvableType = ResolvableType
|
||||
.forType(getClass().getGenericSuperclass());
|
||||
Class<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
||||
Constructor<T> 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<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
||||
Constructor<T> 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());
|
||||
}
|
||||
}
|
||||
|
@ -25,22 +25,21 @@ import org.springframework.http.MediaType;
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class ConsumeMediaTypeExpressionTest
|
||||
extends AbstractMediaTypeExpressionTest<ConsumeMediaTypeExpression> {
|
||||
public class ConsumeMediaTypeExpressionTest extends AbstractMediaTypeExpressionTest<ConsumeMediaTypeExpression> {
|
||||
|
||||
@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));
|
||||
}
|
||||
}
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class HeaderExpressionTest
|
||||
extends AbstractNameValueExpressionTest<HeaderExpression> {
|
||||
public class HeaderExpressionTest extends AbstractNameValueExpressionTest<HeaderExpression> {
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class HttpRequestMethodsMatcherTest
|
||||
extends AbstractHttpRequestMatcherTest<HttpRequestMethodsMatcher> {
|
||||
public class HttpRequestMethodsMatcherTest extends AbstractHttpRequestMatcherTest<HttpRequestMethodsMatcher> {
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String, List<String>> 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<String> 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<String, List<String>> 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<String> 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));
|
||||
}
|
||||
}
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class ParamExpressionTest
|
||||
extends AbstractNameValueExpressionTest<ParamExpression> {
|
||||
public class ParamExpressionTest extends AbstractNameValueExpressionTest<ParamExpression> {
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class ProduceMediaTypeExpressionTest
|
||||
extends AbstractMediaTypeExpressionTest<ProduceMediaTypeExpression> {
|
||||
public class ProduceMediaTypeExpressionTest extends AbstractMediaTypeExpressionTest<ProduceMediaTypeExpression> {
|
||||
|
||||
@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)));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String> paramNames = new LinkedHashSet<>(Arrays.asList("a", "b", "c"));
|
||||
private Set<String> paramNames = new LinkedHashSet<>(Arrays.asList("a", "b", "c"));
|
||||
|
||||
private Set<String> headerNames = new LinkedHashSet<>(Arrays.asList("d", "e", "f"));
|
||||
private Set<String> 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<RequestMetadata, RequestMetadata> 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<RequestMetadata, RequestMetadata> 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);
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
|
@ -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<DubboTransportedMethodMetadata> metadataSet = resolver
|
||||
.resolveDubboTransportedMethodMetadataSet(TestDefaultService.class);
|
||||
Assert.assertEquals(1, metadataSet.size());
|
||||
}
|
||||
@Test
|
||||
public void testResolve() {
|
||||
Set<DubboTransportedMethodMetadata> metadataSet = resolver.resolveDubboTransportedMethodMetadataSet(TestDefaultService.class);
|
||||
Assert.assertEquals(1, metadataSet.size());
|
||||
}
|
||||
|
||||
@DubboTransported
|
||||
interface TestDefaultService {
|
||||
|
||||
String test(String message);
|
||||
@DubboTransported
|
||||
interface TestDefaultService {
|
||||
|
||||
}
|
||||
String test(String message);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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<ServiceInstance> hostToServiceInstanceList(
|
||||
public static List<ServiceInstance> hostToServiceInstanceList(
|
||||
List<Instance> instances, String serviceId) {
|
||||
List<ServiceInstance> 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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user