mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
This commit is contained in:
parent
325d00d1b6
commit
d40555eff4
158
spring-cloud-alibaba-dubbo/pom.xml
Normal file
158
spring-cloud-alibaba-dubbo/pom.xml
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>spring-cloud-alibaba</artifactId>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<version>0.2.2.BUILD-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>spring-cloud-alibaba-dubbo</artifactId>
|
||||||
|
<name>Spring Cloud Alibaba Dubbo</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- Spring Boot dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-actuator</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring Cloud dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-commons</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-context</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Dubbo Spring Boot Starter -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.boot</groupId>
|
||||||
|
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>dubbo</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Netty -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- REST -->
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>org.jboss.resteasy</groupId>-->
|
||||||
|
<!--<artifactId>resteasy-jaxrs</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>org.jboss.resteasy</groupId>-->
|
||||||
|
<!--<artifactId>resteasy-client</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>javax.validation</groupId>-->
|
||||||
|
<!--<artifactId>validation-api</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>org.hibernate.validator</groupId>-->
|
||||||
|
<!--<artifactId>hibernate-validator</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>org.mortbay.jetty</groupId>-->
|
||||||
|
<!--<artifactId>jetty</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
|
<!-- Feign for JAX-RS 2-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.openfeign</groupId>
|
||||||
|
<artifactId>feign-jaxrs2</artifactId>
|
||||||
|
<version>9.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Nacos Service Discovery -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Eureka Service Discovery -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.autoconfigure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Boot Auto-Configuration class for Dubbo REST
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class DubboRestAutoConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.autoconfigure;
|
||||||
|
|
||||||
|
import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory;
|
||||||
|
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link DubboServiceRegistrationAutoConfiguration} will register the Dubbo services as the specified Spring cloud
|
||||||
|
* applications that will not be considered normal ones, but only are used to Dubbo's service discovery even if it is
|
||||||
|
* based on Spring Cloud Commons abstraction. However, current application will be registered by other
|
||||||
|
* DiscoveryClientAutoConfiguration.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class, DubboAutoConfiguration.class})
|
||||||
|
public class DubboServiceRegistrationAutoConfiguration implements ApplicationContextAware {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
// Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register
|
||||||
|
SpringCloudRegistryFactory.setApplicationContext(applicationContext);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.registry;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Registration} of Dubbo uses an external of {@link ServiceInstance} instance as the delegate.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
class DubboRegistration implements Registration {
|
||||||
|
|
||||||
|
private final ServiceInstance delegate;
|
||||||
|
|
||||||
|
public DubboRegistration(ServiceInstance delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceId() {
|
||||||
|
return delegate.getServiceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHost() {
|
||||||
|
return delegate.getHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPort() {
|
||||||
|
return delegate.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSecure() {
|
||||||
|
return delegate.isSecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI getUri() {
|
||||||
|
return delegate.getUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getMetadata() {
|
||||||
|
return delegate.getMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getScheme() {
|
||||||
|
return delegate.getScheme();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,405 @@
|
|||||||
|
/*
|
||||||
|
* 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.registry;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.common.Constants;
|
||||||
|
import com.alibaba.dubbo.common.URL;
|
||||||
|
import com.alibaba.dubbo.common.utils.NetUtils;
|
||||||
|
import com.alibaba.dubbo.common.utils.UrlUtils;
|
||||||
|
import com.alibaba.dubbo.registry.NotifyListener;
|
||||||
|
import com.alibaba.dubbo.registry.RegistryFactory;
|
||||||
|
import com.alibaba.dubbo.registry.support.FailbackRegistry;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||||
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
|
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
|
||||||
|
import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
|
||||||
|
import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
|
||||||
|
import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public class SpringCloudRegistry extends FailbackRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All supported categories
|
||||||
|
*/
|
||||||
|
private static final String[] ALL_SUPPORTED_CATEGORIES = of(
|
||||||
|
PROVIDERS_CATEGORY,
|
||||||
|
CONSUMERS_CATEGORY,
|
||||||
|
ROUTERS_CATEGORY,
|
||||||
|
CONFIGURATORS_CATEGORY
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final int CATEGORY_INDEX = 0;
|
||||||
|
|
||||||
|
private static final int SERVICE_INTERFACE_INDEX = 1;
|
||||||
|
|
||||||
|
private static final int SERVICE_VERSION_INDEX = 2;
|
||||||
|
|
||||||
|
private static final int SERVICE_GROUP_INDEX = 3;
|
||||||
|
|
||||||
|
private static final String WILDCARD = "*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The separator for service name
|
||||||
|
*/
|
||||||
|
private static final String SERVICE_NAME_SEPARATOR = ":";
|
||||||
|
|
||||||
|
private final ServiceRegistry<Registration> serviceRegistry;
|
||||||
|
|
||||||
|
private final DiscoveryClient discoveryClient;
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS)
|
||||||
|
*/
|
||||||
|
private volatile ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval in second of lookup service names(only for Dubbo-OPS)
|
||||||
|
*/
|
||||||
|
private static final long LOOKUP_INTERVAL = Long.getLong("dubbo.service.names.lookup.interval", 30);
|
||||||
|
|
||||||
|
public SpringCloudRegistry(URL url, ServiceRegistry<Registration> serviceRegistry,
|
||||||
|
DiscoveryClient discoveryClient) {
|
||||||
|
super(url);
|
||||||
|
this.serviceRegistry = serviceRegistry;
|
||||||
|
this.discoveryClient = discoveryClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRegister(URL url) {
|
||||||
|
final String serviceName = getServiceName(url);
|
||||||
|
final Registration registration = createRegistration(serviceName, url);
|
||||||
|
serviceRegistry.register(registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doUnregister(URL url) {
|
||||||
|
final String serviceName = getServiceName(url);
|
||||||
|
final Registration registration = createRegistration(serviceName, url);
|
||||||
|
this.serviceRegistry.deregister(registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doSubscribe(URL url, NotifyListener listener) {
|
||||||
|
List<String> serviceNames = getServiceNames(url, listener);
|
||||||
|
doSubscribe(url, listener, serviceNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doUnsubscribe(URL url, NotifyListener listener) {
|
||||||
|
if (isAdminProtocol(url)) {
|
||||||
|
shutdownServiceNamesLookup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shutdownServiceNamesLookup() {
|
||||||
|
if (scheduledExecutorService != null) {
|
||||||
|
scheduledExecutorService.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Registration createRegistration(String serviceName, URL url) {
|
||||||
|
return new DubboRegistration(createServiceInstance(serviceName, url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceInstance createServiceInstance(String serviceName, URL url) {
|
||||||
|
// Append default category if absent
|
||||||
|
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
|
||||||
|
URL newURL = url.addParameter(Constants.CATEGORY_KEY, category);
|
||||||
|
newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol());
|
||||||
|
String ip = NetUtils.getLocalHost();
|
||||||
|
int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort());
|
||||||
|
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(serviceName, ip, port, false);
|
||||||
|
serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters()));
|
||||||
|
return serviceInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getServiceName(URL url) {
|
||||||
|
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
|
||||||
|
return getServiceName(url, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getServiceName(URL url, String category) {
|
||||||
|
StringBuilder serviceNameBuilder = new StringBuilder(category);
|
||||||
|
appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
|
||||||
|
appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
|
||||||
|
appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
|
||||||
|
return serviceNameBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendIfPresent(StringBuilder target, URL url, String parameterName) {
|
||||||
|
String parameterValue = url.getParameter(parameterName);
|
||||||
|
if (StringUtils.hasText(parameterValue)) {
|
||||||
|
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterServiceNames(List<String> serviceNames, URL url) {
|
||||||
|
|
||||||
|
final String[] categories = getCategories(url);
|
||||||
|
|
||||||
|
final String targetServiceInterface = url.getServiceInterface();
|
||||||
|
|
||||||
|
final String targetVersion = url.getParameter(Constants.VERSION_KEY);
|
||||||
|
|
||||||
|
final String targetGroup = url.getParameter(Constants.GROUP_KEY);
|
||||||
|
|
||||||
|
filter(serviceNames, new Filter<String>() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(String serviceName) {
|
||||||
|
// split service name to segments
|
||||||
|
// (required) segments[0] = category
|
||||||
|
// (required) segments[1] = serviceInterface
|
||||||
|
// (required) segments[2] = version
|
||||||
|
// (optional) segments[3] = group
|
||||||
|
String[] segments = StringUtils.split(serviceName, SERVICE_NAME_SEPARATOR);
|
||||||
|
int length = segments.length;
|
||||||
|
if (length < 3) { // must present 3 segments or more
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String category = segments[CATEGORY_INDEX];
|
||||||
|
if (Arrays.binarySearch(categories, category) > -1) { // no match category
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String serviceInterface = segments[SERVICE_INTERFACE_INDEX];
|
||||||
|
if (!WILDCARD.equals(targetServiceInterface) &&
|
||||||
|
!Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String version = segments[SERVICE_VERSION_INDEX];
|
||||||
|
if (!WILDCARD.equals(targetVersion) &&
|
||||||
|
!Objects.equals(targetVersion, version)) { // no match service version
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String group = length > 3 ? segments[SERVICE_GROUP_INDEX] : null;
|
||||||
|
if (group != null && !WILDCARD.equals(targetGroup)
|
||||||
|
&& !Objects.equals(targetGroup, group)) { // no match service group
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the categories from {@link URL}
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @return non-null array
|
||||||
|
*/
|
||||||
|
private String[] getCategories(URL url) {
|
||||||
|
return Constants.ANY_VALUE.equals(url.getServiceInterface()) ?
|
||||||
|
ALL_SUPPORTED_CATEGORIES : of(Constants.DEFAULT_CATEGORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getAllServiceNames() {
|
||||||
|
return discoveryClient.getServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the service names from the specified {@link URL url}
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @param listener {@link NotifyListener}
|
||||||
|
* @return non-null
|
||||||
|
*/
|
||||||
|
private List<String> getServiceNames(URL url, NotifyListener listener) {
|
||||||
|
if (isAdminProtocol(url)) {
|
||||||
|
scheduleServiceNamesLookup(url, listener);
|
||||||
|
return getServiceNamesForOps(url);
|
||||||
|
} else {
|
||||||
|
return doGetServiceNames(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean isAdminProtocol(URL url) {
|
||||||
|
return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleServiceNamesLookup(final URL url, final NotifyListener listener) {
|
||||||
|
if (scheduledExecutorService == null) {
|
||||||
|
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<String> serviceNames = getAllServiceNames();
|
||||||
|
filter(serviceNames, new Filter<String>() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(String serviceName) {
|
||||||
|
boolean accepted = false;
|
||||||
|
for (String category : ALL_SUPPORTED_CATEGORIES) {
|
||||||
|
String prefix = category + SERVICE_NAME_SEPARATOR;
|
||||||
|
if (StringUtils.startsWithIgnoreCase(serviceName, prefix)) {
|
||||||
|
accepted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accepted;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
doSubscribe(url, listener, serviceNames);
|
||||||
|
}
|
||||||
|
}, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSubscribe(final URL url, final NotifyListener listener, final List<String> serviceNames) {
|
||||||
|
for (String serviceName : serviceNames) {
|
||||||
|
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
|
||||||
|
notifySubscriber(url, listener, serviceInstances);
|
||||||
|
// TODO Support Update notification event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> doGetServiceNames(URL url) {
|
||||||
|
String[] categories = getCategories(url);
|
||||||
|
List<String> serviceNames = new ArrayList<String>(categories.length);
|
||||||
|
for (String category : categories) {
|
||||||
|
final String serviceName = getServiceName(url, category);
|
||||||
|
serviceNames.add(serviceName);
|
||||||
|
}
|
||||||
|
return serviceNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the Healthy {@link ServiceInstance service instance} to subscriber.
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @param listener {@link NotifyListener}
|
||||||
|
* @param serviceInstances all {@link ServiceInstance instances}
|
||||||
|
*/
|
||||||
|
private void notifySubscriber(URL url, NotifyListener listener, List<ServiceInstance> serviceInstances) {
|
||||||
|
List<ServiceInstance> healthyInstances = new LinkedList<ServiceInstance>(serviceInstances);
|
||||||
|
// Healthy Instances
|
||||||
|
filterHealthyInstances(healthyInstances);
|
||||||
|
List<URL> urls = buildURLs(url, healthyInstances);
|
||||||
|
this.notify(url, listener, urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterHealthyInstances(Collection<ServiceInstance> instances) {
|
||||||
|
filter(instances, new Filter<ServiceInstance>() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(ServiceInstance data) {
|
||||||
|
// TODO check the details of status
|
||||||
|
return serviceRegistry.getStatus(new DubboRegistration(data)) != null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<URL> buildURLs(URL consumerURL, Collection<ServiceInstance> serviceInstances) {
|
||||||
|
if (serviceInstances.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<URL> urls = new LinkedList<URL>();
|
||||||
|
for (ServiceInstance serviceInstance : serviceInstances) {
|
||||||
|
URL url = buildURL(serviceInstance);
|
||||||
|
if (UrlUtils.isMatch(consumerURL, url)) {
|
||||||
|
urls.add(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
private URL buildURL(ServiceInstance serviceInstance) {
|
||||||
|
URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY),
|
||||||
|
serviceInstance.getHost(),
|
||||||
|
serviceInstance.getPort(),
|
||||||
|
serviceInstance.getMetadata());
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the service names for Dubbo OPS
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @return non-null
|
||||||
|
*/
|
||||||
|
private List<String> getServiceNamesForOps(URL url) {
|
||||||
|
List<String> serviceNames = getAllServiceNames();
|
||||||
|
filterServiceNames(serviceNames, url);
|
||||||
|
return serviceNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> void filter(Collection<T> collection, Filter<T> filter) {
|
||||||
|
Iterator<T> iterator = collection.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
T data = iterator.next();
|
||||||
|
if (!filter.accept(data)) { // remove if not accept
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T[] of(T... values) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filter
|
||||||
|
*/
|
||||||
|
private interface Filter<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether or not the specified data should be accepted.
|
||||||
|
*
|
||||||
|
* @param data The data to be tested
|
||||||
|
* @return <code>true</code> if and only if <code>data</code>
|
||||||
|
* should be accepted
|
||||||
|
*/
|
||||||
|
boolean accept(T data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.registry;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.common.URL;
|
||||||
|
import com.alibaba.dubbo.registry.Registry;
|
||||||
|
import com.alibaba.dubbo.registry.RegistryFactory;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
|
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||||
|
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
* @see RegistryFactory
|
||||||
|
* @see SpringCloudRegistry
|
||||||
|
*/
|
||||||
|
public class SpringCloudRegistryFactory implements RegistryFactory {
|
||||||
|
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Registry getRegistry(URL url) {
|
||||||
|
ServiceRegistry<Registration> serviceRegistry = applicationContext.getBean(ServiceRegistry.class);
|
||||||
|
DiscoveryClient discoveryClient = applicationContext.getBean(DiscoveryClient.class);
|
||||||
|
return new SpringCloudRegistry(url, serviceRegistry, discoveryClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setApplicationContext(ApplicationContext applicationContext) {
|
||||||
|
SpringCloudRegistryFactory.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
spring-cloud=org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory
|
@ -0,0 +1,3 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\
|
||||||
|
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.autoconfigure;
|
||||||
|
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link DubboServiceRegistrationAutoConfiguration} Test
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
@SpringBootTest
|
||||||
|
public class DubboServiceRegistrationAutoConfigurationTest {
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.bootstrap;
|
||||||
|
|
||||||
|
import com.alibaba.dubbo.config.annotation.Reference;
|
||||||
|
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.cloud.alibaba.dubbo.service.EchoService;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dubbo Spring Cloud Bootstrap
|
||||||
|
*/
|
||||||
|
@EnableDiscoveryClient
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
public class DubboSpringCloudBootstrap {
|
||||||
|
|
||||||
|
@Reference(version = "1.0.0")
|
||||||
|
private EchoService echoService;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ApplicationRunner applicationRunner() {
|
||||||
|
return arguments -> {
|
||||||
|
System.out.println(echoService.echo("mercyblitz"));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
|
||||||
|
.run(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.alibaba.dubbo.config.annotation.Service;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default {@link EchoService}
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
@Service(version = "1.0.0")
|
||||||
|
@RestController
|
||||||
|
public class DefaultEchoService implements EchoService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@GetMapping("/echo")
|
||||||
|
public String echo(@RequestParam String message) {
|
||||||
|
return "[echo] : " + message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Echo Service
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public interface EchoService {
|
||||||
|
|
||||||
|
String echo(String message);
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
dubbo:
|
||||||
|
scan:
|
||||||
|
base-packages: org.springframework.cloud.alibaba.dubbo.service
|
||||||
|
protocol:
|
||||||
|
port: 12345
|
||||||
|
registry:
|
||||||
|
address: spring-cloud://dummy
|
26
spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml
Normal file
26
spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: spring-cloud-alibaba-dubbo
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
server-addr: 127.0.0.1:8848
|
||||||
|
port: 12345
|
||||||
|
eureka:
|
||||||
|
client:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: eureka
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
enabled: false
|
||||||
|
register-enabled: false
|
||||||
|
|
||||||
|
eureka:
|
||||||
|
client:
|
||||||
|
enabled: true
|
||||||
|
service-url:
|
||||||
|
defaultZone: http://127.0.0.1:8761/eureka/
|
Loading…
x
Reference in New Issue
Block a user