1
0
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:
fangjian0423 2019-08-01 14:33:27 +08:00
parent 7914702ef9
commit c7e80a847b
61 changed files with 1624 additions and 752 deletions

View File

@ -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")

View File

@ -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 {

View File

@ -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
*/

View File

@ -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) {

View File

@ -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;

View File

@ -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 {
}
}

View File

@ -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);
}
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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 {
/**

View File

@ -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
*/

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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
*/

View File

@ -73,6 +73,7 @@ public class MutableHttpServerRequest implements HttpServerRequest {
}
// Override method since Spring Framework 5.0
@Override
public String getMethodValue() {
return httpMethod.name();
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
/**

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 {
}
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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)));
}
}

View File

@ -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());
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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());
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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)));
}
}

View File

@ -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);
}
}

View File

@ -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);
//
// }
}

View File

@ -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);
}
}

View File

@ -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;
}