mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Merge pull request #562 from mercyblitz/master
[Refactor] add Introspective DubboMetadataService for Dubbo Spring Cloud
This commit is contained in:
commit
d535c6f74f
@ -32,7 +32,7 @@ import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolve
|
|||||||
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
|
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
|
||||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceExporter;
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceExporter;
|
||||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||||
import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataService;
|
import org.springframework.cloud.alibaba.dubbo.service.IntrospectiveDubboMetadataService;
|
||||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -50,13 +50,13 @@ import java.util.function.Supplier;
|
|||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@Import({DubboServiceMetadataRepository.class,
|
@Import({DubboServiceMetadataRepository.class,
|
||||||
PublishingDubboMetadataService.class,
|
IntrospectiveDubboMetadataService.class,
|
||||||
DubboMetadataServiceExporter.class,
|
DubboMetadataServiceExporter.class,
|
||||||
JSONUtils.class})
|
JSONUtils.class})
|
||||||
public class DubboMetadataAutoConfiguration {
|
public class DubboMetadataAutoConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PublishingDubboMetadataService dubboMetadataService;
|
private ObjectProvider<DubboServiceMetadataRepository> dubboServiceMetadataRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MetadataResolver metadataResolver;
|
private MetadataResolver metadataResolver;
|
||||||
@ -87,7 +87,6 @@ public class DubboMetadataAutoConfiguration {
|
|||||||
public void onServiceBeanExported(ServiceBeanExportedEvent event) {
|
public void onServiceBeanExported(ServiceBeanExportedEvent event) {
|
||||||
ServiceBean serviceBean = event.getServiceBean();
|
ServiceBean serviceBean = event.getServiceBean();
|
||||||
publishServiceRestMetadata(serviceBean);
|
publishServiceRestMetadata(serviceBean);
|
||||||
exportDubboMetadataConfigService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventListener(ApplicationFailedEvent.class)
|
@EventListener(ApplicationFailedEvent.class)
|
||||||
@ -97,15 +96,11 @@ public class DubboMetadataAutoConfiguration {
|
|||||||
|
|
||||||
@EventListener(ContextClosedEvent.class)
|
@EventListener(ContextClosedEvent.class)
|
||||||
public void onContextClosed() {
|
public void onContextClosed() {
|
||||||
dubboMetadataConfigServiceExporter.unexport();
|
unExportDubboMetadataConfigService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void publishServiceRestMetadata(ServiceBean serviceBean) {
|
private void publishServiceRestMetadata(ServiceBean serviceBean) {
|
||||||
dubboMetadataService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
|
dubboServiceMetadataRepository.getIfAvailable().publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
|
||||||
}
|
|
||||||
|
|
||||||
private void exportDubboMetadataConfigService() {
|
|
||||||
dubboMetadataConfigServiceExporter.export();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unExportDubboMetadataConfigService() {
|
private void unExportDubboMetadataConfigService() {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
|
||||||
import org.apache.dubbo.config.spring.ServiceBean;
|
import org.apache.dubbo.config.spring.ServiceBean;
|
||||||
|
|
||||||
import com.ecwid.consul.v1.agent.model.NewService;
|
import com.ecwid.consul.v1.agent.model.NewService;
|
||||||
@ -35,7 +34,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|||||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
|
import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
|
||||||
import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
|
||||||
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
|
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
|
||||||
@ -46,17 +44,13 @@ import org.springframework.context.SmartLifecycle;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
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.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.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
import static org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository.DUBBO_URLS_METADATA_PROPERTY_NAME;
|
|
||||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
import static org.springframework.util.ObjectUtils.isEmpty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,13 +87,10 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private JSONUtils jsonUtils;
|
|
||||||
|
|
||||||
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
||||||
public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
|
public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
|
||||||
Registration registration = event.getSource();
|
Registration registration = event.getSource();
|
||||||
attachURLsIntoMetadata(registration);
|
attachDubboMetadataServiceMetadata(registration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -115,7 +106,7 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
Registration registration = event.getSource();
|
Registration registration = event.getSource();
|
||||||
EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration);
|
EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration);
|
||||||
InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo();
|
InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo();
|
||||||
attachURLsIntoMetadata(instanceInfo.getMetadata());
|
attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,39 +146,30 @@ public class DubboServiceRegistrationAutoConfiguration {
|
|||||||
|
|
||||||
private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
|
private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
|
||||||
NewService newService = consulRegistration.getService();
|
NewService newService = consulRegistration.getService();
|
||||||
String dubboURLsJson = getDubboURLsJSON();
|
Map<String, String> serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
|
||||||
if (StringUtils.hasText(dubboURLsJson)) {
|
if (!isEmpty(serviceMetadata)) {
|
||||||
List<String> tags = newService.getTags();
|
List<String> tags = newService.getTags();
|
||||||
tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson);
|
for (Map.Entry<String, String> entry : serviceMetadata.entrySet()) {
|
||||||
|
tags.add(entry.getKey() + "=" + entry.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attachURLsIntoMetadata(Registration registration) {
|
private void attachDubboMetadataServiceMetadata(Registration registration) {
|
||||||
if (registration == null) {
|
if (registration == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized (registration) {
|
synchronized (registration) {
|
||||||
Map<String, String> metadata = registration.getMetadata();
|
Map<String, String> metadata = registration.getMetadata();
|
||||||
attachURLsIntoMetadata(metadata);
|
attachDubboMetadataServiceMetadata(metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attachURLsIntoMetadata(Map<String, String> metadata) {
|
private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
|
||||||
String dubboURLsJson = getDubboURLsJSON();
|
Map<String, String> serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
|
||||||
if (StringUtils.hasText(dubboURLsJson)) {
|
if (!isEmpty(serviceMetadata)) {
|
||||||
metadata.put(DUBBO_URLS_METADATA_PROPERTY_NAME, dubboURLsJson);
|
metadata.putAll(serviceMetadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDubboURLsJSON() {
|
|
||||||
Collection<URL> urls = dubboServiceMetadataRepository.getRegisteredUrls();
|
|
||||||
if (CollectionUtils.isEmpty(urls)) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("There is no registered URL to attach into metadata.");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return jsonUtils.toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -41,7 +41,7 @@ import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegist
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME;
|
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME;
|
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME;
|
||||||
@ -97,20 +97,21 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
|
|||||||
*/
|
*/
|
||||||
private void setServerPort() {
|
private void setServerPort() {
|
||||||
if (serverPort == null) {
|
if (serverPort == null) {
|
||||||
Collection<URL> urls = repository.getRegisteredUrls();
|
for (List<URL> urls : repository.getAllExportedUrls().values()) {
|
||||||
urls.stream()
|
urls.stream()
|
||||||
.filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol()))
|
.filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.ifPresent(url -> {
|
.ifPresent(url -> {
|
||||||
|
serverPort = url.getPort();
|
||||||
|
});
|
||||||
|
|
||||||
|
// If REST protocol is not present, use any applied port.
|
||||||
|
if (serverPort == null) {
|
||||||
|
urls.stream()
|
||||||
|
.findAny().ifPresent(url -> {
|
||||||
serverPort = url.getPort();
|
serverPort = url.getPort();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// If REST protocol is not present, use any applied port.
|
|
||||||
if (serverPort == null) {
|
|
||||||
urls.stream()
|
|
||||||
.findAny().ifPresent(url -> {
|
|
||||||
serverPort = url.getPort();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import java.util.Iterator;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL;
|
import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL;
|
||||||
|
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo's {@link ProtocolConfig} {@link Supplier}
|
* Dubbo's {@link ProtocolConfig} {@link Supplier}
|
||||||
@ -43,23 +44,26 @@ public class DubboProtocolConfigSupplier implements Supplier<ProtocolConfig> {
|
|||||||
public ProtocolConfig get() {
|
public ProtocolConfig get() {
|
||||||
ProtocolConfig protocolConfig = null;
|
ProtocolConfig protocolConfig = null;
|
||||||
Collection<ProtocolConfig> protocols = this.protocols.getIfAvailable();
|
Collection<ProtocolConfig> protocols = this.protocols.getIfAvailable();
|
||||||
for (ProtocolConfig protocol : protocols) {
|
|
||||||
String protocolName = protocol.getName();
|
|
||||||
if (DEFAULT_PROTOCOL.equals(protocolName)) {
|
|
||||||
protocolConfig = protocol;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them
|
if (!isEmpty(protocols)) {
|
||||||
Iterator<ProtocolConfig> iterator = protocols.iterator();
|
for (ProtocolConfig protocol : protocols) {
|
||||||
protocolConfig = iterator.hasNext() ? iterator.next() : null;
|
String protocolName = protocol.getName();
|
||||||
|
if (DEFAULT_PROTOCOL.equals(protocolName)) {
|
||||||
|
protocolConfig = protocol;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them
|
||||||
|
Iterator<ProtocolConfig> iterator = protocols.iterator();
|
||||||
|
protocolConfig = iterator.hasNext() ? iterator.next() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocolConfig == null) {
|
if (protocolConfig == null) {
|
||||||
protocolConfig = new ProtocolConfig();
|
protocolConfig = new ProtocolConfig();
|
||||||
protocolConfig.setName(DEFAULT_PROTOCOL);
|
protocolConfig.setName(DEFAULT_PROTOCOL);
|
||||||
protocolConfig.setPort(20880);
|
protocolConfig.setPort(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocolConfig;
|
return protocolConfig;
|
||||||
|
@ -30,6 +30,7 @@ import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata
|
|||||||
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
|
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
|
||||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataService;
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataService;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceExporter;
|
||||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||||
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
@ -37,12 +38,12 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
|
|||||||
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.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@ -51,10 +52,19 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static java.lang.String.valueOf;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.emptySet;
|
||||||
|
import static java.util.Collections.unmodifiableList;
|
||||||
|
import static java.util.Collections.unmodifiableMap;
|
||||||
|
import static java.util.Collections.unmodifiableSet;
|
||||||
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
|
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
|
||||||
|
import static org.apache.dubbo.common.Constants.VERSION_KEY;
|
||||||
import static org.springframework.cloud.alibaba.dubbo.env.DubboCloudProperties.ALL_DUBBO_SERVICES;
|
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.cloud.alibaba.dubbo.http.DefaultHttpRequest.builder;
|
||||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||||
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo Service Metadata {@link Repository}
|
* Dubbo Service Metadata {@link Repository}
|
||||||
@ -65,17 +75,56 @@ import static org.springframework.util.CollectionUtils.isEmpty;
|
|||||||
public class DubboServiceMetadataRepository {
|
public class DubboServiceMetadataRepository {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property name of Dubbo {@link URL URLs} metadata
|
* The prefix of {@link DubboMetadataService} : "dubbo.metadata-service."
|
||||||
*/
|
*/
|
||||||
public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo.urls";
|
public static final String DUBBO_METADATA_SERVICE_PREFIX = "dubbo.metadata-service.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link URL URLs} property name of {@link DubboMetadataService} : "dubbo.metadata-service.urls"
|
||||||
|
*/
|
||||||
|
public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = DUBBO_METADATA_SERVICE_PREFIX + "urls";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link String#format(String, Object...) pattern} of dubbo protocols port
|
||||||
|
*/
|
||||||
|
public static final String DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN = "dubbo.protocols.%s.port";
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
private final Set<URL> registeredURLs = new LinkedHashSet<>();
|
// =================================== Registration =================================== //
|
||||||
|
|
||||||
private final Map<String, String> dubboServiceKeysRepository = new HashMap<>();
|
/**
|
||||||
|
* 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 URLs}
|
||||||
|
*/
|
||||||
|
private final MultiValueMap<String, URL> allExportedURLs = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
|
// ==================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
|
// =================================== Subscription =================================== //
|
||||||
|
|
||||||
|
private Set<String> subscribedServices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subscribed {@link URL urls} {@link Map} of {@link DubboMetadataService},
|
||||||
|
* whose key is the return value of {@link URL#getServiceKey()} method and value is the {@link List} of
|
||||||
|
* {@link URL URLs}
|
||||||
|
*/
|
||||||
|
private final MultiValueMap<String, URL> subscribedDubboMetadataServiceURLs = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
|
// ==================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
|
// =================================== REST Metadata ================================== //
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service,
|
||||||
|
* the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods.
|
||||||
|
*/
|
||||||
|
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key is application name
|
* Key is application name
|
||||||
@ -83,7 +132,10 @@ public class DubboServiceMetadataRepository {
|
|||||||
*/
|
*/
|
||||||
private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> dubboRestServiceMetadataRepository = newHashMap();
|
private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> dubboRestServiceMetadataRepository = newHashMap();
|
||||||
|
|
||||||
private Set<String> subscribedServices;
|
// ==================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
|
// =================================== Dependencies =================================== //
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DubboCloudProperties dubboCloudProperties;
|
private DubboCloudProperties dubboCloudProperties;
|
||||||
@ -100,14 +152,118 @@ public class DubboServiceMetadataRepository {
|
|||||||
@Value("${spring.application.name}")
|
@Value("${spring.application.name}")
|
||||||
private String currentApplicationName;
|
private String currentApplicationName;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DubboMetadataServiceExporter dubboMetadataServiceExporter;
|
||||||
|
|
||||||
|
// ==================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
|
// Keep the order in following invocations
|
||||||
initSubscribedServices();
|
initSubscribedServices();
|
||||||
initDubboServiceKeysRepository();
|
initSubscribedDubboMetadataServices();
|
||||||
retainAvailableSubscribedServices();
|
|
||||||
initDubboRestServiceMetadataRepository();
|
initDubboRestServiceMetadataRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the metadata {@link Map} of {@link DubboMetadataService}
|
||||||
|
*
|
||||||
|
* @return non-null read-only {@link Map}
|
||||||
|
*/
|
||||||
|
public Map<String, String> getDubboMetadataServiceMetadata() {
|
||||||
|
|
||||||
|
List<URL> dubboMetadataServiceURLs = dubboMetadataServiceExporter.export();
|
||||||
|
|
||||||
|
// remove the exported URLs of DubboMetadataService
|
||||||
|
removeDubboMetadataServiceURLs(dubboMetadataServiceURLs);
|
||||||
|
|
||||||
|
Map<String, String> metadata = newHashMap();
|
||||||
|
|
||||||
|
addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs);
|
||||||
|
addDubboProtocolsPortMetadata(metadata);
|
||||||
|
|
||||||
|
return Collections.unmodifiableMap(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeDubboMetadataServiceURLs(List<URL> dubboMetadataServiceURLs) {
|
||||||
|
dubboMetadataServiceURLs.forEach(this::unexportURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDubboMetadataServiceURLsMetadata(Map<String, String> metadata, List<URL> dubboMetadataServiceURLs) {
|
||||||
|
String dubboMetadataServiceURLsJSON = jsonUtils.toJSON(dubboMetadataServiceURLs);
|
||||||
|
metadata.put(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME, dubboMetadataServiceURLsJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDubboProtocolsPortMetadata(Map<String, String> metadata) {
|
||||||
|
|
||||||
|
allExportedURLs.values()
|
||||||
|
.stream()
|
||||||
|
.flatMap(v -> v.stream())
|
||||||
|
.forEach(url -> {
|
||||||
|
String protocol = url.getProtocol();
|
||||||
|
String propertyName = getDubboProtocolPropertyName(protocol);
|
||||||
|
String propertyValue = valueOf(url.getPort());
|
||||||
|
metadata.put(propertyName, propertyValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the property name of Dubbo Protocol
|
||||||
|
*
|
||||||
|
* @param protocol Dubbo Protocol
|
||||||
|
* @return non-null
|
||||||
|
*/
|
||||||
|
public String getDubboProtocolPropertyName(String protocol) {
|
||||||
|
return format(DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish the {@link Set} of {@link ServiceRestMetadata}
|
||||||
|
*
|
||||||
|
* @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata}
|
||||||
|
*/
|
||||||
|
public void publishServiceRestMetadata(Set<ServiceRestMetadata> serviceRestMetadataSet) {
|
||||||
|
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
|
||||||
|
if (!isEmpty(serviceRestMetadata.getMeta())) {
|
||||||
|
this.serviceRestMetadata.add(serviceRestMetadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link Set} of {@link ServiceRestMetadata}
|
||||||
|
*
|
||||||
|
* @return non-null read-only {@link Set}
|
||||||
|
*/
|
||||||
|
public Set<ServiceRestMetadata> getServiceRestMetadata() {
|
||||||
|
return unmodifiableSet(serviceRestMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Get The subscribed {@link DubboMetadataService}'s {@link URL URLs}
|
||||||
|
// *
|
||||||
|
// * @return non-null read-only {@link List}
|
||||||
|
// */
|
||||||
|
// public List<URL> getSubscribedDubboMetadataServiceURLs() {
|
||||||
|
// return Collections.unmodifiableList(subscribedDubboMetadataServiceURLs);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public List<URL> findSubscribedDubboMetadataServiceURLs(String serviceName, String group, String version,
|
||||||
|
String protocol) {
|
||||||
|
String serviceKey = URL.buildKey(serviceName, group, version);
|
||||||
|
List<URL> urls = subscribedDubboMetadataServiceURLs.get(serviceKey);
|
||||||
|
|
||||||
|
if (isEmpty(urls)) {
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasText(protocol) ?
|
||||||
|
urls.stream().filter(url -> url.getProtocol().equalsIgnoreCase(protocol)).collect(Collectors.toList()) :
|
||||||
|
unmodifiableList(urls)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The specified service is subscribe or not
|
* The specified service is subscribe or not
|
||||||
*
|
*
|
||||||
@ -118,49 +274,57 @@ public class DubboServiceMetadataRepository {
|
|||||||
return subscribedServices.contains(serviceName);
|
return subscribedServices.contains(serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void exportURL(URL url) {
|
||||||
|
this.allExportedURLs.add(url.getServiceKey(), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unexportURL(URL url) {
|
||||||
|
String key = url.getServiceKey();
|
||||||
|
List<URL> urls = allExportedURLs.get(key);
|
||||||
|
urls.remove(url);
|
||||||
|
this.allExportedURLs.addAll(key, urls);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the service name by the {@link URL#getServiceKey() service key}
|
* Get all exported {@link URL urls}.
|
||||||
*
|
*
|
||||||
* @param url {@link URL}
|
* @return non-null read-only
|
||||||
* @return the service name if found
|
|
||||||
*/
|
*/
|
||||||
public String getServiceName(URL url) {
|
public Map<String, List<URL>> getAllExportedUrls() {
|
||||||
return getServiceName(url.getServiceKey());
|
return unmodifiableMap(allExportedURLs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the service name by the {@link URL#getServiceKey() service key}
|
* Get all exported {@link URL#getServiceKey() service keys}
|
||||||
*
|
*
|
||||||
* @param serviceKey the {@link URL#getServiceKey() service key}
|
* @return non-null read-only
|
||||||
* @return the service name if found
|
|
||||||
*/
|
*/
|
||||||
public String getServiceName(String serviceKey) {
|
public Set<String> getAllServiceKeys() {
|
||||||
return dubboServiceKeysRepository.get(serviceKey);
|
return allExportedURLs.keySet();
|
||||||
}
|
|
||||||
|
|
||||||
public void registerURL(URL url) {
|
|
||||||
this.registeredURLs.add(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterURL(URL url) {
|
|
||||||
this.registeredURLs.remove(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<URL> getRegisteredUrls() {
|
|
||||||
return Collections.unmodifiableSet(registeredURLs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the {@link URL urls} by the specified {@link ServiceInstance}
|
* Get the {@link URL urls} that {@link DubboMetadataService} exported by the specified {@link ServiceInstance}
|
||||||
*
|
*
|
||||||
* @param serviceInstance {@link ServiceInstance}
|
* @param serviceInstance {@link ServiceInstance}
|
||||||
* @return the mutable {@link URL urls}
|
* @return the mutable {@link URL urls}
|
||||||
*/
|
*/
|
||||||
public List<URL> buildURLs(ServiceInstance serviceInstance) {
|
public List<URL> getDubboMetadataServiceURLs(ServiceInstance serviceInstance) {
|
||||||
Map<String, String> metadata = serviceInstance.getMetadata();
|
Map<String, String> metadata = serviceInstance.getMetadata();
|
||||||
String dubboURLsJSON = metadata.get(DUBBO_URLS_METADATA_PROPERTY_NAME);
|
String dubboURLsJSON = metadata.get(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME);
|
||||||
List<String> urlValues = jsonUtils.toList(dubboURLsJSON);
|
return jsonUtils.toURLs(dubboURLsJSON);
|
||||||
return urlValues.stream().map(URL::valueOf).collect(Collectors.toList());
|
}
|
||||||
|
|
||||||
|
public Integer getDubboProtocolPort(ServiceInstance serviceInstance, String protocol) {
|
||||||
|
String protocolProperty = getDubboProtocolPropertyName(protocol);
|
||||||
|
Map<String, String> metadata = serviceInstance.getMetadata();
|
||||||
|
String protocolPort = metadata.get(protocolProperty);
|
||||||
|
return hasText(protocolPort) ? Integer.valueOf(protocolPort) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<URL> getExportedURLs(String serviceInterface, String group, String version) {
|
||||||
|
String serviceKey = URL.buildKey(serviceInterface, group, version);
|
||||||
|
return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,6 +376,10 @@ public class DubboServiceMetadataRepository {
|
|||||||
return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata);
|
return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getSubscribedServices() {
|
||||||
|
return Collections.unmodifiableSet(subscribedServices);
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository, String serviceName,
|
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository, String serviceName,
|
||||||
RequestMetadata requestMetadata) {
|
RequestMetadata requestMetadata) {
|
||||||
|
|
||||||
@ -256,18 +424,22 @@ public class DubboServiceMetadataRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Set<ServiceRestMetadata> getServiceRestMetadataSet(String serviceName) {
|
private Set<ServiceRestMetadata> getServiceRestMetadataSet(String serviceName) {
|
||||||
DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.newProxy(serviceName);
|
|
||||||
|
|
||||||
Set<ServiceRestMetadata> metadata = Collections.emptySet();
|
Set<ServiceRestMetadata> metadata = emptySet();
|
||||||
try {
|
|
||||||
String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata();
|
DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName);
|
||||||
if(StringUtils.hasText(serviceRestMetadataJsonConfig)) {
|
|
||||||
metadata = objectMapper.readValue(serviceRestMetadataJsonConfig,
|
if (dubboMetadataService != null) {
|
||||||
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
|
try {
|
||||||
}
|
String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata();
|
||||||
} catch (Exception e) {
|
if (hasText(serviceRestMetadataJsonConfig)) {
|
||||||
if (logger.isErrorEnabled()) {
|
metadata = objectMapper.readValue(serviceRestMetadataJsonConfig,
|
||||||
logger.error(e.getMessage(), e);
|
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (logger.isErrorEnabled()) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return metadata;
|
return metadata;
|
||||||
@ -292,8 +464,16 @@ public class DubboServiceMetadataRepository {
|
|||||||
|
|
||||||
private void initSubscribedServices() {
|
private void initSubscribedServices() {
|
||||||
// If subscribes all services
|
// If subscribes all services
|
||||||
if (ALL_DUBBO_SERVICES.equalsIgnoreCase(dubboCloudProperties.getSubscribedServices())) {
|
if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) {
|
||||||
subscribedServices = new HashSet<>(discoveryClient.getServices());
|
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 {
|
} else {
|
||||||
subscribedServices = new HashSet<>(dubboCloudProperties.subscribedServices());
|
subscribedServices = new HashSet<>(dubboCloudProperties.subscribedServices());
|
||||||
}
|
}
|
||||||
@ -305,23 +485,33 @@ public class DubboServiceMetadataRepository {
|
|||||||
subscribedServices.remove(currentApplicationName);
|
subscribedServices.remove(currentApplicationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initDubboServiceKeysRepository() {
|
private void initSubscribedDubboMetadataServices() {
|
||||||
|
// clear subscribedDubboMetadataServiceURLs
|
||||||
|
subscribedDubboMetadataServiceURLs.clear();
|
||||||
|
|
||||||
subscribedServices.stream()
|
subscribedServices.stream()
|
||||||
.map(discoveryClient::getInstances)
|
.map(discoveryClient::getInstances)
|
||||||
.filter(this::isNotEmpty)
|
.filter(this::isNotEmpty)
|
||||||
.forEach(serviceInstances -> {
|
.forEach(serviceInstances -> {
|
||||||
ServiceInstance serviceInstance = serviceInstances.get(0);
|
ServiceInstance serviceInstance = serviceInstances.get(0);
|
||||||
buildURLs(serviceInstance).forEach(url -> {
|
getDubboMetadataServiceURLs(serviceInstance).forEach(dubboMetadataServiceURL -> {
|
||||||
String serviceKey = url.getServiceKey();
|
initSubscribedDubboMetadataServiceURLs(dubboMetadataServiceURL);
|
||||||
String serviceName = url.getParameter(APPLICATION_KEY);
|
initDubboMetadataServiceProxy(dubboMetadataServiceURL);
|
||||||
dubboServiceKeysRepository.put(serviceKey, serviceName);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retainAvailableSubscribedServices() {
|
private void initSubscribedDubboMetadataServiceURLs(URL dubboMetadataServiceURL) {
|
||||||
// dubboServiceKeysRepository.values() returns the available services(possible duplicated ones)
|
// add subscriptions
|
||||||
subscribedServices = new HashSet<>(dubboServiceKeysRepository.values());
|
String serviceKey = dubboMetadataServiceURL.getServiceKey();
|
||||||
|
subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDubboMetadataServiceProxy(URL dubboMetadataServiceURL) {
|
||||||
|
String serviceName = dubboMetadataServiceURL.getParameter(APPLICATION_KEY);
|
||||||
|
String version = dubboMetadataServiceURL.getParameter(VERSION_KEY);
|
||||||
|
// Initialize DubboMetadataService with right version
|
||||||
|
dubboMetadataConfigServiceProxy.initProxy(serviceName, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initDubboRestServiceMetadataRepository() {
|
private void initDubboRestServiceMetadataRepository() {
|
||||||
|
@ -24,24 +24,30 @@ 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.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataService;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||||
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 java.util.Collection;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
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.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singleton;
|
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
|
||||||
|
import static org.apache.dubbo.common.Constants.GROUP_KEY;
|
||||||
|
import static org.apache.dubbo.common.Constants.PROTOCOL_KEY;
|
||||||
import static org.apache.dubbo.common.Constants.PROVIDER_SIDE;
|
import static org.apache.dubbo.common.Constants.PROVIDER_SIDE;
|
||||||
import static org.apache.dubbo.common.Constants.SIDE_KEY;
|
import static org.apache.dubbo.common.Constants.SIDE_KEY;
|
||||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
import static org.apache.dubbo.common.Constants.VERSION_KEY;
|
||||||
import static org.springframework.util.StringUtils.hasText;
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,6 +62,10 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
*/
|
*/
|
||||||
public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval";
|
public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval";
|
||||||
|
|
||||||
|
protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName();
|
||||||
|
|
||||||
|
private static final Set<String> schedulerTasks = new HashSet<>();
|
||||||
|
|
||||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,14 +75,27 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
private final DiscoveryClient discoveryClient;
|
private final DiscoveryClient discoveryClient;
|
||||||
|
|
||||||
|
private final DubboServiceMetadataRepository repository;
|
||||||
|
|
||||||
|
private final DubboMetadataServiceProxy dubboMetadataConfigServiceProxy;
|
||||||
|
|
||||||
|
private final JSONUtils jsonUtils;
|
||||||
|
|
||||||
|
|
||||||
protected final ScheduledExecutorService servicesLookupScheduler;
|
protected final ScheduledExecutorService servicesLookupScheduler;
|
||||||
|
|
||||||
public AbstractSpringCloudRegistry(URL url,
|
public AbstractSpringCloudRegistry(URL url,
|
||||||
DiscoveryClient discoveryClient,
|
DiscoveryClient discoveryClient,
|
||||||
|
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||||
|
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
||||||
|
JSONUtils jsonUtils,
|
||||||
ScheduledExecutorService servicesLookupScheduler) {
|
ScheduledExecutorService servicesLookupScheduler) {
|
||||||
super(url);
|
super(url);
|
||||||
this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L);
|
this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L);
|
||||||
this.discoveryClient = discoveryClient;
|
this.discoveryClient = discoveryClient;
|
||||||
|
this.repository = dubboServiceMetadataRepository;
|
||||||
|
this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy;
|
||||||
|
this.jsonUtils = jsonUtils;
|
||||||
this.servicesLookupScheduler = servicesLookupScheduler;
|
this.servicesLookupScheduler = servicesLookupScheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,13 +145,113 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void doSubscribe(URL url, NotifyListener listener) {
|
public final void doSubscribe(URL url, NotifyListener listener) {
|
||||||
Set<String> serviceNames = getServiceNames(url);
|
|
||||||
doSubscribe(url, listener, serviceNames);
|
if (isAdminURL(url)) {
|
||||||
|
// TODO in future
|
||||||
|
} else if (isDubboMetadataServiceURL(url)) { // for DubboMetadataService
|
||||||
|
subscribeDubboMetadataServiceURLs(url, listener);
|
||||||
|
} else { // for general Dubbo Services
|
||||||
|
subscribeDubboServiceURLs(url, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void subscribeDubboServiceURLs(URL url, NotifyListener listener) {
|
||||||
|
|
||||||
|
doSubscribeDubboServiceURLs(url, listener);
|
||||||
|
|
||||||
|
submitSchedulerTaskIfAbsent(url, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) {
|
||||||
|
String taskId = url.toIdentityString();
|
||||||
|
if (schedulerTasks.add(taskId)) {
|
||||||
|
schedule(() -> doSubscribeDubboServiceURLs(url, listener));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) {
|
||||||
|
|
||||||
|
Set<String> subscribedServices = repository.getSubscribedServices();
|
||||||
|
|
||||||
|
subscribedServices.stream()
|
||||||
|
.map(dubboMetadataConfigServiceProxy::getProxy)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.forEach(dubboMetadataService -> {
|
||||||
|
List<URL> exportedURLs = getExportedURLs(dubboMetadataService, url);
|
||||||
|
List<URL> allSubscribedURLs = new LinkedList<>();
|
||||||
|
for (URL exportedURL : exportedURLs) {
|
||||||
|
String serviceName = exportedURL.getParameter(APPLICATION_KEY);
|
||||||
|
List<ServiceInstance> serviceInstances = getServiceInstances(serviceName);
|
||||||
|
String protocol = exportedURL.getProtocol();
|
||||||
|
List<URL> subscribedURLs = new LinkedList<>();
|
||||||
|
serviceInstances.forEach(serviceInstance -> {
|
||||||
|
Integer port = repository.getDubboProtocolPort(serviceInstance, protocol);
|
||||||
|
String host = serviceInstance.getHost();
|
||||||
|
if (port == null) {
|
||||||
|
if (logger.isWarnEnabled()) {
|
||||||
|
logger.warn("The protocol[{}] port of Dubbo service instance[host : {}] " +
|
||||||
|
"can't be resolved", protocol, host);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
URL subscribedURL = new URL(protocol, host, port, exportedURL.getParameters());
|
||||||
|
subscribedURLs.add(subscribedURL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("The subscribed URL[{}] will notify all URLs : {}", url, subscribedURLs);
|
||||||
|
}
|
||||||
|
|
||||||
|
allSubscribedURLs.addAll(subscribedURLs);
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.notify(allSubscribedURLs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ServiceInstance> getServiceInstances(String serviceName) {
|
||||||
|
return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ServiceInstance> doGetServiceInstances(String serviceName) {
|
||||||
|
List<ServiceInstance> serviceInstances = emptyList();
|
||||||
|
try {
|
||||||
|
serviceInstances = discoveryClient.getInstances(serviceName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (logger.isErrorEnabled()) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serviceInstances;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<URL> getExportedURLs(DubboMetadataService dubboMetadataService, URL url) {
|
||||||
|
String serviceInterface = url.getServiceInterface();
|
||||||
|
String group = url.getParameter(GROUP_KEY);
|
||||||
|
String version = url.getParameter(VERSION_KEY);
|
||||||
|
// The subscribed protocol may be null
|
||||||
|
String subscribedProtocol = url.getParameter(PROTOCOL_KEY);
|
||||||
|
String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface, group, version);
|
||||||
|
return jsonUtils
|
||||||
|
.toURLs(exportedURLsJSON)
|
||||||
|
.stream()
|
||||||
|
.filter(exportedURL ->
|
||||||
|
subscribedProtocol == null || subscribedProtocol.equalsIgnoreCase(exportedURL.getProtocol())
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void subscribeDubboMetadataServiceURLs(URL url, NotifyListener listener) {
|
||||||
|
String serviceInterface = url.getServiceInterface();
|
||||||
|
String group = url.getParameter(GROUP_KEY);
|
||||||
|
String version = url.getParameter(VERSION_KEY);
|
||||||
|
String protocol = url.getParameter(PROTOCOL_KEY);
|
||||||
|
List<URL> urls = repository.findSubscribedDubboMetadataServiceURLs(serviceInterface, group, version, protocol);
|
||||||
|
listener.notify(urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void doUnsubscribe(URL url, NotifyListener listener) {
|
public final void doUnsubscribe(URL url, NotifyListener listener) {
|
||||||
if (isAdminProtocol(url)) {
|
if (isAdminURL(url)) {
|
||||||
shutdownServiceNamesLookup();
|
shutdownServiceNamesLookup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,86 +267,16 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> filterServiceNames(Collection<String> serviceNames) {
|
protected boolean isAdminURL(URL url) {
|
||||||
return new LinkedHashSet<>(filter(serviceNames, this::supports));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract boolean supports(String serviceName);
|
|
||||||
|
|
||||||
protected final Set<String> getAllServiceNames() {
|
|
||||||
return new LinkedHashSet<>(discoveryClient.getServices());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the service names from the specified {@link URL url}
|
|
||||||
*
|
|
||||||
* @param url {@link URL}
|
|
||||||
* @return non-null
|
|
||||||
*/
|
|
||||||
private Set<String> getServiceNames(URL url) {
|
|
||||||
if (isAdminProtocol(url)) {
|
|
||||||
return getServiceNamesForOps(url);
|
|
||||||
} else {
|
|
||||||
return singleton(getServiceName(url));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAdminProtocol(URL url) {
|
|
||||||
return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
|
return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected boolean isDubboMetadataServiceURL(URL url) {
|
||||||
* Get the service names for Dubbo OPS
|
return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface());
|
||||||
*
|
|
||||||
* @param url {@link URL}
|
|
||||||
* @return non-null
|
|
||||||
*/
|
|
||||||
protected Set<String> getServiceNamesForOps(URL url) {
|
|
||||||
Set<String> serviceNames = getAllServiceNames();
|
|
||||||
return filterServiceNames(serviceNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract String getServiceName(URL url);
|
|
||||||
|
|
||||||
private void doSubscribe(final URL url, final NotifyListener listener, final Collection<String> serviceNames) {
|
|
||||||
|
|
||||||
subscribe(url, listener, serviceNames);
|
|
||||||
|
|
||||||
schedule(() -> {
|
|
||||||
subscribe(url, listener, serviceNames);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ScheduledFuture<?> schedule(Runnable runnable) {
|
protected ScheduledFuture<?> schedule(Runnable runnable) {
|
||||||
return this.servicesLookupScheduler.scheduleAtFixedRate(runnable, servicesLookupInterval,
|
return this.servicesLookupScheduler.scheduleAtFixedRate(runnable, servicesLookupInterval,
|
||||||
servicesLookupInterval, TimeUnit.SECONDS);
|
servicesLookupInterval, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<ServiceInstance> getServiceInstances(String serviceName) {
|
|
||||||
return hasText(serviceName) ? discoveryClient.getInstances(serviceName) : emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void subscribe(final URL url, final NotifyListener listener, final Collection<String> serviceNames) {
|
|
||||||
for (String serviceName : serviceNames) {
|
|
||||||
List<ServiceInstance> serviceInstances = getServiceInstances(serviceName);
|
|
||||||
if (!isEmpty(serviceInstances)) {
|
|
||||||
notifySubscriber(url, listener, serviceInstances);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the Healthy {@link ServiceInstance service instance} to subscriber.
|
|
||||||
*
|
|
||||||
* @param url {@link URL}
|
|
||||||
* @param listener {@link NotifyListener}
|
|
||||||
* @param serviceInstances all {@link ServiceInstance instances}
|
|
||||||
*/
|
|
||||||
protected abstract void notifySubscriber(URL url, NotifyListener listener, List<ServiceInstance> serviceInstances);
|
|
||||||
|
|
||||||
protected <T> Collection<T> filter(Collection<T> collection, Predicate<T> filter) {
|
|
||||||
return collection.stream()
|
|
||||||
.filter(filter)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,14 @@
|
|||||||
package org.springframework.cloud.alibaba.dubbo.registry;
|
package org.springframework.cloud.alibaba.dubbo.registry;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.registry.NotifyListener;
|
|
||||||
import org.apache.dubbo.registry.RegistryFactory;
|
import org.apache.dubbo.registry.RegistryFactory;
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
|
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
|
||||||
@ -38,38 +36,21 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry {
|
|||||||
private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||||
|
|
||||||
public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
||||||
ScheduledExecutorService servicesLookupScheduler,
|
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||||
DubboServiceMetadataRepository dubboServiceMetadataRepository) {
|
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
||||||
super(url, discoveryClient, servicesLookupScheduler);
|
JSONUtils jsonUtils,
|
||||||
|
ScheduledExecutorService servicesLookupScheduler) {
|
||||||
|
super(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler);
|
||||||
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
|
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doRegister0(URL url) {
|
protected void doRegister0(URL url) {
|
||||||
dubboServiceMetadataRepository.registerURL(url);
|
dubboServiceMetadataRepository.exportURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doUnregister0(URL url) {
|
protected void doUnregister0(URL url) {
|
||||||
dubboServiceMetadataRepository.unregisterURL(url);
|
dubboServiceMetadataRepository.unexportURL(url);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean supports(String serviceName) {
|
|
||||||
return dubboServiceMetadataRepository.isSubscribedService(serviceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getServiceName(URL url) {
|
|
||||||
return dubboServiceMetadataRepository.getServiceName(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void notifySubscriber(URL url, NotifyListener listener, List<ServiceInstance> serviceInstances) {
|
|
||||||
List<URL> urls = serviceInstances.stream()
|
|
||||||
.map(dubboServiceMetadataRepository::buildURLs)
|
|
||||||
.flatMap(List::stream)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
notify(url, listener, urls);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ import org.apache.dubbo.registry.Registry;
|
|||||||
import org.apache.dubbo.registry.RegistryFactory;
|
import org.apache.dubbo.registry.RegistryFactory;
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
@ -50,6 +52,10 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
|||||||
|
|
||||||
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||||
|
|
||||||
|
private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy;
|
||||||
|
|
||||||
|
private JSONUtils jsonUtils;
|
||||||
|
|
||||||
private volatile boolean initialized = false;
|
private volatile boolean initialized = false;
|
||||||
|
|
||||||
public SpringCloudRegistryFactory() {
|
public SpringCloudRegistryFactory() {
|
||||||
@ -63,12 +69,15 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
|||||||
}
|
}
|
||||||
this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
|
this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
|
||||||
this.dubboServiceMetadataRepository = applicationContext.getBean(DubboServiceMetadataRepository.class);
|
this.dubboServiceMetadataRepository = applicationContext.getBean(DubboServiceMetadataRepository.class);
|
||||||
|
this.dubboMetadataConfigServiceProxy = applicationContext.getBean(DubboMetadataServiceProxy.class);
|
||||||
|
this.jsonUtils = applicationContext.getBean(JSONUtils.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Registry getRegistry(URL url) {
|
public Registry getRegistry(URL url) {
|
||||||
init();
|
init();
|
||||||
return new SpringCloudRegistry(url, discoveryClient, servicesLookupScheduler, dubboServiceMetadataRepository);
|
return new SpringCloudRegistry(url, discoveryClient, dubboServiceMetadataRepository,
|
||||||
|
dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setApplicationContext(ConfigurableApplicationContext applicationContext) {
|
public static void setApplicationContext(ConfigurableApplicationContext applicationContext) {
|
||||||
|
@ -62,9 +62,9 @@ public class DubboGenericServiceFactory {
|
|||||||
return referenceBean == null ? null : referenceBean.get();
|
return referenceBean == null ? null : referenceBean.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenericService create(String serviceName, Class<?> serviceClass) {
|
public GenericService create(String serviceName, Class<?> serviceClass, String version) {
|
||||||
String interfaceName = serviceClass.getName();
|
String interfaceName = serviceClass.getName();
|
||||||
ReferenceBean<GenericService> referenceBean = build(interfaceName, serviceName, null, emptyMap());
|
ReferenceBean<GenericService> referenceBean = build(interfaceName, version, serviceName, emptyMap());
|
||||||
return referenceBean.get();
|
return referenceBean.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,21 +16,61 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.service;
|
package org.springframework.cloud.alibaba.dubbo.service;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.config.annotation.Service;
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dubbo Metadata Service
|
* Dubbo Metadata Service is a core interface for service subscribers,
|
||||||
|
* it must keep the stable of structure in every evolution , makes sure all subscribers' compatibility.
|
||||||
|
* <p>
|
||||||
|
* The interface contract's version must be {@link #VERSION} constant and group must be current Dubbo application name
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
*/
|
*/
|
||||||
public interface DubboMetadataService {
|
public interface DubboMetadataService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get The json content of {@link ServiceRestMetadata} {@link Set}
|
* Current version of the interface contract
|
||||||
|
*/
|
||||||
|
String VERSION = "1.0.0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the json content of {@link ServiceRestMetadata} {@link Set}
|
||||||
*
|
*
|
||||||
* @return <code>null</code> if present
|
* @return <code>null</code> if present
|
||||||
*/
|
*/
|
||||||
String getServiceRestMetadata();
|
String getServiceRestMetadata();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all exported {@link URL#getServiceKey() service keys}
|
||||||
|
*
|
||||||
|
* @return non-null read-only {@link Set}
|
||||||
|
*/
|
||||||
|
Set<String> getAllServiceKeys();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all exported Dubbo's {@link URL URLs} {@link Map} whose key is the return value of
|
||||||
|
* {@link URL#getServiceKey()} method and value is the json content of List<URL> of {@link URL URLs}
|
||||||
|
*
|
||||||
|
* @return non-null read-only {@link Map}
|
||||||
|
*/
|
||||||
|
Map<String, String> getAllExportedURLs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the json content of an exported List<URL> of {@link URL URLs} by the serviceInterface , group and version
|
||||||
|
*
|
||||||
|
* @param serviceInterface The class name of service interface
|
||||||
|
* @param group {@link Service#group() the service group} (optional)
|
||||||
|
* @param version {@link Service#version() the service version} (optional)
|
||||||
|
* @return non-null read-only {@link List}
|
||||||
|
* @see URL
|
||||||
|
*/
|
||||||
|
String getExportedURLs(String serviceInterface, String group, String version);
|
||||||
}
|
}
|
||||||
|
@ -16,16 +16,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.service;
|
package org.springframework.cloud.alibaba.dubbo.service;
|
||||||
|
|
||||||
|
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.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.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,12 +46,12 @@ public class DubboMetadataServiceExporter {
|
|||||||
private ApplicationConfig applicationConfig;
|
private ApplicationConfig applicationConfig;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DubboMetadataService dubboMetadataService;
|
private ObjectProvider<DubboMetadataService> dubboMetadataService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Supplier<ProtocolConfig> protocolConfigSupplier;
|
private Supplier<ProtocolConfig> protocolConfigSupplier;
|
||||||
|
|
||||||
@Value("${spring.application.name:application}")
|
@Value("${spring.application.name:${dubbo.application.name:application}}")
|
||||||
private String currentApplicationName;
|
private String currentApplicationName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,33 +61,39 @@ public class DubboMetadataServiceExporter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* export {@link DubboMetadataService} as Dubbo service
|
* export {@link DubboMetadataService} as Dubbo service
|
||||||
|
*
|
||||||
|
* @return the exported {@link URL URLs}
|
||||||
*/
|
*/
|
||||||
public void export() {
|
public List<URL> export() {
|
||||||
|
|
||||||
if (serviceConfig != null && serviceConfig.isExported()) {
|
if (serviceConfig == null || !serviceConfig.isExported()) {
|
||||||
return;
|
|
||||||
|
serviceConfig = new ServiceConfig<>();
|
||||||
|
|
||||||
|
serviceConfig.setInterface(DubboMetadataService.class);
|
||||||
|
// Use DubboMetadataService.VERSION as the Dubbo Service version
|
||||||
|
serviceConfig.setVersion(DubboMetadataService.VERSION);
|
||||||
|
// Use current Spring application name as the Dubbo Service group
|
||||||
|
serviceConfig.setGroup(currentApplicationName);
|
||||||
|
serviceConfig.setRef(dubboMetadataService.getIfAvailable());
|
||||||
|
serviceConfig.setApplication(applicationConfig);
|
||||||
|
serviceConfig.setProtocol(protocolConfigSupplier.get());
|
||||||
|
|
||||||
|
serviceConfig.export();
|
||||||
|
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceConfig = new ServiceConfig<>();
|
return serviceConfig.getExportedUrls();
|
||||||
|
|
||||||
serviceConfig.setInterface(DubboMetadataService.class);
|
|
||||||
// Use current Spring application name as the Dubbo Service version
|
|
||||||
serviceConfig.setVersion(currentApplicationName);
|
|
||||||
serviceConfig.setRef(dubboMetadataService);
|
|
||||||
serviceConfig.setApplication(applicationConfig);
|
|
||||||
serviceConfig.setProtocol(protocolConfigSupplier.get());
|
|
||||||
|
|
||||||
serviceConfig.export();
|
|
||||||
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unexport {@link DubboMetadataService}
|
* unexport {@link DubboMetadataService}
|
||||||
*/
|
*/
|
||||||
|
@PreDestroy
|
||||||
public void unexport() {
|
public void unexport() {
|
||||||
|
|
||||||
if (serviceConfig == null || serviceConfig.isUnexported()) {
|
if (serviceConfig == null || serviceConfig.isUnexported()) {
|
||||||
|
@ -18,8 +18,12 @@ package org.springframework.cloud.alibaba.dubbo.service;
|
|||||||
|
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
import org.apache.dubbo.rpc.service.GenericService;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DubboMetadataService} {@link InvocationHandler}
|
* {@link DubboMetadataService} {@link InvocationHandler}
|
||||||
@ -28,27 +32,29 @@ import java.lang.reflect.Method;
|
|||||||
*/
|
*/
|
||||||
class DubboMetadataServiceInvocationHandler implements InvocationHandler {
|
class DubboMetadataServiceInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
/**
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
* The method name of {@link DubboMetadataService#getServiceRestMetadata()}
|
|
||||||
*/
|
|
||||||
private static final String METHOD_NAME = "getServiceRestMetadata";
|
|
||||||
|
|
||||||
private static final String[] PARAMETER_TYPES = new String[0];
|
|
||||||
|
|
||||||
private static final String[] PARAMETER_VALUES = new String[0];
|
|
||||||
|
|
||||||
private final GenericService genericService;
|
private final GenericService genericService;
|
||||||
|
|
||||||
public DubboMetadataServiceInvocationHandler(String serviceName, DubboGenericServiceFactory dubboGenericServiceFactory) {
|
public DubboMetadataServiceInvocationHandler(String serviceName, String version, DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||||
this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class);
|
this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
String methodName = method.getName();
|
Object returnValue = null;
|
||||||
if (METHOD_NAME.equals(methodName)) {
|
try {
|
||||||
return genericService.$invoke(methodName, PARAMETER_TYPES, PARAMETER_VALUES);
|
returnValue = genericService.$invoke(method.getName(), getParameterTypes(method), args);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (logger.isErrorEnabled()) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return method.invoke(proxy, args);
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getParameterTypes(Method method) {
|
||||||
|
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||||
|
return Stream.of(parameterTypes).map(Class::getName).toArray(length -> new String[length]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,35 +17,68 @@
|
|||||||
package org.springframework.cloud.alibaba.dubbo.service;
|
package org.springframework.cloud.alibaba.dubbo.service;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static java.lang.reflect.Proxy.newProxyInstance;
|
import static java.lang.reflect.Proxy.newProxyInstance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The proxy of {@link DubboMetadataService}
|
* The proxy of {@link DubboMetadataService}
|
||||||
*/
|
*/
|
||||||
public class DubboMetadataServiceProxy implements BeanClassLoaderAware {
|
public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean {
|
||||||
|
|
||||||
private final DubboGenericServiceFactory dubboGenericServiceFactory;
|
private final DubboGenericServiceFactory dubboGenericServiceFactory;
|
||||||
|
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
private final Map<String, DubboMetadataService> dubboMetadataServiceCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public DubboMetadataServiceProxy(DubboGenericServiceFactory dubboGenericServiceFactory) {
|
public DubboMetadataServiceProxy(DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||||
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
|
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New proxy instance of {@link DubboMetadataService} via the specified service name
|
* Initializes {@link DubboMetadataService}'s Proxy
|
||||||
|
*
|
||||||
|
* @param serviceName the service name
|
||||||
|
* @param version the service version
|
||||||
|
* @return a {@link DubboMetadataService} proxy
|
||||||
|
*/
|
||||||
|
public DubboMetadataService initProxy(String serviceName, String version) {
|
||||||
|
return dubboMetadataServiceCache.computeIfAbsent(serviceName, name -> newProxy(name, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a proxy instance of {@link DubboMetadataService} via the specified service name
|
||||||
*
|
*
|
||||||
* @param serviceName the service name
|
* @param serviceName the service name
|
||||||
* @return a {@link DubboMetadataService} proxy
|
* @return a {@link DubboMetadataService} proxy
|
||||||
*/
|
*/
|
||||||
public DubboMetadataService newProxy(String serviceName) {
|
public DubboMetadataService getProxy(String serviceName) {
|
||||||
return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class},
|
return dubboMetadataServiceCache.get(serviceName);
|
||||||
new DubboMetadataServiceInvocationHandler(serviceName, dubboGenericServiceFactory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() throws Exception {
|
||||||
|
dubboMetadataServiceCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New a proxy instance of {@link DubboMetadataService} via the specified service name
|
||||||
|
*
|
||||||
|
* @param serviceName the service name
|
||||||
|
* @param version the service version
|
||||||
|
* @return a {@link DubboMetadataService} proxy
|
||||||
|
*/
|
||||||
|
protected DubboMetadataService newProxy(String serviceName, String version) {
|
||||||
|
return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class},
|
||||||
|
new DubboMetadataServiceInvocationHandler(serviceName, version, dubboGenericServiceFactory));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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.service;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.Collections.unmodifiableMap;
|
||||||
|
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Introspective {@link DubboMetadataService} implementation
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class IntrospectiveDubboMetadataService implements DubboMetadataService {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectProvider<DubboServiceMetadataRepository> dubboServiceMetadataRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JSONUtils jsonUtils;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceRestMetadata() {
|
||||||
|
Set<ServiceRestMetadata> serviceRestMetadata = getRepository().getServiceRestMetadata();
|
||||||
|
String serviceRestMetadataJsonConfig = null;
|
||||||
|
if (!isEmpty(serviceRestMetadata)) {
|
||||||
|
serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata);
|
||||||
|
}
|
||||||
|
return serviceRestMetadataJsonConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getAllServiceKeys() {
|
||||||
|
return getRepository().getAllServiceKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getAllExportedURLs() {
|
||||||
|
Map<String, List<URL>> allExportedUrls = getRepository().getAllExportedUrls();
|
||||||
|
if (isEmpty(allExportedUrls)) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("There is no registered URL.");
|
||||||
|
}
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
|
||||||
|
allExportedUrls.forEach((serviceKey, urls) -> {
|
||||||
|
result.put(serviceKey, jsonUtils.toJSON(urls));
|
||||||
|
});
|
||||||
|
|
||||||
|
return unmodifiableMap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExportedURLs(String serviceInterface, String group, String version) {
|
||||||
|
List<URL> urls = getRepository().getExportedURLs(serviceInterface, group, version);
|
||||||
|
return jsonUtils.toJSON(urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DubboServiceMetadataRepository getRepository() {
|
||||||
|
return dubboServiceMetadataRepository.getIfAvailable();
|
||||||
|
}
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.service;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
|
||||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publishing {@link DubboMetadataService} implementation
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
|
||||||
*/
|
|
||||||
public class PublishingDubboMetadataService implements DubboMetadataService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service,
|
|
||||||
* the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods.
|
|
||||||
*/
|
|
||||||
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private JSONUtils jsonUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publish the {@link Set} of {@link ServiceRestMetadata}
|
|
||||||
*
|
|
||||||
* @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata}
|
|
||||||
*/
|
|
||||||
public void publishServiceRestMetadata(Set<ServiceRestMetadata> serviceRestMetadataSet) {
|
|
||||||
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
|
|
||||||
if (!CollectionUtils.isEmpty(serviceRestMetadata.getMeta())) {
|
|
||||||
this.serviceRestMetadata.add(serviceRestMetadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getServiceRestMetadata() {
|
|
||||||
String serviceRestMetadataJsonConfig = null;
|
|
||||||
if (!isEmpty(serviceRestMetadata)) {
|
|
||||||
serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata);
|
|
||||||
}
|
|
||||||
return serviceRestMetadataJsonConfig;
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.alibaba.dubbo.util;
|
package org.springframework.cloud.alibaba.dubbo.util;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
@ -25,8 +27,10 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON Utilities class
|
* JSON Utilities class
|
||||||
@ -44,6 +48,10 @@ public class JSONUtils {
|
|||||||
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toJSON(Collection<URL> urls) {
|
||||||
|
return toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
public String toJSON(Object object) {
|
public String toJSON(Object object) {
|
||||||
String jsonContent = null;
|
String jsonContent = null;
|
||||||
try {
|
try {
|
||||||
@ -56,6 +64,11 @@ public class JSONUtils {
|
|||||||
return jsonContent;
|
return jsonContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<URL> toURLs(String urlsJSON) {
|
||||||
|
List<String> list = toList(urlsJSON);
|
||||||
|
return list.stream().map(URL::valueOf).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
public List<String> toList(String json) {
|
public List<String> toList(String json) {
|
||||||
List<String> list = Collections.emptyList();
|
List<String> list = Collections.emptyList();
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user