Polish spring-cloud-incubator/spring-cloud-alibaba#524 : Add @ConfigurationProperties for Dubbo Spring Cloud

pull/525/head
mercyblitz 6 years ago
parent 026046fb15
commit fd410ccf38

@ -20,7 +20,9 @@ import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.config.spring.util.PropertySourcesUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.cloud.alibaba.dubbo.env.DubboCloudProperties;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
import org.springframework.cloud.alibaba.dubbo.service.parameter.PathVariableServiceParameterResolver;
@ -49,6 +51,7 @@ import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_SCAN_PREFIX;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Configuration
@EnableConfigurationProperties(DubboCloudProperties.class)
public class DubboServiceAutoConfiguration {
@Bean

@ -56,7 +56,7 @@ import java.util.stream.Collectors;
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME;
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.DUBBO_URLS_METADATA_PROPERTY_NAME;
import static org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository.DUBBO_URLS_METADATA_PROPERTY_NAME;
import static org.springframework.util.ObjectUtils.isEmpty;
/**

@ -0,0 +1,81 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.env;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
import static org.springframework.util.StringUtils.hasText;
import static org.springframework.util.StringUtils.trimAllWhitespace;
/**
* Dubbo Cloud {@link ConfigurationProperties Properties}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConfigurationProperties(prefix = "dubbo.cloud")
public class DubboCloudProperties {
/**
* All services of Dubbo
*/
public static final String ALL_DUBBO_SERVICES = "*";
/**
* The subscribed services, the default value is "*". The multiple value will use comma(",") as the separator.
*
* @see #ALL_DUBBO_SERVICES
*/
private String subscribedServices = ALL_DUBBO_SERVICES;
public String getSubscribedServices() {
return subscribedServices;
}
public void setSubscribedServices(String subscribedServices) {
this.subscribedServices = subscribedServices;
}
/**
* Get the subscribed services as a {@link Set} with configuration order.
*
* @return non-null Read-only {@link Set}
*/
public Set<String> subscribedServices() {
String[] services = commaDelimitedListToStringArray(getSubscribedServices());
if (services.length < 1) {
return Collections.emptySet();
}
Set<String> subscribedServices = new LinkedHashSet<>();
for (String service : services) {
if (hasText(service)) { // filter blank service name
// remove all whitespace
subscribedServices.add(trimAllWhitespace(service));
}
}
return Collections.unmodifiableSet(subscribedServices);
}
}

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.registry.env;
package org.springframework.cloud.alibaba.dubbo.env;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ -23,22 +23,35 @@ import com.fasterxml.jackson.databind.type.TypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.alibaba.dubbo.env.DubboCloudProperties;
import org.springframework.cloud.alibaba.dubbo.http.matcher.RequestMetadataMatcher;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigService;
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy;
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
import static org.springframework.cloud.alibaba.dubbo.env.DubboCloudProperties.ALL_DUBBO_SERVICES;
import static org.springframework.cloud.alibaba.dubbo.http.DefaultHttpRequest.builder;
import static org.springframework.util.CollectionUtils.isEmpty;
@ -50,21 +63,80 @@ import static org.springframework.util.CollectionUtils.isEmpty;
@Repository
public class DubboServiceMetadataRepository {
/**
* The property name of Dubbo {@link URL URLs} metadata
*/
public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo.urls";
private final Logger logger = LoggerFactory.getLogger(getClass());
private final ObjectMapper objectMapper = new ObjectMapper();
private final Set<URL> registeredURLs = new LinkedHashSet<>();
private final Map<String, String> dubboServiceKeysRepository = new HashMap<>();
/**
* Key is application name
* Value is Map<RequestMetadata, DubboRestServiceMetadata>
*/
private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> repository = newHashMap();
private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> dubboRestServiceMetadataRepository = newHashMap();
private Set<String> subscribedServices;
@Autowired
private DubboCloudProperties dubboCloudProperties;
@Autowired
private DubboMetadataConfigServiceProxy dubboMetadataConfigServiceProxy;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private JSONUtils jsonUtils;
@Value("${spring.application.name}")
private String currentApplicationName;
@PostConstruct
public void init() {
initSubscribedServices();
initDubboServiceKeysRepository();
retainAvailableSubscribedServices();
initDubboRestServiceMetadataRepository();
}
/**
* The specified service is subscribe or not
*
* @param serviceName the service name
* @return
*/
public boolean isSubscribedService(String serviceName) {
return subscribedServices.contains(serviceName);
}
/**
* Get the service name by the {@link URL#getServiceKey() service key}
*
* @param url {@link URL}
* @return the service name if found
*/
public String getServiceName(URL url) {
return getServiceName(url.getServiceKey());
}
/**
* Get the service name by the {@link URL#getServiceKey() service key}
*
* @param serviceKey the {@link URL#getServiceKey() service key}
* @return the service name if found
*/
public String getServiceName(String serviceKey) {
return dubboServiceKeysRepository.get(serviceKey);
}
public void registerURL(URL url) {
this.registeredURLs.add(url);
}
@ -77,6 +149,19 @@ public class DubboServiceMetadataRepository {
return Collections.unmodifiableSet(registeredURLs);
}
/**
* Build the {@link URL urls} by the specified {@link ServiceInstance}
*
* @param serviceInstance {@link ServiceInstance}
* @return the mutable {@link URL urls}
*/
public List<URL> buildURLs(ServiceInstance serviceInstance) {
Map<String, String> metadata = serviceInstance.getMetadata();
String dubboURLsJSON = metadata.get(DUBBO_URLS_METADATA_PROPERTY_NAME);
List<String> urlValues = jsonUtils.toList(dubboURLsJSON);
return urlValues.stream().map(URL::valueOf).collect(Collectors.toList());
}
/**
* Initialize the specified service's {@link ServiceRestMetadata}
*
@ -84,7 +169,7 @@ public class DubboServiceMetadataRepository {
*/
public void initialize(String serviceName) {
if (repository.containsKey(serviceName)) {
if (dubboRestServiceMetadataRepository.containsKey(serviceName)) {
return;
}
@ -123,7 +208,7 @@ public class DubboServiceMetadataRepository {
* @return {@link DubboRestServiceMetadata} if matched, or <code>null</code>
*/
public DubboRestServiceMetadata get(String serviceName, RequestMetadata requestMetadata) {
return match(repository, serviceName, requestMetadata);
return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata);
}
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository, String serviceName,
@ -166,22 +251,21 @@ public class DubboServiceMetadataRepository {
}
private Map<RequestMetadataMatcher, DubboRestServiceMetadata> getMetadataMap(String serviceName) {
return getMap(repository, serviceName);
return getMap(dubboRestServiceMetadataRepository, serviceName);
}
private Set<ServiceRestMetadata> getServiceRestMetadataSet(String serviceName) {
DubboMetadataConfigService dubboMetadataConfigService = dubboMetadataConfigServiceProxy.newProxy(serviceName);
String serviceRestMetadataJsonConfig = dubboMetadataConfigService.getServiceRestMetadata();
Set<ServiceRestMetadata> metadata;
Set<ServiceRestMetadata> metadata = Collections.emptySet();
try {
String serviceRestMetadataJsonConfig = dubboMetadataConfigService.getServiceRestMetadata();
metadata = objectMapper.readValue(serviceRestMetadataJsonConfig,
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
metadata = Collections.emptySet();
}
return metadata;
}
@ -203,4 +287,45 @@ public class DubboServiceMetadataRepository {
return new LinkedHashMap<>();
}
private void initSubscribedServices() {
// If subscribes all services
if (ALL_DUBBO_SERVICES.equalsIgnoreCase(dubboCloudProperties.getSubscribedServices())) {
subscribedServices = new HashSet<>(discoveryClient.getServices());
} else {
subscribedServices = new HashSet<>(dubboCloudProperties.subscribedServices());
}
excludeSelf(subscribedServices);
}
private void excludeSelf(Set<String> subscribedServices) {
subscribedServices.remove(currentApplicationName);
}
private void initDubboServiceKeysRepository() {
subscribedServices.stream()
.map(discoveryClient::getInstances)
.filter(this::isNotEmpty)
.forEach(serviceInstances -> {
ServiceInstance serviceInstance = serviceInstances.get(0);
buildURLs(serviceInstance).forEach(url -> {
String serviceKey = url.getServiceKey();
String serviceName = url.getParameter(APPLICATION_KEY);
dubboServiceKeysRepository.put(serviceKey, serviceName);
});
});
}
private void retainAvailableSubscribedServices() {
// dubboServiceKeysRepository.values() returns the available services(possible duplicated ones)
subscribedServices = new HashSet<>(dubboServiceKeysRepository.values());
}
private void initDubboRestServiceMetadataRepository() {
subscribedServices.forEach(this::initialize);
}
private boolean isNotEmpty(Collection collection) {
return !CollectionUtils.isEmpty(collection);
}
}

@ -21,25 +21,13 @@ import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.RegistryFactory;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;
import static java.util.Collections.emptyMap;
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
import static org.springframework.util.CollectionUtils.isEmpty;
/**
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
*
@ -47,79 +35,13 @@ import static org.springframework.util.CollectionUtils.isEmpty;
*/
public class SpringCloudRegistry extends AbstractSpringCloudRegistry {
/**
* The property name of Dubbo {@link URL URLs} metadata
*/
public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo.urls";
/**
* The parameter name of the services of Dubbo Provider
*/
public static final String DUBBO_PROVIDER_SERVICES_PARAM_NAME = "dubbo-provider-services";
/**
* All services of Dubbo Provider
*/
public static final String ALL_DUBBO_PROVIDER_SERVICES = "*";
private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
private final JSONUtils jsonUtils;
private final Set<String> dubboProviderServices;
private final Map<String, String> dubboServiceKeysCache;
public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
ScheduledExecutorService servicesLookupScheduler,
DubboServiceMetadataRepository dubboServiceMetadataRepository,
ConfigurableApplicationContext applicationContext) {
DubboServiceMetadataRepository dubboServiceMetadataRepository) {
super(url, discoveryClient, servicesLookupScheduler);
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
this.jsonUtils = applicationContext.getBean(JSONUtils.class);
this.dubboProviderServices = getDubboProviderServices();
this.dubboServiceKeysCache = this.initDubboServiceKeysCache();
}
private Map<String, String> initDubboServiceKeysCache() {
if (isEmpty(dubboProviderServices)) {
return emptyMap();
}
Map<String, String> newCache = new HashMap<>();
dubboProviderServices.stream()
.map(this::getServiceInstances)
.filter(this::isNotEmpty)
.forEach(serviceInstances -> {
ServiceInstance serviceInstance = serviceInstances.get(0);
getURLs(serviceInstance).forEach(url -> {
String serviceKey = url.getServiceKey();
String serviceName = url.getParameter(APPLICATION_KEY);
newCache.put(serviceKey, serviceName);
});
});
return newCache;
}
private boolean isNotEmpty(Collection collection) {
return !CollectionUtils.isEmpty(collection);
}
private List<URL> getURLs(ServiceInstance serviceInstance) {
Map<String, String> metadata = serviceInstance.getMetadata();
String dubboURLsJSON = metadata.get(DUBBO_URLS_METADATA_PROPERTY_NAME);
List<String> urlValues = jsonUtils.toList(dubboURLsJSON);
return urlValues.stream().map(URL::valueOf).collect(Collectors.toList());
}
private Set<String> getDubboProviderServices() {
URL registryURL = getUrl();
String services = registryURL.getParameter(DUBBO_PROVIDER_SERVICES_PARAM_NAME, ALL_DUBBO_PROVIDER_SERVICES);
return ALL_DUBBO_PROVIDER_SERVICES.equalsIgnoreCase(services) ?
getAllServiceNames() : StringUtils.commaDelimitedListToSet(services);
}
@Override
@ -134,18 +56,18 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry {
@Override
protected boolean supports(String serviceName) {
return dubboProviderServices.contains(serviceName);
return dubboServiceMetadataRepository.isSubscribedService(serviceName);
}
@Override
protected String getServiceName(URL url) {
String serviceKey = url.getServiceKey();
return dubboServiceKeysCache.get(serviceKey);
return dubboServiceMetadataRepository.getServiceName(url);
}
@Override
protected void notifySubscriber(URL url, NotifyListener listener, List<ServiceInstance> serviceInstances) {
List<URL> urls = serviceInstances.stream().map(this::getURLs)
List<URL> urls = serviceInstances.stream()
.map(dubboServiceMetadataRepository::buildURLs)
.flatMap(List::stream)
.collect(Collectors.toList());
notify(url, listener, urls);

@ -68,8 +68,7 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
@Override
public Registry getRegistry(URL url) {
init();
return new SpringCloudRegistry(url, discoveryClient, servicesLookupScheduler,
dubboServiceMetadataRepository, applicationContext);
return new SpringCloudRegistry(url, discoveryClient, servicesLookupScheduler, dubboServiceMetadataRepository);
}
public static void setApplicationContext(ConfigurableApplicationContext applicationContext) {

@ -1,15 +1,15 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.alibaba.dubbo.registry.env.DubboNonWebApplicationEnvironmentPostProcessor
org.springframework.cloud.alibaba.dubbo.env.DubboNonWebApplicationEnvironmentPostProcessor

@ -3,9 +3,13 @@ dubbo:
# The Spring Cloud Dubbo's registry extension
## the default value of dubbo-provider-services is "*", that means to subscribe all providers,
## thus it's optimized if subscriber specifies the required providers.
address: spring-cloud://localhost?dubbo-provider-services=${provider.application.name}
# The traditional Dubbo's registry
address: spring-cloud://localhost
# The traditional Dubbo's registry also is supported
# address: zookeeper://127.0.0.1:2181
cloud:
# The subscribed services in consumer side
subscribed-services: ${provider.application.name}
server:
port: 0

Loading…
Cancel
Save