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:
@@ -28,6 +28,8 @@ import com.alibaba.cloud.dubbo.actuate.endpoint.DubboRestMetadataEndpoint;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo Metadata Endpoints Auto-{@link Configuration}
|
* Dubbo Metadata Endpoints Auto-{@link Configuration}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.annotation.Endpoint")
|
@ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.annotation.Endpoint")
|
||||||
@PropertySource(value = "classpath:/META-INF/dubbo/default/actuator-endpoints.properties")
|
@PropertySource(value = "classpath:/META-INF/dubbo/default/actuator-endpoints.properties")
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import com.alibaba.cloud.dubbo.service.DubboMetadataService;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo Rest Metadata {@link Endpoint}
|
* Dubbo Rest Metadata {@link Endpoint}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@Endpoint(id = "dubborestmetadata")
|
@Endpoint(id = "dubborestmetadata")
|
||||||
public class DubboRestMetadataEndpoint {
|
public class DubboRestMetadataEndpoint {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.lang.annotation.Target;
|
|||||||
import org.apache.dubbo.config.annotation.Reference;
|
import org.apache.dubbo.config.annotation.Reference;
|
||||||
import org.apache.dubbo.rpc.ExporterListener;
|
import org.apache.dubbo.rpc.ExporterListener;
|
||||||
import org.apache.dubbo.rpc.Filter;
|
import org.apache.dubbo.rpc.Filter;
|
||||||
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
@@ -51,6 +52,7 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
* </ol>
|
* </ol>
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
* @see FeignClient
|
* @see FeignClient
|
||||||
* @see LoadBalanced
|
* @see LoadBalanced
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.function.Supplier;
|
|||||||
import org.apache.dubbo.config.ProtocolConfig;
|
import org.apache.dubbo.config.ProtocolConfig;
|
||||||
import org.apache.dubbo.config.spring.ServiceBean;
|
import org.apache.dubbo.config.spring.ServiceBean;
|
||||||
import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
|
import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
|||||||
@@ -49,15 +49,6 @@ public class DubboServiceAutoConfiguration {
|
|||||||
return new DubboGenericServiceFactory();
|
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}
|
* Build a primary {@link PropertyResolver} bean to {@link Autowired @Autowired}
|
||||||
*
|
*
|
||||||
@@ -69,4 +60,13 @@ public class DubboServiceAutoConfiguration {
|
|||||||
public PropertyResolver primaryPropertyResolver(Environment environment) {
|
public PropertyResolver primaryPropertyResolver(Environment environment) {
|
||||||
return environment;
|
return environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(value = { DubboGenericServiceExecutionContextFactory.class,
|
||||||
|
RequestParamServiceParameterResolver.class,
|
||||||
|
RequestBodyServiceParameterResolver.class,
|
||||||
|
RequestHeaderServiceParameterResolver.class,
|
||||||
|
PathVariableServiceParameterResolver.class })
|
||||||
|
static class ParameterResolversConfiguration {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,552 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.alibaba.cloud.dubbo.autoconfigure;
|
||||||
|
|
||||||
|
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
|
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
|
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
|
import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
|
import static com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient.hostToServiceInstanceList;
|
||||||
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentSkipListSet;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.listen.Listenable;
|
||||||
|
import org.apache.curator.framework.listen.ListenerContainer;
|
||||||
|
import org.apache.curator.framework.recipes.cache.ChildData;
|
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCache;
|
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
|
||||||
|
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.registry.NotifyListener;
|
||||||
|
|
||||||
|
import org.apache.zookeeper.Watcher;
|
||||||
|
import org.aspectj.lang.annotation.After;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
|
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||||
|
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
|
||||||
|
import org.springframework.cloud.consul.discovery.ConsulCatalogWatch;
|
||||||
|
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||||
|
import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryProperties;
|
||||||
|
import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceWatch;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.TaskScheduler;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import com.alibaba.cloud.dubbo.env.DubboCloudProperties;
|
||||||
|
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
import com.alibaba.cloud.dubbo.registry.AbstractSpringCloudRegistry;
|
||||||
|
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent;
|
||||||
|
import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent;
|
||||||
|
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
|
||||||
|
import com.alibaba.cloud.nacos.discovery.NacosWatch;
|
||||||
|
import com.alibaba.nacos.api.exception.NacosException;
|
||||||
|
import com.alibaba.nacos.api.naming.NamingService;
|
||||||
|
import com.alibaba.nacos.api.naming.listener.NamingEvent;
|
||||||
|
import com.netflix.discovery.CacheRefreshedEvent;
|
||||||
|
import com.netflix.discovery.shared.Applications;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo Service Discovery Auto {@link Configuration} (after
|
||||||
|
* {@link DubboServiceRegistrationAutoConfiguration})
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
* @see DubboServiceRegistrationAutoConfiguration
|
||||||
|
* @see Configuration
|
||||||
|
* @see DiscoveryClient
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(name = "org.springframework.cloud.client.discovery.DiscoveryClient")
|
||||||
|
@ConditionalOnProperty(name = "spring.cloud.discovery.enabled", matchIfMissing = true)
|
||||||
|
@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
|
||||||
|
ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME,
|
||||||
|
CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME,
|
||||||
|
NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME }, value = {
|
||||||
|
DubboServiceRegistrationAutoConfiguration.class })
|
||||||
|
public class DubboServiceDiscoveryAutoConfiguration {
|
||||||
|
|
||||||
|
public static final String ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryAutoConfiguration";
|
||||||
|
|
||||||
|
public static final String CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration";
|
||||||
|
|
||||||
|
public static final String NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration";
|
||||||
|
|
||||||
|
private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
private final DiscoveryClient discoveryClient;
|
||||||
|
|
||||||
|
private final AtomicReference<Object> heartbeatState = new AtomicReference<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #defaultHeartbeatEventChangePredicate()
|
||||||
|
*/
|
||||||
|
private final ObjectProvider<Predicate<HeartbeatEvent>> heartbeatEventChangedPredicate;
|
||||||
|
|
||||||
|
public DubboServiceDiscoveryAutoConfiguration(
|
||||||
|
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||||
|
ApplicationEventPublisher applicationEventPublisher,
|
||||||
|
DiscoveryClient discoveryClient,
|
||||||
|
ObjectProvider<Predicate<HeartbeatEvent>> heartbeatEventChangedPredicate) {
|
||||||
|
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
|
||||||
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
|
this.discoveryClient = discoveryClient;
|
||||||
|
this.heartbeatEventChangedPredicate = heartbeatEventChangedPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a {@link ServiceInstancesChangedEvent}
|
||||||
|
*
|
||||||
|
* @param serviceName the name of service
|
||||||
|
* @param serviceInstances the {@link ServiceInstance instances} of some service
|
||||||
|
* @see AbstractSpringCloudRegistry#registerServiceInstancesChangedEventListener(URL,
|
||||||
|
* NotifyListener)
|
||||||
|
*/
|
||||||
|
private void dispatchServiceInstancesChangedEvent(String serviceName,
|
||||||
|
Collection<ServiceInstance> serviceInstances) {
|
||||||
|
if (!hasText(serviceName) || serviceInstances == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(serviceName,
|
||||||
|
serviceInstances);
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
logger.info(
|
||||||
|
"The event of the service instances[name : {} , size : {}] change is about to be dispatched",
|
||||||
|
serviceName, serviceInstances.size());
|
||||||
|
}
|
||||||
|
applicationEventPublisher.publishEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ServiceInstance> getInstances(String serviceName) {
|
||||||
|
return discoveryClient.getInstances(serviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a {@link ServiceInstancesChangedEvent} when the {@link HeartbeatEvent}
|
||||||
|
* raised, use for these scenarios:
|
||||||
|
* <ul>
|
||||||
|
* <li>Eureka : {@link CloudEurekaClient#onCacheRefreshed()} publishes a
|
||||||
|
* {@link HeartbeatEvent} instead of {@link CacheRefreshedEvent}</li>
|
||||||
|
* <li>Zookeeper :
|
||||||
|
* {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)}
|
||||||
|
* publishes a {@link HeartbeatEvent} when
|
||||||
|
* {@link ZookeeperDiscoveryProperties#getRoot() the services' root path} has been
|
||||||
|
* changed</li>
|
||||||
|
* <li>Consul : {@link ConsulCatalogWatch#catalogServicesWatch()} publishes a
|
||||||
|
* {@link HeartbeatEvent} when
|
||||||
|
* <a href="https://www.consul.io/api/features/blocking.html">Consul's Blocking
|
||||||
|
* Queries response</a></li>
|
||||||
|
* <li>Nacos : {@link NacosWatch#nacosServicesWatch()} publishes a
|
||||||
|
* {@link HeartbeatEvent} under a {@link TaskScheduler} every
|
||||||
|
* {@link NacosDiscoveryProperties#getWatchDelay()} milliseconds</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* In order to reduce the duplicated handling for
|
||||||
|
* {@link ServiceInstancesChangedEvent},
|
||||||
|
* {@link #defaultHeartbeatEventChangePredicate()} method providers the default
|
||||||
|
* implementation to detect whether the {@link HeartbeatEvent#getValue() state} is
|
||||||
|
* changed or not. If and only if changed, the
|
||||||
|
* {@link #dispatchServiceInstancesChangedEvent(String, Collection)} will be executed.
|
||||||
|
* <p>
|
||||||
|
* <b>Note : </b> Spring Cloud {@link HeartbeatEvent} has a critical flaw that can't
|
||||||
|
* figure out which service was changed precisely, it's just used for a notification
|
||||||
|
* that the {@link DubboServiceMetadataRepository#getSubscribedServices() subscribed
|
||||||
|
* services} used to {@link NotifyListener#notify(List) notify} the Dubbo consumer
|
||||||
|
* cached {@link URL URLs}. Because of some {@link DiscoveryClient} implementations
|
||||||
|
* have the better and fine-grained the event mechanism for service instances change,
|
||||||
|
* thus {@link HeartbeatEvent} handle will be ignored in these scenarios:
|
||||||
|
* <ul>
|
||||||
|
* <li>Zookeeper : {@link Watcher}, see
|
||||||
|
* {@link ZookeeperConfiguration#heartbeatEventChangedPredicate()}</li>
|
||||||
|
* <li>Nacos : {@link com.alibaba.nacos.api.naming.listener.EventListener} , see
|
||||||
|
* {@link NacosConfiguration#heartbeatEventChangedPredicate()}</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* If the customized {@link DiscoveryClient} also providers the similar mechanism, the
|
||||||
|
* implementation could declare a Spring Bean of {@link Predicate} of
|
||||||
|
* {@link HeartbeatEvent} to override {@link #defaultHeartbeatEventChangePredicate()
|
||||||
|
* default one}.
|
||||||
|
*
|
||||||
|
* @param event the instance of {@link HeartbeatEvent}
|
||||||
|
* @see HeartbeatEvent
|
||||||
|
*/
|
||||||
|
@EventListener(HeartbeatEvent.class)
|
||||||
|
public void onHeartbeatEvent(HeartbeatEvent event) {
|
||||||
|
/**
|
||||||
|
* Try to re-initialize the subscribed services, in order to sense the change of
|
||||||
|
* services if {@link DubboCloudProperties#getSubscribedServices()} is wildcard
|
||||||
|
* that indicates all services should be subscribed.
|
||||||
|
*/
|
||||||
|
Stream<String> subscribedServices = dubboServiceMetadataRepository
|
||||||
|
.initSubscribedServices();
|
||||||
|
|
||||||
|
heartbeatEventChangedPredicate.ifAvailable(predicate -> {
|
||||||
|
if (predicate.test(event)) {
|
||||||
|
// Dispatch ServiceInstancesChangedEvent for each service
|
||||||
|
subscribedServices.forEach(serviceName -> {
|
||||||
|
List<ServiceInstance> serviceInstances = getInstances(serviceName);
|
||||||
|
dispatchServiceInstancesChangedEvent(serviceName, serviceInstances);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default {@link Predicate} implementation of {@link HeartbeatEvent} based on the
|
||||||
|
* comparison between previous and current {@link HeartbeatEvent#getValue() state
|
||||||
|
* value}, the {@link DiscoveryClient} implementation may override current.
|
||||||
|
*
|
||||||
|
* @return {@link Predicate<HeartbeatEvent>}
|
||||||
|
* @see EurekaConfiguration#heartbeatEventChangedPredicate()
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public Predicate<HeartbeatEvent> defaultHeartbeatEventChangePredicate() {
|
||||||
|
return event -> {
|
||||||
|
Object oldState = heartbeatState.get();
|
||||||
|
Object newState = event.getValue();
|
||||||
|
return heartbeatState.compareAndSet(oldState, newState)
|
||||||
|
&& !Objects.equals(oldState, newState);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eureka Customized Configuration
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
|
public class EurekaConfiguration {
|
||||||
|
|
||||||
|
private final AtomicReference<String> appsHashCodeCache = new AtomicReference<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare {@link Applications#getAppsHashCode() apps hash code} between last
|
||||||
|
* {@link Applications} and current.
|
||||||
|
*
|
||||||
|
* @see Applications#getAppsHashCode()
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Predicate<HeartbeatEvent> heartbeatEventChangedPredicate() {
|
||||||
|
return event -> {
|
||||||
|
String oldAppsHashCode = appsHashCodeCache.get();
|
||||||
|
CloudEurekaClient cloudEurekaClient = (CloudEurekaClient) event
|
||||||
|
.getSource();
|
||||||
|
Applications applications = cloudEurekaClient.getApplications();
|
||||||
|
String appsHashCode = applications.getAppsHashCode();
|
||||||
|
return appsHashCodeCache.compareAndSet(oldAppsHashCode, appsHashCode)
|
||||||
|
&& !Objects.equals(oldAppsHashCode, appsHashCode);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zookeeper Customized Configuration
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnBean(name = ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
|
@Aspect
|
||||||
|
public class ZookeeperConfiguration
|
||||||
|
implements ApplicationListener<InstanceRegisteredEvent> {
|
||||||
|
/**
|
||||||
|
* The pointcut expression for
|
||||||
|
* {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)}
|
||||||
|
*/
|
||||||
|
public static final String CHILD_EVENT_POINTCUT_EXPRESSION = "execution(void org.springframework.cloud.zookeeper.discovery.ZookeeperServiceWatch.childEvent(..)) && args(client,event)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path separator of Zookeeper node
|
||||||
|
*/
|
||||||
|
public static final String NODE_PATH_SEPARATOR = "/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path variable name for the name of service
|
||||||
|
*/
|
||||||
|
private static final String SERVICE_NAME_PATH_VARIABLE_NAME = "serviceName";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path variable name for the id of {@link ServiceInstance service instance}
|
||||||
|
*/
|
||||||
|
private static final String SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME = "serviceInstanceId";
|
||||||
|
|
||||||
|
private final ZookeeperServiceWatch zookeeperServiceWatch;
|
||||||
|
|
||||||
|
private final String rootPath;
|
||||||
|
|
||||||
|
private final AntPathMatcher pathMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ant Path pattern for {@link ServiceInstance} :
|
||||||
|
* <p>
|
||||||
|
* <p>
|
||||||
|
* ${{@link #rootPath}}/{serviceName}/{serviceInstanceId}
|
||||||
|
*
|
||||||
|
* @see #rootPath
|
||||||
|
* @see #SERVICE_NAME_PATH_VARIABLE_NAME
|
||||||
|
* @see #SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME
|
||||||
|
*/
|
||||||
|
private final String serviceInstancePathPattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ThreadLocal} holds the processed service name
|
||||||
|
*/
|
||||||
|
private final ThreadLocal<String> processedServiceNameThreadLocal;
|
||||||
|
|
||||||
|
ZookeeperConfiguration(ZookeeperDiscoveryProperties zookeeperDiscoveryProperties,
|
||||||
|
ZookeeperServiceWatch zookeeperServiceWatch) {
|
||||||
|
this.zookeeperServiceWatch = zookeeperServiceWatch;
|
||||||
|
this.rootPath = zookeeperDiscoveryProperties.getRoot();
|
||||||
|
this.pathMatcher = new AntPathMatcher(NODE_PATH_SEPARATOR);
|
||||||
|
this.serviceInstancePathPattern = rootPath + NODE_PATH_SEPARATOR + "{"
|
||||||
|
+ SERVICE_NAME_PATH_VARIABLE_NAME + "}" + NODE_PATH_SEPARATOR + "{"
|
||||||
|
+ SERVICE_INSTANCE_ID_PATH_VARIABLE_NAME + "}";
|
||||||
|
this.processedServiceNameThreadLocal = new ThreadLocal<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zookeeper uses {@link TreeCacheEvent} to trigger
|
||||||
|
* {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus
|
||||||
|
* {@link HeartbeatEvent} handle is always ignored
|
||||||
|
*
|
||||||
|
* @return <code>false</code> forever
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Predicate<HeartbeatEvent> heartbeatEventChangedPredicate() {
|
||||||
|
return event -> false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle on {@link InstanceRegisteredEvent} after
|
||||||
|
* {@link ZookeeperServiceWatch#onApplicationEvent(InstanceRegisteredEvent)}
|
||||||
|
*
|
||||||
|
* @param event {@link InstanceRegisteredEvent}
|
||||||
|
* @see #reattachTreeCacheListeners()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(InstanceRegisteredEvent event) {
|
||||||
|
reattachTreeCacheListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-attach the {@link TreeCacheListener TreeCacheListeners}
|
||||||
|
*/
|
||||||
|
private void reattachTreeCacheListeners() {
|
||||||
|
|
||||||
|
TreeCache treeCache = zookeeperServiceWatch.getCache();
|
||||||
|
|
||||||
|
Listenable<TreeCacheListener> listenable = treeCache.getListenable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All registered TreeCacheListeners except {@link ZookeeperServiceWatch}.
|
||||||
|
* Usually, "otherListeners" will be empty because Spring Cloud Zookeeper only
|
||||||
|
* adds "zookeeperServiceWatch" bean as {@link TreeCacheListener}
|
||||||
|
*/
|
||||||
|
List<TreeCacheListener> otherListeners = new LinkedList<>();
|
||||||
|
|
||||||
|
if (listenable instanceof ListenerContainer) {
|
||||||
|
ListenerContainer<TreeCacheListener> listenerContainer = (ListenerContainer) listenable;
|
||||||
|
listenerContainer.forEach(listener -> {
|
||||||
|
/**
|
||||||
|
* Even though "listener" is an instance of
|
||||||
|
* {@link ZookeeperServiceWatch}, "zookeeperServiceWatch" bean that
|
||||||
|
* was enhanced by AOP is different from the former, thus it's
|
||||||
|
* required to exclude "listener"
|
||||||
|
*/
|
||||||
|
if (!(listener instanceof ZookeeperServiceWatch)) {
|
||||||
|
otherListeners.add(listener);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove all TreeCacheListeners temporarily
|
||||||
|
listenerContainer.clear();
|
||||||
|
// re-store zookeeperServiceWatch, and make sure it's first one
|
||||||
|
// now "beforeChildEvent" is available for Spring AOP
|
||||||
|
listenerContainer.addListener(zookeeperServiceWatch);
|
||||||
|
// re-store others
|
||||||
|
otherListeners.forEach(listenerContainer::addListener);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (logger.isWarnEnabled()) {
|
||||||
|
logger.warn(
|
||||||
|
"Tell me which version Curator framework current application used? I will do better :D");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to {@link #dispatchServiceInstancesChangedEvent(String, Collection)
|
||||||
|
* dispatch} {@link ServiceInstancesChangedEvent} before
|
||||||
|
* {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)}
|
||||||
|
* execution if required
|
||||||
|
*
|
||||||
|
* @param client {@link CuratorFramework}
|
||||||
|
* @param event {@link TreeCacheEvent}
|
||||||
|
*/
|
||||||
|
@Before(CHILD_EVENT_POINTCUT_EXPRESSION)
|
||||||
|
public void beforeChildEvent(CuratorFramework client, TreeCacheEvent event) {
|
||||||
|
if (supportsEventType(event)) {
|
||||||
|
String serviceName = resolveServiceName(event);
|
||||||
|
if (hasText(serviceName)) {
|
||||||
|
dispatchServiceInstancesChangedEvent(serviceName,
|
||||||
|
getInstances(serviceName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After(CHILD_EVENT_POINTCUT_EXPRESSION)
|
||||||
|
public void afterChildEvent(CuratorFramework client, TreeCacheEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the name of service
|
||||||
|
*
|
||||||
|
* @param event {@link TreeCacheEvent}
|
||||||
|
* @return If the Zookeeper's {@link ChildData#getPath() node path} that was
|
||||||
|
* notified comes from {@link ServiceInstance the service instance}, return it's
|
||||||
|
* parent path as the service name, or return <code>null</code>
|
||||||
|
*/
|
||||||
|
private String resolveServiceName(TreeCacheEvent event) {
|
||||||
|
ChildData childData = event.getData();
|
||||||
|
String path = childData.getPath();
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("ZK node[path : {}] event type : {}", path, event.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
String serviceName = null;
|
||||||
|
|
||||||
|
if (pathMatcher.match(serviceInstancePathPattern, path)) {
|
||||||
|
Map<String, String> variables = pathMatcher
|
||||||
|
.extractUriTemplateVariables(serviceInstancePathPattern, path);
|
||||||
|
serviceName = variables.get(SERVICE_NAME_PATH_VARIABLE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link TreeCacheEvent#getType() event type} is supported or not
|
||||||
|
*
|
||||||
|
* @param event {@link TreeCacheEvent}
|
||||||
|
* @return the rule is same as
|
||||||
|
* {@link ZookeeperServiceWatch#childEvent(CuratorFramework, TreeCacheEvent)}
|
||||||
|
* method
|
||||||
|
*/
|
||||||
|
private boolean supportsEventType(TreeCacheEvent event) {
|
||||||
|
TreeCacheEvent.Type eventType = event.getType();
|
||||||
|
return eventType.equals(TreeCacheEvent.Type.NODE_ADDED)
|
||||||
|
|| eventType.equals(TreeCacheEvent.Type.NODE_REMOVED)
|
||||||
|
|| eventType.equals(TreeCacheEvent.Type.NODE_UPDATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consul Customized Configuration
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnBean(name = CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
|
class ConsulConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nacos Customized Configuration
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnBean(name = NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
|
class NacosConfiguration {
|
||||||
|
|
||||||
|
private final NamingService namingService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the set of services is listening
|
||||||
|
*/
|
||||||
|
private final Set<String> listeningServices;
|
||||||
|
|
||||||
|
NacosConfiguration(NacosDiscoveryProperties nacosDiscoveryProperties) {
|
||||||
|
this.namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||||
|
this.listeningServices = new ConcurrentSkipListSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nacos uses {@link EventListener} to trigger
|
||||||
|
* {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus
|
||||||
|
* {@link HeartbeatEvent} handle is always ignored
|
||||||
|
*
|
||||||
|
* @return <code>false</code> forever
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Predicate<HeartbeatEvent> heartbeatEventChangedPredicate() {
|
||||||
|
return event -> false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(SubscribedServicesChangedEvent.class)
|
||||||
|
public void onSubscribedServicesChangedEvent(SubscribedServicesChangedEvent event)
|
||||||
|
throws Exception {
|
||||||
|
// subscribe EventListener for each service
|
||||||
|
event.getNewSubscribedServices().forEach(this::subscribeEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void subscribeEventListener(String serviceName) {
|
||||||
|
if (listeningServices.add(serviceName)) {
|
||||||
|
try {
|
||||||
|
namingService.subscribe(serviceName, event -> {
|
||||||
|
if (event instanceof NamingEvent) {
|
||||||
|
NamingEvent namingEvent = (NamingEvent) event;
|
||||||
|
List<ServiceInstance> serviceInstances = hostToServiceInstanceList(
|
||||||
|
namingEvent.getInstances(), serviceName);
|
||||||
|
dispatchServiceInstancesChangedEvent(serviceName,
|
||||||
|
serviceInstances);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (NacosException e) {
|
||||||
|
ReflectionUtils.rethrowRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.autoconfigure;
|
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.CONSUL_AUTO_SERVICE_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.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
|
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
|
||||||
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
|
import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
|
||||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
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.RegistryConfig;
|
||||||
import org.apache.dubbo.config.spring.ServiceBean;
|
import org.apache.dubbo.config.spring.ServiceBean;
|
||||||
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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.metadata.repository.DubboServiceMetadataRepository;
|
||||||
import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
|
import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
|
||||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||||
|
|
||||||
import com.ecwid.consul.v1.agent.model.NewService;
|
import com.ecwid.consul.v1.agent.model.NewService;
|
||||||
import com.netflix.appinfo.InstanceInfo;
|
import com.netflix.appinfo.InstanceInfo;
|
||||||
|
|
||||||
@@ -68,19 +68,19 @@ import com.netflix.appinfo.InstanceInfo;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@Import({ DubboServiceRegistrationEventPublishingAspect.class })
|
@Import({ DubboServiceRegistrationEventPublishingAspect.class })
|
||||||
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
||||||
@AutoConfigureAfter(name = { EUREKA_AUTO_CONFIGURATION_CLASS_NAME,
|
@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
|
||||||
CONSUL_AUTO_CONFIGURATION_CLASS_NAME,
|
CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME,
|
||||||
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" }, value = {
|
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" }, value = {
|
||||||
DubboMetadataAutoConfiguration.class })
|
DubboMetadataAutoConfiguration.class })
|
||||||
public class DubboServiceRegistrationAutoConfiguration {
|
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
|
private static final Logger logger = LoggerFactory
|
||||||
.getLogger(DubboServiceRegistrationAutoConfiguration.class);
|
.getLogger(DubboServiceRegistrationAutoConfiguration.class);
|
||||||
@@ -100,8 +100,26 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
attachDubboMetadataServiceMetadata(registration);
|
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
|
@Configuration
|
||||||
@ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME)
|
@ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
@Aspect
|
@Aspect
|
||||||
class EurekaConfiguration implements SmartInitializingSingleton {
|
class EurekaConfiguration implements SmartInitializingSingleton {
|
||||||
|
|
||||||
@@ -136,7 +154,7 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME)
|
@ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
@AutoConfigureOrder
|
@AutoConfigureOrder
|
||||||
class ConsulConfiguration {
|
class ConsulConfiguration {
|
||||||
|
|
||||||
@@ -151,7 +169,7 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
Registration registration = event.getSource();
|
Registration registration = event.getSource();
|
||||||
Class<?> registrationClass = AopUtils.getTargetClass(registration);
|
Class<?> registrationClass = AopUtils.getTargetClass(registration);
|
||||||
String registrationClassName = registrationClass.getName();
|
String registrationClassName = registrationClass.getName();
|
||||||
if (CONSUL_AUTO_REGISTRATION_CLASS_NAME
|
if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME
|
||||||
.equalsIgnoreCase(registrationClassName)) {
|
.equalsIgnoreCase(registrationClassName)) {
|
||||||
ConsulRegistration consulRegistration = (ConsulRegistration) registration;
|
ConsulRegistration consulRegistration = (ConsulRegistration) registration;
|
||||||
attachURLsIntoMetadata(consulRegistration);
|
attachURLsIntoMetadata(consulRegistration);
|
||||||
@@ -170,22 +188,4 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attachDubboMetadataServiceMetadata(Registration registration) {
|
|
||||||
if (registration == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
synchronized (registration) {
|
|
||||||
Map<String, String> metadata = registration.getMetadata();
|
|
||||||
attachDubboMetadataServiceMetadata(metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
|
|
||||||
Map<String, String> serviceMetadata = dubboServiceMetadataRepository
|
|
||||||
.getDubboMetadataServiceMetadata();
|
|
||||||
if (!isEmpty(serviceMetadata)) {
|
|
||||||
metadata.putAll(serviceMetadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,13 +16,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.autoconfigure;
|
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.CONSUL_AUTO_SERVICE_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.ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.config.spring.ServiceBean;
|
import org.apache.dubbo.config.spring.ServiceBean;
|
||||||
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
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.metadata.repository.DubboServiceMetadataRepository;
|
||||||
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||||
|
|
||||||
import com.ecwid.consul.v1.agent.model.NewService;
|
import com.ecwid.consul.v1.agent.model.NewService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,7 +117,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnBean(name = ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME)
|
@ConditionalOnBean(name = ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
class ZookeeperConfiguration implements SmartInitializingSingleton {
|
class ZookeeperConfiguration implements SmartInitializingSingleton {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -138,7 +138,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME)
|
@ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME)
|
||||||
class ConsulConfiguration {
|
class ConsulConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.alibaba.cloud.dubbo.registry.SpringCloudRegistry;
|
|||||||
/**
|
/**
|
||||||
* Missing {@link SpringCloudRegistry} Property {@link Condition}
|
* Missing {@link SpringCloudRegistry} Property {@link Condition}
|
||||||
*
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
* @see SpringCloudRegistry
|
* @see SpringCloudRegistry
|
||||||
* @see Condition
|
* @see Condition
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericException;
|
import org.apache.dubbo.rpc.service.GenericException;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericException;
|
import org.apache.dubbo.rpc.service.GenericException;
|
||||||
|
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class DubboMetadataInitializerInterceptor implements ClientHttpRequestInt
|
|||||||
|
|
||||||
String serviceName = originalUri.getHost();
|
String serviceName = originalUri.getHost();
|
||||||
|
|
||||||
repository.initialize(serviceName);
|
repository.initializeMetadata(serviceName);
|
||||||
|
|
||||||
// Execute next
|
// Execute next
|
||||||
return execution.execute(request, body);
|
return execution.execute(request, body);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericException;
|
import org.apache.dubbo.rpc.service.GenericException;
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
|
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
|
||||||
import org.springframework.http.HttpRequest;
|
import org.springframework.http.HttpRequest;
|
||||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ public class DubboNonWebApplicationEnvironmentPostProcessor
|
|||||||
private final Logger logger = LoggerFactory
|
private final Logger logger = LoggerFactory
|
||||||
.getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class);
|
.getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class);
|
||||||
|
|
||||||
|
private static boolean isRestProtocol(String protocol) {
|
||||||
|
return REST_PROTOCOL.equalsIgnoreCase(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postProcessEnvironment(ConfigurableEnvironment environment,
|
public void postProcessEnvironment(ConfigurableEnvironment environment,
|
||||||
SpringApplication application) {
|
SpringApplication application) {
|
||||||
@@ -219,8 +223,4 @@ public class DubboNonWebApplicationEnvironmentPostProcessor
|
|||||||
public int getOrder() { // Keep LOWEST_PRECEDENCE
|
public int getOrder() { // Keep LOWEST_PRECEDENCE
|
||||||
return LOWEST_PRECEDENCE;
|
return LOWEST_PRECEDENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isRestProtocol(String protocol) {
|
|
||||||
return REST_PROTOCOL.equalsIgnoreCase(protocol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
|
import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpInputMessage;
|
import org.springframework.http.HttpInputMessage;
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ public class DefaultHttpRequest implements HttpRequest {
|
|||||||
this.headers.putAll(headers);
|
this.headers.putAll(headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
private URI buildURI(String path, Map<String, List<String>> params) {
|
private URI buildURI(String path, Map<String, List<String>> params) {
|
||||||
UriComponentsBuilder builder = fromPath(path)
|
UriComponentsBuilder builder = fromPath(path)
|
||||||
.queryParams(new LinkedMultiValueMap<>(params));
|
.queryParams(new LinkedMultiValueMap<>(params));
|
||||||
@@ -60,6 +64,7 @@ public class DefaultHttpRequest implements HttpRequest {
|
|||||||
return HttpMethod.resolve(getMethodValue());
|
return HttpMethod.resolve(getMethodValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getMethodValue() {
|
public String getMethodValue() {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
@@ -74,10 +79,6 @@ public class DefaultHttpRequest implements HttpRequest {
|
|||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Builder builder() {
|
|
||||||
return new Builder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HttpRequest} Builder
|
* {@link HttpRequest} Builder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public class MutableHttpServerRequest implements HttpServerRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Override method since Spring Framework 5.0
|
// Override method since Spring Framework 5.0
|
||||||
|
@Override
|
||||||
public String getMethodValue() {
|
public String getMethodValue() {
|
||||||
return httpMethod.name();
|
return httpMethod.name();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,26 @@ public class HttpRequestConsumersMatcher extends AbstractHttpRequestMatcher {
|
|||||||
Collections.sort(this.expressions);
|
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
|
@Override
|
||||||
public boolean match(HttpRequest request) {
|
public boolean match(HttpRequest request) {
|
||||||
|
|
||||||
@@ -94,26 +114,6 @@ public class HttpRequestConsumersMatcher extends AbstractHttpRequestMatcher {
|
|||||||
return true;
|
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
|
@Override
|
||||||
protected Collection<ConsumeMediaTypeExpression> getContent() {
|
protected Collection<ConsumeMediaTypeExpression> getContent() {
|
||||||
return this.expressions;
|
return this.expressions;
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ public class HttpRequestParamsMatcher extends AbstractHttpRequestMatcher {
|
|||||||
this.expressions = parseExpressions(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
|
@Override
|
||||||
public boolean match(HttpRequest request) {
|
public boolean match(HttpRequest request) {
|
||||||
if (CollectionUtils.isEmpty(expressions)) {
|
if (CollectionUtils.isEmpty(expressions)) {
|
||||||
@@ -56,14 +64,6 @@ public class HttpRequestParamsMatcher extends AbstractHttpRequestMatcher {
|
|||||||
return false;
|
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
|
@Override
|
||||||
protected Collection<ParamExpression> getContent() {
|
protected Collection<ParamExpression> getContent() {
|
||||||
return this.expressions;
|
return this.expressions;
|
||||||
|
|||||||
@@ -45,6 +45,17 @@ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher {
|
|||||||
this.pathMatcher = new AntPathMatcher();
|
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
|
@Override
|
||||||
public boolean match(HttpRequest request) {
|
public boolean match(HttpRequest request) {
|
||||||
List<String> matches = getMatchingPatterns(request);
|
List<String> matches = getMatchingPatterns(request);
|
||||||
@@ -94,17 +105,6 @@ public class HttpRequestPathMatcher extends AbstractHttpRequestMatcher {
|
|||||||
return uri.getPath();
|
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
|
@Override
|
||||||
protected Collection<String> getContent() {
|
protected Collection<String> getContent() {
|
||||||
return this.patterns;
|
return this.patterns;
|
||||||
|
|||||||
@@ -70,26 +70,6 @@ public class HttpRequestProducesMatcher extends AbstractHttpRequestMatcher {
|
|||||||
Collections.sort(this.expressions);
|
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,
|
private static Set<ProduceMediaTypeExpression> parseExpressions(String[] produces,
|
||||||
String[] headers) {
|
String[] headers) {
|
||||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>();
|
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>();
|
||||||
@@ -111,6 +91,26 @@ public class HttpRequestProducesMatcher extends AbstractHttpRequestMatcher {
|
|||||||
return result;
|
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
|
@Override
|
||||||
protected Collection<ProduceMediaTypeExpression> getContent() {
|
protected Collection<ProduceMediaTypeExpression> getContent() {
|
||||||
return expressions;
|
return expressions;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.Iterator;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.apache.dubbo.config.ProtocolConfig;
|
import org.apache.dubbo.config.ProtocolConfig;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -45,10 +45,12 @@ public class DubboRestServiceMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (!(o instanceof DubboRestServiceMetadata))
|
}
|
||||||
|
if (!(o instanceof DubboRestServiceMetadata)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
DubboRestServiceMetadata that = (DubboRestServiceMetadata) o;
|
DubboRestServiceMetadata that = (DubboRestServiceMetadata) o;
|
||||||
return Objects.equals(serviceRestMetadata, that.serviceRestMetadata)
|
return Objects.equals(serviceRestMetadata, that.serviceRestMetadata)
|
||||||
&& Objects.equals(restMethodMetadata, that.restMethodMetadata);
|
&& Objects.equals(restMethodMetadata, that.restMethodMetadata);
|
||||||
|
|||||||
@@ -77,10 +77,12 @@ public class DubboTransportedMethodMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (!(o instanceof DubboTransportedMethodMetadata))
|
}
|
||||||
|
if (!(o instanceof DubboTransportedMethodMetadata)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o;
|
DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o;
|
||||||
return Objects.equals(methodMetadata, that.methodMetadata)
|
return Objects.equals(methodMetadata, that.methodMetadata)
|
||||||
&& Objects.equals(attributes, that.attributes);
|
&& Objects.equals(attributes, that.attributes);
|
||||||
|
|||||||
@@ -111,10 +111,12 @@ public class MethodMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (o == null || getClass() != o.getClass())
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
MethodMetadata that = (MethodMetadata) o;
|
MethodMetadata that = (MethodMetadata) o;
|
||||||
return Objects.equals(name, that.name)
|
return Objects.equals(name, that.name)
|
||||||
&& Objects.equals(returnType, that.returnType)
|
&& Objects.equals(returnType, that.returnType)
|
||||||
|
|||||||
@@ -61,10 +61,12 @@ public class MethodParameterMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (o == null || getClass() != o.getClass())
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
MethodParameterMetadata that = (MethodParameterMetadata) o;
|
MethodParameterMetadata that = (MethodParameterMetadata) o;
|
||||||
return index == that.index && Objects.equals(name, that.name)
|
return index == that.index && Objects.equals(name, that.name)
|
||||||
&& Objects.equals(type, that.type);
|
&& Objects.equals(type, that.type);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.metadata;
|
package com.alibaba.cloud.dubbo.metadata;
|
||||||
|
|
||||||
|
import static com.alibaba.cloud.dubbo.http.util.HttpUtils.normalizePath;
|
||||||
import static org.springframework.http.MediaType.parseMediaTypes;
|
import static org.springframework.http.MediaType.parseMediaTypes;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -36,8 +37,6 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import com.alibaba.cloud.dubbo.http.util.HttpUtils;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
@@ -74,6 +73,67 @@ public class RequestMetadata {
|
|||||||
headers(requestTemplate.headers());
|
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() {
|
public String getMethod() {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
@@ -87,7 +147,7 @@ public class RequestMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setPath(String path) {
|
public void setPath(String path) {
|
||||||
this.path = HttpUtils.normalizePath(path);
|
this.path = normalizePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiValueMap<String, String> getParams() {
|
public MultiValueMap<String, String> getParams() {
|
||||||
@@ -180,73 +240,14 @@ public class RequestMetadata {
|
|||||||
return this;
|
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
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (!(o instanceof RequestMetadata))
|
}
|
||||||
|
if (!(o instanceof RequestMetadata)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
RequestMetadata that = (RequestMetadata) o;
|
RequestMetadata that = (RequestMetadata) o;
|
||||||
return Objects.equals(method, that.method) && Objects.equals(path, that.path)
|
return Objects.equals(method, that.method) && Objects.equals(path, that.path)
|
||||||
&& Objects.equals(consumes, that.consumes)
|
&& Objects.equals(consumes, that.consumes)
|
||||||
|
|||||||
@@ -184,10 +184,12 @@ public class RestMethodMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (!(o instanceof RestMethodMetadata))
|
}
|
||||||
|
if (!(o instanceof RestMethodMetadata)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
RestMethodMetadata that = (RestMethodMetadata) o;
|
RestMethodMetadata that = (RestMethodMetadata) o;
|
||||||
return queryMapEncoded == that.queryMapEncoded
|
return queryMapEncoded == that.queryMapEncoded
|
||||||
&& Objects.equals(method, that.method)
|
&& Objects.equals(method, that.method)
|
||||||
|
|||||||
@@ -52,10 +52,12 @@ public class ServiceRestMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
if (!(o instanceof ServiceRestMetadata))
|
}
|
||||||
|
if (!(o instanceof ServiceRestMetadata)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
ServiceRestMetadata that = (ServiceRestMetadata) o;
|
ServiceRestMetadata that = (ServiceRestMetadata) o;
|
||||||
return Objects.equals(url, that.url) && Objects.equals(meta, that.meta);
|
return Objects.equals(url, that.url) && Objects.equals(meta, that.meta);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
|
|||||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||||
import static org.springframework.util.StringUtils.hasText;
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -40,20 +38,25 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
import org.springframework.cloud.commons.util.InetUtils;
|
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.http.HttpRequest;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
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.DubboRestServiceMetadata;
|
||||||
import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
|
import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
|
||||||
import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata;
|
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.DubboMetadataService;
|
||||||
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter;
|
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter;
|
||||||
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
|
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
|
||||||
import com.alibaba.cloud.dubbo.util.JSONUtils;
|
import com.alibaba.cloud.dubbo.util.JSONUtils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
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>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
@Repository
|
@Repository
|
||||||
public class DubboServiceMetadataRepository {
|
public class DubboServiceMetadataRepository
|
||||||
|
implements SmartInitializingSingleton, ApplicationEventPublisherAware {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The prefix of {@link DubboMetadataService} : "dubbo.metadata-service."
|
* The prefix of {@link DubboMetadataService} : "dubbo.metadata-service."
|
||||||
@@ -99,9 +103,14 @@ public class DubboServiceMetadataRepository {
|
|||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
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
|
* 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
|
* {@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<>();
|
private final MultiValueMap<String, URL> allExportedURLs = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
// ====================================================================================
|
// =================================== Registration
|
||||||
// //
|
|
||||||
|
|
||||||
// =================================== Subscription
|
|
||||||
// =================================== //
|
// =================================== //
|
||||||
|
|
||||||
private Set<String> subscribedServices;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The subscribed {@link URL urls} {@link Map} of {@link DubboMetadataService}, whose
|
* 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
|
* 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
|
* 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
|
* Dubbo service, the value is a JSON content of JAX-RS or Spring MVC REST metadata
|
||||||
* from the annotated methods.
|
* from the annotated methods.
|
||||||
*/
|
*/
|
||||||
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
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>
|
* 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
|
@PostConstruct
|
||||||
public void init() {
|
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
|
// Keep the order in following invocations
|
||||||
initSubscribedServices();
|
initSubscribedDubboMetadataService(serviceName);
|
||||||
initSubscribedDubboMetadataServices();
|
initDubboRestServiceMetadataRepository(serviceName);
|
||||||
initDubboRestServiceMetadataRepository();
|
// mark this service name having been initialized
|
||||||
|
initializedServices.add(serviceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -254,19 +365,15 @@ public class DubboServiceMetadataRepository {
|
|||||||
return unmodifiableSet(serviceRestMetadata);
|
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,
|
public List<URL> findSubscribedDubboMetadataServiceURLs(String serviceName,
|
||||||
String group, String version, String protocol) {
|
String group, String version, String protocol) {
|
||||||
String serviceKey = URL.buildKey(serviceName, group, version);
|
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)) {
|
if (isEmpty(urls)) {
|
||||||
return emptyList();
|
return emptyList();
|
||||||
@@ -286,7 +393,7 @@ public class DubboServiceMetadataRepository {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean isSubscribedService(String serviceName) {
|
public boolean isSubscribedService(String serviceName) {
|
||||||
return subscribedServices.contains(serviceName);
|
return doGetSubscribedServices().contains(serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exportURL(URL url) {
|
public void exportURL(URL url) {
|
||||||
@@ -363,7 +470,7 @@ public class DubboServiceMetadataRepository {
|
|||||||
*
|
*
|
||||||
* @param serviceName the service name
|
* @param serviceName the service name
|
||||||
*/
|
*/
|
||||||
public void initialize(String serviceName) {
|
protected void initDubboRestServiceMetadataRepository(String serviceName) {
|
||||||
|
|
||||||
if (dubboRestServiceMetadataRepository.containsKey(serviceName)) {
|
if (dubboRestServiceMetadataRepository.containsKey(serviceName)) {
|
||||||
return;
|
return;
|
||||||
@@ -416,8 +523,16 @@ public class DubboServiceMetadataRepository {
|
|||||||
return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata);
|
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() {
|
public Set<String> getSubscribedServices() {
|
||||||
return Collections.unmodifiableSet(subscribedServices);
|
return unmodifiableSet(doGetSubscribedServices());
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository,
|
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository,
|
||||||
@@ -489,66 +604,30 @@ public class DubboServiceMetadataRepository {
|
|||||||
return metadata;
|
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) {
|
private void excludeSelf(Set<String> subscribedServices) {
|
||||||
subscribedServices.remove(currentApplicationName);
|
subscribedServices.remove(currentApplicationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initSubscribedDubboMetadataServices() {
|
protected void initSubscribedDubboMetadataService(String serviceName) {
|
||||||
// clear subscribedDubboMetadataServiceURLs
|
discoveryClient.getInstances(serviceName).stream().findAny()
|
||||||
subscribedDubboMetadataServiceURLs.clear();
|
.map(this::getDubboMetadataServiceURLs)
|
||||||
|
.ifPresent(dubboMetadataServiceURLs -> {
|
||||||
subscribedServices.stream().map(discoveryClient::getInstances)
|
dubboMetadataServiceURLs.forEach(dubboMetadataServiceURL -> {
|
||||||
.filter(this::isNotEmpty).forEach(serviceInstances -> {
|
try {
|
||||||
ServiceInstance serviceInstance = serviceInstances.get(0);
|
initSubscribedDubboMetadataServiceURL(
|
||||||
getDubboMetadataServiceURLs(serviceInstance)
|
|
||||||
.forEach(dubboMetadataServiceURL -> {
|
|
||||||
initSubscribedDubboMetadataServiceURLs(
|
|
||||||
dubboMetadataServiceURL);
|
dubboMetadataServiceURL);
|
||||||
initDubboMetadataServiceProxy(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
|
// add subscriptions
|
||||||
String serviceKey = dubboMetadataServiceURL.getServiceKey();
|
String serviceKey = dubboMetadataServiceURL.getServiceKey();
|
||||||
subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL);
|
subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL);
|
||||||
@@ -561,11 +640,9 @@ public class DubboServiceMetadataRepository {
|
|||||||
dubboMetadataConfigServiceProxy.initProxy(serviceName, version);
|
dubboMetadataConfigServiceProxy.initProxy(serviceName, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initDubboRestServiceMetadataRepository() {
|
@Override
|
||||||
subscribedServices.forEach(this::initialize);
|
public void setApplicationEventPublisher(
|
||||||
}
|
ApplicationEventPublisher applicationEventPublisher) {
|
||||||
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
private boolean isNotEmpty(Collection collection) {
|
|
||||||
return !CollectionUtils.isEmpty(collection);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.config.spring.ServiceBean;
|
import org.apache.dubbo.config.spring.ServiceBean;
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata;
|
import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.cloud.openfeign.FeignContext;
|
import org.springframework.cloud.openfeign.FeignContext;
|
||||||
@@ -77,6 +78,10 @@ class TargeterInvocationHandler implements InvocationHandler {
|
|||||||
this.contextFactory = contextFactory;
|
this.contextFactory = contextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> T cast(Object object) {
|
||||||
|
return (T) object;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
/**
|
/**
|
||||||
@@ -134,7 +139,7 @@ class TargeterInvocationHandler implements InvocationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update Metadata
|
// Update Metadata
|
||||||
repository.initialize(serviceName);
|
repository.initializeMetadata(serviceName);
|
||||||
|
|
||||||
Map<Method, FeignMethodMetadata> feignMethodMetadataMap = getFeignMethodMetadataMap(
|
Map<Method, FeignMethodMetadata> feignMethodMetadataMap = getFeignMethodMetadataMap(
|
||||||
serviceName, feignRestMethodMetadataMap);
|
serviceName, feignRestMethodMetadataMap);
|
||||||
@@ -180,8 +185,4 @@ class TargeterInvocationHandler implements InvocationHandler {
|
|||||||
|
|
||||||
return feignMethodMetadataMap;
|
return feignMethodMetadataMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T cast(Object object) {
|
|
||||||
return (T) object;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,36 +16,41 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.registry;
|
package com.alibaba.cloud.dubbo.registry;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
import static java.util.Collections.emptyList;
|
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.GROUP_KEY;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_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.PROVIDER_SIDE;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
|
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.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.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
|
||||||
import static org.springframework.util.StringUtils.hasText;
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.function.Function;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.registry.NotifyListener;
|
import org.apache.dubbo.registry.NotifyListener;
|
||||||
import org.apache.dubbo.registry.RegistryFactory;
|
import org.apache.dubbo.registry.RegistryFactory;
|
||||||
import org.apache.dubbo.registry.support.FailbackRegistry;
|
import org.apache.dubbo.registry.support.FailbackRegistry;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
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.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent;
|
||||||
import com.alibaba.cloud.dubbo.service.DubboMetadataService;
|
import com.alibaba.cloud.dubbo.service.DubboMetadataService;
|
||||||
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
|
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
|
||||||
import com.alibaba.cloud.dubbo.util.JSONUtils;
|
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
|
protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class
|
||||||
.getName();
|
.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());
|
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@@ -83,12 +90,12 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
private final JSONUtils jsonUtils;
|
private final JSONUtils jsonUtils;
|
||||||
|
|
||||||
protected final ScheduledExecutorService servicesLookupScheduler;
|
private final ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
public AbstractSpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
public AbstractSpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
||||||
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||||
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
||||||
JSONUtils jsonUtils, ScheduledExecutorService servicesLookupScheduler) {
|
JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) {
|
||||||
super(url);
|
super(url);
|
||||||
this.servicesLookupInterval = url
|
this.servicesLookupInterval = url
|
||||||
.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L);
|
.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L);
|
||||||
@@ -96,7 +103,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
this.repository = dubboServiceMetadataRepository;
|
this.repository = dubboServiceMetadataRepository;
|
||||||
this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy;
|
this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy;
|
||||||
this.jsonUtils = jsonUtils;
|
this.jsonUtils = jsonUtils;
|
||||||
this.servicesLookupScheduler = servicesLookupScheduler;
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean shouldRegister(URL url) {
|
protected boolean shouldRegister(URL url) {
|
||||||
@@ -161,33 +168,103 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
doSubscribeDubboServiceURLs(url, listener);
|
doSubscribeDubboServiceURLs(url, listener);
|
||||||
|
|
||||||
submitSchedulerTaskIfAbsent(url, listener);
|
registerServiceInstancesChangedEventListener(url, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) {
|
/**
|
||||||
String taskId = url.toIdentityString();
|
* Register a {@link ApplicationListener listener} for
|
||||||
if (SCHEDULER_TASKS.add(taskId)) {
|
* {@link ServiceInstancesChangedEvent}
|
||||||
schedule(() -> doSubscribeDubboServiceURLs(url, listener));
|
*
|
||||||
|
* @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();
|
Set<String> subscribedServices = repository.getSubscribedServices();
|
||||||
|
// Sync
|
||||||
|
subscribedServices.forEach(service -> subscribeDubboServiceURL(url, listener,
|
||||||
|
service, this::getServiceInstances));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void subscribeDubboServiceURL(URL url, NotifyListener listener,
|
||||||
|
String serviceName,
|
||||||
|
Function<String, Collection<ServiceInstance>> serviceInstancesFunction) {
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
subscribedServices.stream().map(dubboMetadataConfigServiceProxy::getProxy)
|
|
||||||
.filter(Objects::nonNull).forEach(dubboMetadataService -> {
|
|
||||||
List<URL> exportedURLs = getExportedURLs(dubboMetadataService, url);
|
|
||||||
List<URL> allSubscribedURLs = new LinkedList<>();
|
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) {
|
for (URL exportedURL : exportedURLs) {
|
||||||
String serviceName = exportedURL.getParameter(APPLICATION_KEY);
|
|
||||||
List<ServiceInstance> serviceInstances = getServiceInstances(
|
|
||||||
serviceName);
|
|
||||||
String protocol = exportedURL.getProtocol();
|
String protocol = exportedURL.getProtocol();
|
||||||
List<URL> subscribedURLs = new LinkedList<>();
|
List<URL> subscribedURLs = new LinkedList<>();
|
||||||
serviceInstances.forEach(serviceInstance -> {
|
serviceInstances.forEach(serviceInstance -> {
|
||||||
Integer port = repository
|
Integer port = repository.getDubboProtocolPort(serviceInstance,
|
||||||
.getDubboProtocolPort(serviceInstance, protocol);
|
protocol);
|
||||||
String host = serviceInstance.getHost();
|
String host = serviceInstance.getHost();
|
||||||
if (port == null) {
|
if (port == null) {
|
||||||
if (logger.isWarnEnabled()) {
|
if (logger.isWarnEnabled()) {
|
||||||
@@ -204,17 +281,24 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
allSubscribedURLs.addAll(subscribedURLs);
|
||||||
logger.debug(
|
}
|
||||||
"The subscribed URL[{}] will notify all URLs : {}",
|
|
||||||
url, subscribedURLs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allSubscribedURLs.addAll(subscribedURLs);
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("The subscribed URL[{}] will notify all URLs : {}", url,
|
||||||
|
allSubscribedURLs);
|
||||||
}
|
}
|
||||||
|
|
||||||
listener.notify(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) {
|
private List<ServiceInstance> getServiceInstances(String serviceName) {
|
||||||
@@ -262,7 +346,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
@Override
|
@Override
|
||||||
public final void doUnsubscribe(URL url, NotifyListener listener) {
|
public final void doUnsubscribe(URL url, NotifyListener listener) {
|
||||||
if (isAdminURL(url)) {
|
if (isAdminURL(url)) {
|
||||||
shutdownServiceNamesLookup();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,12 +354,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
return !discoveryClient.getServices().isEmpty();
|
return !discoveryClient.getServices().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void shutdownServiceNamesLookup() {
|
|
||||||
if (servicesLookupScheduler != null) {
|
|
||||||
servicesLookupScheduler.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAdminURL(URL url) {
|
protected boolean isAdminURL(URL url) {
|
||||||
return ADMIN_PROTOCOL.equals(url.getProtocol());
|
return ADMIN_PROTOCOL.equals(url.getProtocol());
|
||||||
}
|
}
|
||||||
@@ -284,9 +361,4 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
protected boolean isDubboMetadataServiceURL(URL url) {
|
protected boolean isDubboMetadataServiceURL(URL url) {
|
||||||
return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface());
|
return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ScheduledFuture<?> schedule(Runnable runnable) {
|
|
||||||
return this.servicesLookupScheduler.scheduleAtFixedRate(runnable,
|
|
||||||
servicesLookupInterval, servicesLookupInterval, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.registry;
|
package com.alibaba.cloud.dubbo.registry;
|
||||||
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.registry.RegistryFactory;
|
import org.apache.dubbo.registry.RegistryFactory;
|
||||||
|
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
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.metadata.repository.DubboServiceMetadataRepository;
|
||||||
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
|
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
|
||||||
@@ -39,9 +39,9 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry {
|
|||||||
public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
||||||
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||||
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
||||||
JSONUtils jsonUtils, ScheduledExecutorService servicesLookupScheduler) {
|
JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) {
|
||||||
super(url, discoveryClient, dubboServiceMetadataRepository,
|
super(url, discoveryClient, dubboServiceMetadataRepository,
|
||||||
dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler);
|
dubboMetadataConfigServiceProxy, jsonUtils, applicationContext);
|
||||||
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
|
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,14 +17,11 @@
|
|||||||
package com.alibaba.cloud.dubbo.registry;
|
package com.alibaba.cloud.dubbo.registry;
|
||||||
|
|
||||||
import static java.lang.System.getProperty;
|
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.URL;
|
||||||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
|
||||||
import org.apache.dubbo.registry.Registry;
|
import org.apache.dubbo.registry.Registry;
|
||||||
import org.apache.dubbo.registry.RegistryFactory;
|
import org.apache.dubbo.registry.RegistryFactory;
|
||||||
|
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
@@ -52,8 +49,6 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
|||||||
|
|
||||||
private static ConfigurableApplicationContext applicationContext;
|
private static ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
private final ScheduledExecutorService servicesLookupScheduler;
|
|
||||||
|
|
||||||
private DiscoveryClient discoveryClient;
|
private DiscoveryClient discoveryClient;
|
||||||
|
|
||||||
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||||
@@ -65,8 +60,11 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
|||||||
private volatile boolean initialized = false;
|
private volatile boolean initialized = false;
|
||||||
|
|
||||||
public SpringCloudRegistryFactory() {
|
public SpringCloudRegistryFactory() {
|
||||||
servicesLookupScheduler = newSingleThreadScheduledExecutor(
|
}
|
||||||
new NamedThreadFactory(SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX));
|
|
||||||
|
public static void setApplicationContext(
|
||||||
|
ConfigurableApplicationContext applicationContext) {
|
||||||
|
SpringCloudRegistryFactory.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init() {
|
protected void init() {
|
||||||
@@ -86,11 +84,6 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
|||||||
init();
|
init();
|
||||||
return new SpringCloudRegistry(url, discoveryClient,
|
return new SpringCloudRegistry(url, discoveryClient,
|
||||||
dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy,
|
dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy,
|
||||||
jsonUtils, servicesLookupScheduler);
|
jsonUtils, applicationContext);
|
||||||
}
|
|
||||||
|
|
||||||
public static void setApplicationContext(
|
|
||||||
ConfigurableApplicationContext applicationContext) {
|
|
||||||
SpringCloudRegistryFactory.applicationContext = applicationContext;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.registry.event;
|
package com.alibaba.cloud.dubbo.registry.event;
|
||||||
|
|
||||||
import java.util.EventObject;
|
|
||||||
|
|
||||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The after-{@link ServiceRegistry#register(Registration) register} event for
|
* 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>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class ServiceInstanceRegisteredEvent extends EventObject {
|
public class ServiceInstanceRegisteredEvent extends ApplicationEvent {
|
||||||
|
|
||||||
public ServiceInstanceRegisteredEvent(Registration source) {
|
public ServiceInstanceRegisteredEvent(Registration source) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.alibaba.cloud.dubbo.registry.event;
|
||||||
|
|
||||||
|
import static java.util.Collections.unmodifiableCollection;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
import org.springframework.context.event.ApplicationEventMulticaster;
|
||||||
|
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event raised after the {@link ServiceInstance instances} of one service has been
|
||||||
|
* changed.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class ServiceInstancesChangedEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
private final String serviceName;
|
||||||
|
|
||||||
|
private final Collection<ServiceInstance> serviceInstances;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current event has been processed or not. Typically, Spring Event was based on sync
|
||||||
|
* {@link ApplicationEventMulticaster}
|
||||||
|
*
|
||||||
|
* @see SimpleApplicationEventMulticaster
|
||||||
|
*/
|
||||||
|
private boolean processed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param serviceName The name of service that was changed
|
||||||
|
* @param serviceInstances all {@link ServiceInstance service instances}
|
||||||
|
* @throws IllegalArgumentException if source is null.
|
||||||
|
*/
|
||||||
|
public ServiceInstancesChangedEvent(String serviceName,
|
||||||
|
Collection<ServiceInstance> serviceInstances) {
|
||||||
|
super(serviceName);
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
this.serviceInstances = unmodifiableCollection(serviceInstances);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The name of service that was changed
|
||||||
|
*/
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return all {@link ServiceInstance service instances}
|
||||||
|
*/
|
||||||
|
public Collection<ServiceInstance> getServiceInstances() {
|
||||||
|
return serviceInstances;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark current event being processed
|
||||||
|
*/
|
||||||
|
public void processed() {
|
||||||
|
processed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current event has been processed or not
|
||||||
|
*
|
||||||
|
* @return if processed, return <code>true</code>, or <code>false</code>
|
||||||
|
*/
|
||||||
|
public boolean isProcessed() {
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.alibaba.cloud.dubbo.registry.event;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ApplicationEvent Event} raised when the subscribed services are changed
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
* @see ApplicationEvent
|
||||||
|
*/
|
||||||
|
public class SubscribedServicesChangedEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
private final Set<String> oldSubscribedServices;
|
||||||
|
|
||||||
|
private final Set<String> newSubscribedServices;
|
||||||
|
|
||||||
|
private final boolean changed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ApplicationEvent.
|
||||||
|
*
|
||||||
|
* @param source the object on which the event initially occurred (never {@code null})
|
||||||
|
* @param oldSubscribedServices the subscribed services before changed
|
||||||
|
* @param newSubscribedServices the subscribed services after changed
|
||||||
|
*/
|
||||||
|
public SubscribedServicesChangedEvent(Object source,
|
||||||
|
Set<String> oldSubscribedServices, Set<String> newSubscribedServices) {
|
||||||
|
super(source);
|
||||||
|
this.oldSubscribedServices = new LinkedHashSet<>(oldSubscribedServices);
|
||||||
|
this.newSubscribedServices = new LinkedHashSet<>(newSubscribedServices);
|
||||||
|
this.changed = !Objects.equals(oldSubscribedServices, newSubscribedServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getOldSubscribedServices() {
|
||||||
|
return oldSubscribedServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getNewSubscribedServices() {
|
||||||
|
return newSubscribedServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChanged() {
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ import org.apache.dubbo.common.utils.CollectionUtils;
|
|||||||
import org.apache.dubbo.config.RegistryConfig;
|
import org.apache.dubbo.config.RegistryConfig;
|
||||||
import org.apache.dubbo.config.spring.ReferenceBean;
|
import org.apache.dubbo.config.spring.ReferenceBean;
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
@@ -118,6 +119,7 @@ public class DubboGenericServiceFactory {
|
|||||||
dataBinder.registerCustomEditor(Map.class, "parameters",
|
dataBinder.registerCustomEditor(Map.class, "parameters",
|
||||||
new PropertyEditorSupport() {
|
new PropertyEditorSupport() {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setAsText(String text)
|
public void setAsText(String text)
|
||||||
throws java.lang.IllegalArgumentException {
|
throws java.lang.IllegalArgumentException {
|
||||||
// Trim all whitespace
|
// Trim all whitespace
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.apache.dubbo.common.URL;
|
|||||||
import org.apache.dubbo.config.ApplicationConfig;
|
import org.apache.dubbo.config.ApplicationConfig;
|
||||||
import org.apache.dubbo.config.ProtocolConfig;
|
import org.apache.dubbo.config.ProtocolConfig;
|
||||||
import org.apache.dubbo.config.ServiceConfig;
|
import org.apache.dubbo.config.ServiceConfig;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ import org.springframework.beans.factory.DisposableBean;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The proxy of {@link DubboMetadataService}
|
* The proxy of {@link DubboMetadataService}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean {
|
public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean {
|
||||||
|
|
||||||
private final DubboGenericServiceFactory dubboGenericServiceFactory;
|
private final DubboGenericServiceFactory dubboGenericServiceFactory;
|
||||||
|
|
||||||
private ClassLoader classLoader;
|
|
||||||
|
|
||||||
private final Map<String, DubboMetadataService> dubboMetadataServiceCache = new ConcurrentHashMap<>();
|
private final Map<String, DubboMetadataService> dubboMetadataServiceCache = new ConcurrentHashMap<>();
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
public DubboMetadataServiceProxy(
|
public DubboMetadataServiceProxy(
|
||||||
DubboGenericServiceFactory dubboGenericServiceFactory) {
|
DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
|||||||
@@ -58,15 +58,15 @@ public abstract class AbstractDubboGenericServiceParameterResolver
|
|||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrder(int order) {
|
|
||||||
this.order = order;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOrder(int order) {
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
|
||||||
protected Class<?> resolveClass(String className) {
|
protected Class<?> resolveClass(String className) {
|
||||||
return resolveClassName(className, classLoader);
|
return resolveClassName(className, classLoader);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.alibaba.cloud.dubbo.service.parameter;
|
package com.alibaba.cloud.dubbo.service.parameter;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
import com.alibaba.cloud.dubbo.http.HttpServerRequest;
|
import com.alibaba.cloud.dubbo.http.HttpServerRequest;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.stream.Collectors;
|
|||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
|
|||||||
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
|
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
|
||||||
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\
|
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\
|
||||||
com.alibaba.cloud.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\
|
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=\
|
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\
|
||||||
com.alibaba.cloud.dubbo.actuate.DubboMetadataEndpointAutoConfiguration
|
com.alibaba.cloud.dubbo.actuate.DubboMetadataEndpointAutoConfiguration
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.http.matcher;
|
package com.alibaba.cloud.dubbo.http.matcher;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AbstractMediaTypeExpression} Test
|
* {@link AbstractMediaTypeExpression} Test
|
||||||
*
|
*
|
||||||
@@ -32,14 +32,12 @@ import org.springframework.http.MediaType;
|
|||||||
public abstract class AbstractMediaTypeExpressionTest<T extends AbstractMediaTypeExpression> {
|
public abstract class AbstractMediaTypeExpressionTest<T extends AbstractMediaTypeExpression> {
|
||||||
|
|
||||||
protected T createExpression(String expression) {
|
protected T createExpression(String expression) {
|
||||||
ResolvableType resolvableType = ResolvableType
|
ResolvableType resolvableType = ResolvableType.forType(getClass().getGenericSuperclass());
|
||||||
.forType(getClass().getGenericSuperclass());
|
|
||||||
Class<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
Class<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
||||||
Constructor<T> constructor = null;
|
Constructor<T> constructor = null;
|
||||||
try {
|
try {
|
||||||
constructor = firstGenericType.getDeclaredConstructor(String.class);
|
constructor = firstGenericType.getDeclaredConstructor(String.class);
|
||||||
}
|
} catch (NoSuchMethodException e) {
|
||||||
catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return BeanUtils.instantiateClass(constructor, expression);
|
return BeanUtils.instantiateClass(constructor, expression);
|
||||||
@@ -48,8 +46,7 @@ public abstract class AbstractMediaTypeExpressionTest<T extends AbstractMediaTyp
|
|||||||
@Test
|
@Test
|
||||||
public void testGetMediaTypeAndNegated() {
|
public void testGetMediaTypeAndNegated() {
|
||||||
// Normal
|
// Normal
|
||||||
AbstractMediaTypeExpression expression = createExpression(
|
AbstractMediaTypeExpression expression = createExpression(MediaType.APPLICATION_JSON_VALUE);
|
||||||
MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
Assert.assertEquals(MediaType.APPLICATION_JSON, expression.getMediaType());
|
Assert.assertEquals(MediaType.APPLICATION_JSON, expression.getMediaType());
|
||||||
Assert.assertFalse(expression.isNegated());
|
Assert.assertFalse(expression.isNegated());
|
||||||
|
|
||||||
@@ -61,15 +58,14 @@ public abstract class AbstractMediaTypeExpressionTest<T extends AbstractMediaTyp
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEqualsAndHashCode() {
|
public void testEqualsAndHashCode() {
|
||||||
Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE),
|
Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE), createExpression(MediaType.APPLICATION_JSON_VALUE));
|
||||||
createExpression(MediaType.APPLICATION_JSON_VALUE));
|
|
||||||
Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode(),
|
Assert.assertEquals(createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode(),
|
||||||
createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode());
|
createExpression(MediaType.APPLICATION_JSON_VALUE).hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCompareTo() {
|
public void testCompareTo() {
|
||||||
Assert.assertEquals(0, createExpression(MediaType.APPLICATION_JSON_VALUE)
|
Assert.assertEquals(0,
|
||||||
.compareTo(createExpression(MediaType.APPLICATION_JSON_VALUE)));
|
createExpression(MediaType.APPLICATION_JSON_VALUE).compareTo(createExpression(MediaType.APPLICATION_JSON_VALUE)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.http.matcher;
|
package com.alibaba.cloud.dubbo.http.matcher;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AbstractNameValueExpression} Test
|
* {@link AbstractNameValueExpression} Test
|
||||||
*
|
*
|
||||||
@@ -31,14 +31,12 @@ import org.springframework.core.ResolvableType;
|
|||||||
public abstract class AbstractNameValueExpressionTest<T extends AbstractNameValueExpression> {
|
public abstract class AbstractNameValueExpressionTest<T extends AbstractNameValueExpression> {
|
||||||
|
|
||||||
protected T createExpression(String expression) {
|
protected T createExpression(String expression) {
|
||||||
ResolvableType resolvableType = ResolvableType
|
ResolvableType resolvableType = ResolvableType.forType(getClass().getGenericSuperclass());
|
||||||
.forType(getClass().getGenericSuperclass());
|
|
||||||
Class<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
Class<T> firstGenericType = (Class<T>) resolvableType.resolveGeneric(0);
|
||||||
Constructor<T> constructor = null;
|
Constructor<T> constructor = null;
|
||||||
try {
|
try {
|
||||||
constructor = firstGenericType.getDeclaredConstructor(String.class);
|
constructor = firstGenericType.getDeclaredConstructor(String.class);
|
||||||
}
|
} catch (NoSuchMethodException e) {
|
||||||
catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return BeanUtils.instantiateClass(constructor, expression);
|
return BeanUtils.instantiateClass(constructor, expression);
|
||||||
@@ -70,13 +68,10 @@ public abstract class AbstractNameValueExpressionTest<T extends AbstractNameValu
|
|||||||
@Test
|
@Test
|
||||||
public void testEqualsAndHashCode() {
|
public void testEqualsAndHashCode() {
|
||||||
Assert.assertEquals(createExpression("a"), createExpression("a"));
|
Assert.assertEquals(createExpression("a"), createExpression("a"));
|
||||||
Assert.assertEquals(createExpression("a").hashCode(),
|
Assert.assertEquals(createExpression("a").hashCode(), createExpression("a").hashCode());
|
||||||
createExpression("a").hashCode());
|
|
||||||
Assert.assertEquals(createExpression("a=1"), createExpression("a = 1 "));
|
Assert.assertEquals(createExpression("a=1"), createExpression("a = 1 "));
|
||||||
Assert.assertEquals(createExpression("a=1").hashCode(),
|
Assert.assertEquals(createExpression("a=1").hashCode(), createExpression("a = 1 ").hashCode());
|
||||||
createExpression("a = 1 ").hashCode());
|
|
||||||
Assert.assertNotEquals(createExpression("a"), createExpression("b"));
|
Assert.assertNotEquals(createExpression("a"), createExpression("b"));
|
||||||
Assert.assertNotEquals(createExpression("a").hashCode(),
|
Assert.assertNotEquals(createExpression("a").hashCode(), createExpression("b").hashCode());
|
||||||
createExpression("b").hashCode());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ import org.springframework.http.MediaType;
|
|||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class ConsumeMediaTypeExpressionTest
|
public class ConsumeMediaTypeExpressionTest extends AbstractMediaTypeExpressionTest<ConsumeMediaTypeExpression> {
|
||||||
extends AbstractMediaTypeExpressionTest<ConsumeMediaTypeExpression> {
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatch() {
|
public void testMatch() {
|
||||||
|
|||||||
@@ -20,15 +20,14 @@ import org.junit.Assert;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.http.HttpRequest;
|
import org.springframework.http.HttpRequest;
|
||||||
|
|
||||||
import com.alibaba.cloud.dubbo.http.DefaultHttpRequest;
|
import static com.alibaba.cloud.dubbo.http.DefaultHttpRequest.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HeaderExpression} Test
|
* {@link HeaderExpression} Test
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class HeaderExpressionTest
|
public class HeaderExpressionTest extends AbstractNameValueExpressionTest<HeaderExpression> {
|
||||||
extends AbstractNameValueExpressionTest<HeaderExpression> {
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsCaseSensitiveName() {
|
public void testIsCaseSensitiveName() {
|
||||||
@@ -41,20 +40,20 @@ public class HeaderExpressionTest
|
|||||||
public void testMatch() {
|
public void testMatch() {
|
||||||
|
|
||||||
HeaderExpression expression = createExpression("a=1");
|
HeaderExpression expression = createExpression("a=1");
|
||||||
HttpRequest request = DefaultHttpRequest.builder().build();
|
HttpRequest request = builder().build();
|
||||||
|
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().header("a", "").build();
|
request = builder().header("a", "").build();
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().header("a", "2").build();
|
request = builder().header("a", "2").build();
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().header("", "1").build();
|
request = builder().header("", "1").build();
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().header("a", "1").build();
|
request = builder().header("a", "1").build();
|
||||||
Assert.assertTrue(expression.match(request));
|
Assert.assertTrue(expression.match(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,32 +16,29 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.http.matcher;
|
package com.alibaba.cloud.dubbo.http.matcher;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HttpRequestMethodsMatcher} Test
|
* {@link HttpRequestMethodsMatcher} Test
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class HttpRequestMethodsMatcherTest
|
public class HttpRequestMethodsMatcherTest extends AbstractHttpRequestMatcherTest<HttpRequestMethodsMatcher> {
|
||||||
extends AbstractHttpRequestMatcherTest<HttpRequestMethodsMatcher> {
|
|
||||||
|
|
||||||
HttpRequestMethodsMatcher matcher = new HttpRequestMethodsMatcher("GET");
|
HttpRequestMethodsMatcher matcher = new HttpRequestMethodsMatcher("GET");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testEqualsAndHashCode() {
|
public void testEqualsAndHashCode() {
|
||||||
Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)),
|
Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)), matcher.getMethods());
|
||||||
matcher.getMethods());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void testGetContent() {
|
public void testGetContent() {
|
||||||
Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)),
|
Assert.assertEquals(new HashSet<>(Arrays.asList(HttpMethod.GET)), matcher.getContent());
|
||||||
matcher.getContent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.http.matcher;
|
package com.alibaba.cloud.dubbo.http.matcher;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.mock.http.client.MockClientHttpRequest;
|
import org.springframework.mock.http.client.MockClientHttpRequest;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HttpRequestParamsMatcher} Test
|
* {@link HttpRequestParamsMatcher} Test
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,15 +20,14 @@ import org.junit.Assert;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.http.HttpRequest;
|
import org.springframework.http.HttpRequest;
|
||||||
|
|
||||||
import com.alibaba.cloud.dubbo.http.DefaultHttpRequest;
|
import static com.alibaba.cloud.dubbo.http.DefaultHttpRequest.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ParamExpression} Test
|
* {@link ParamExpression} Test
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class ParamExpressionTest
|
public class ParamExpressionTest extends AbstractNameValueExpressionTest<ParamExpression> {
|
||||||
extends AbstractNameValueExpressionTest<ParamExpression> {
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsCaseSensitiveName() {
|
public void testIsCaseSensitiveName() {
|
||||||
@@ -41,20 +40,20 @@ public class ParamExpressionTest
|
|||||||
public void testMatch() {
|
public void testMatch() {
|
||||||
|
|
||||||
ParamExpression expression = createExpression("a=1");
|
ParamExpression expression = createExpression("a=1");
|
||||||
HttpRequest request = DefaultHttpRequest.builder().build();
|
HttpRequest request = builder().build();
|
||||||
|
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().param("a", "").build();
|
request = builder().param("a", "").build();
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().param("a", "2").build();
|
request = builder().param("a", "2").build();
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().param("", "1").build();
|
request = builder().param("", "1").build();
|
||||||
Assert.assertFalse(expression.match(request));
|
Assert.assertFalse(expression.match(request));
|
||||||
|
|
||||||
request = DefaultHttpRequest.builder().param("a", "1").build();
|
request = builder().param("a", "1").build();
|
||||||
Assert.assertTrue(expression.match(request));
|
Assert.assertTrue(expression.match(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,26 +16,23 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.http.matcher;
|
package com.alibaba.cloud.dubbo.http.matcher;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ProduceMediaTypeExpression} Test
|
* {@link ProduceMediaTypeExpression} Test
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public class ProduceMediaTypeExpressionTest
|
public class ProduceMediaTypeExpressionTest extends AbstractMediaTypeExpressionTest<ProduceMediaTypeExpression> {
|
||||||
extends AbstractMediaTypeExpressionTest<ProduceMediaTypeExpression> {
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatch() {
|
public void testMatch() {
|
||||||
ProduceMediaTypeExpression expression = createExpression(
|
ProduceMediaTypeExpression expression = createExpression(MediaType.APPLICATION_JSON_VALUE);
|
||||||
MediaType.APPLICATION_JSON_VALUE);
|
Assert.assertTrue(expression.match(Arrays.asList(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)));
|
||||||
Assert.assertTrue(expression.match(
|
|
||||||
Arrays.asList(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)));
|
|
||||||
|
|
||||||
expression = createExpression(MediaType.APPLICATION_JSON_VALUE);
|
expression = createExpression(MediaType.APPLICATION_JSON_VALUE);
|
||||||
Assert.assertFalse(expression.match(Arrays.asList(MediaType.APPLICATION_XML)));
|
Assert.assertFalse(expression.match(Arrays.asList(MediaType.APPLICATION_XML)));
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.metadata;
|
package com.alibaba.cloud.dubbo.metadata;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link RequestMetadata} Test
|
* {@link RequestMetadata} Test
|
||||||
*
|
*
|
||||||
@@ -75,8 +75,7 @@ public class RequestMetadataTest {
|
|||||||
// @Test
|
// @Test
|
||||||
// public void testBestMatch() {
|
// public void testBestMatch() {
|
||||||
//
|
//
|
||||||
// NavigableMap<RequestMetadata, RequestMetadata> requestMetadataMap = new
|
// NavigableMap<RequestMetadata, RequestMetadata> requestMetadataMap = new TreeMap<>();
|
||||||
// TreeMap<>();
|
|
||||||
//
|
//
|
||||||
// RequestMetadata metadata = new RequestMetadata();
|
// RequestMetadata metadata = new RequestMetadata();
|
||||||
// metadata.setMethod(method);
|
// metadata.setMethod(method);
|
||||||
|
|||||||
@@ -16,16 +16,15 @@
|
|||||||
*/
|
*/
|
||||||
package com.alibaba.cloud.dubbo.metadata.resolver;
|
package com.alibaba.cloud.dubbo.metadata.resolver;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
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.cloud.openfeign.support.SpringMvcContract;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
|
|
||||||
import com.alibaba.cloud.dubbo.annotation.DubboTransported;
|
import java.util.Set;
|
||||||
import com.alibaba.cloud.dubbo.metadata.DubboTransportedMethodMetadata;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DubboTransportedMethodMetadataResolver} Test
|
* {@link DubboTransportedMethodMetadataResolver} Test
|
||||||
@@ -41,17 +40,16 @@ public class DubboTransportedMethodMetadataResolverTest {
|
|||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
environment = new MockEnvironment();
|
environment = new MockEnvironment();
|
||||||
resolver = new DubboTransportedMethodMetadataResolver(environment,
|
resolver = new DubboTransportedMethodMetadataResolver(environment, new SpringMvcContract());
|
||||||
new SpringMvcContract());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolve() {
|
public void testResolve() {
|
||||||
Set<DubboTransportedMethodMetadata> metadataSet = resolver
|
Set<DubboTransportedMethodMetadata> metadataSet = resolver.resolveDubboTransportedMethodMetadataSet(TestDefaultService.class);
|
||||||
.resolveDubboTransportedMethodMetadataSet(TestDefaultService.class);
|
|
||||||
Assert.assertEquals(1, metadataSet.size());
|
Assert.assertEquals(1, metadataSet.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@DubboTransported
|
@DubboTransported
|
||||||
interface TestDefaultService {
|
interface TestDefaultService {
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,11 @@ public class NacosDiscoveryClient implements DiscoveryClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ServiceInstance hostToServiceInstance(Instance instance,
|
public static ServiceInstance hostToServiceInstance(Instance instance,
|
||||||
String serviceId) {
|
String serviceId) {
|
||||||
|
if (instance == null || !instance.isEnabled() || !instance.isHealthy()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
|
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
|
||||||
nacosServiceInstance.setHost(instance.getIp());
|
nacosServiceInstance.setHost(instance.getIp());
|
||||||
nacosServiceInstance.setPort(instance.getPort());
|
nacosServiceInstance.setPort(instance.getPort());
|
||||||
@@ -87,11 +90,14 @@ public class NacosDiscoveryClient implements DiscoveryClient {
|
|||||||
return nacosServiceInstance;
|
return nacosServiceInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ServiceInstance> hostToServiceInstanceList(
|
public static List<ServiceInstance> hostToServiceInstanceList(
|
||||||
List<Instance> instances, String serviceId) {
|
List<Instance> instances, String serviceId) {
|
||||||
List<ServiceInstance> result = new ArrayList<>(instances.size());
|
List<ServiceInstance> result = new ArrayList<>(instances.size());
|
||||||
for (Instance instance : instances) {
|
for (Instance instance : instances) {
|
||||||
result.add(hostToServiceInstance(instance, serviceId));
|
ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId);
|
||||||
|
if (serviceInstance != null) {
|
||||||
|
result.add(serviceInstance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user