Polish : /spring-cloud-incubator/spring-cloud-alibaba#386 : supports Spring Cloud Netflix Eureka and Spring Cloud Zookeeper

pull/389/head
mercyblitz 6 years ago
parent 6daba36e35
commit b3c26c509e

@ -17,6 +17,8 @@
<dubbo.version>2.6.5</dubbo.version>
<dubbo-spring-boot.version>0.2.1.RELEASE</dubbo-spring-boot.version>
<dubbo-registry-nacos.version>0.0.2</dubbo-registry-nacos.version>
<spring-cloud-zookeeper.version>2.1.0.RELEASE</spring-cloud-zookeeper.version>
<curator.version>4.0.1</curator.version>
</properties>
<dependencyManagement>
@ -53,6 +55,54 @@
<optional>true</optional>
</dependency>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<optional>true</optional>
</dependency>
<!-- Zookeeper Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<version>${spring-cloud-zookeeper.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
<optional>true</optional>
</dependency>
<!-- Nacos Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
@ -90,11 +140,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
@ -118,37 +163,6 @@
<artifactId>netty-all</artifactId>
</dependency>
<!-- REST support dependencies -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-netty4</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@ -162,11 +176,6 @@
<version>9.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
@ -192,19 +201,6 @@
<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>

@ -33,7 +33,6 @@ import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceM
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.context.annotation.Configuration;
@ -55,8 +54,8 @@ import java.util.Map;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Configuration
@ConditionalOnClass(RestTemplate.class)
@AutoConfigureAfter(LoadBalancerAutoConfiguration.class)
@ConditionalOnClass(name = {"org.springframework.web.client.RestTemplate"})
@AutoConfigureAfter(name = {"org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration"})
public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClassLoaderAware {
private static final Class<DubboTransported> DUBBO_TRANSPORTED_CLASS = DubboTransported.class;

@ -66,6 +66,12 @@ public class DubboMetadataAutoConfiguration {
protocolConfig = iterator.hasNext() ? iterator.next() : null;
}
if (protocolConfig == null) {
protocolConfig = new ProtocolConfig();
protocolConfig.setName(DEFAULT_PROTOCOL);
protocolConfig.setPort(20880);
}
return protocolConfig;
}

@ -17,7 +17,6 @@
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import feign.Contract;
import feign.Feign;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -28,7 +27,6 @@ import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolve
import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@ -39,8 +37,8 @@ import org.springframework.core.env.Environment;
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConditionalOnClass(value = Feign.class)
@AutoConfigureAfter(FeignAutoConfiguration.class)
@ConditionalOnClass(name = {"feign.Feign"})
@AutoConfigureAfter(name = {"org.springframework.cloud.openfeign.FeignAutoConfiguration"})
@Configuration
public class DubboOpenFeignAutoConfiguration {

@ -84,7 +84,7 @@ public class DubboServiceBeanMetadataResolver implements BeanClassLoaderAware, S
Stream.of(CONTRACT_CLASS_NAMES)
.filter(this::isClassPresent) // filter the existed classes
.map(this::loadContractClass) // load Contract Class
.map(this::createContract) // create instance by the specified class
.map(this::createContract) // createServiceInstance instance by the specified class
.forEach(contracts::add); // add the Contract instance into contracts
this.contracts = Collections.unmodifiableCollection(contracts);

@ -26,6 +26,7 @@ import org.springframework.core.env.Environment;
import static java.lang.reflect.Proxy.newProxyInstance;
import static org.springframework.util.ClassUtils.getUserClass;
import static org.springframework.util.ClassUtils.isPresent;
import static org.springframework.util.ClassUtils.resolveClassName;
/**
@ -64,12 +65,14 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
Class<?> beanClass = getUserClass(bean.getClass());
Class<?> targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader);
if (targetClass.isAssignableFrom(beanClass)) {
return newProxyInstance(classLoader, new Class[]{targetClass},
new TargeterInvocationHandler(bean, environment, dubboServiceMetadataRepository,
dubboGenericServiceFactory,contextFactory));
if (isPresent(TARGETER_CLASS_NAME, classLoader)) {
Class<?> beanClass = getUserClass(bean.getClass());
Class<?> targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader);
if (targetClass.isAssignableFrom(beanClass)) {
return newProxyInstance(classLoader, new Class[]{targetClass},
new TargeterInvocationHandler(bean, environment, dubboServiceMetadataRepository,
dubboGenericServiceFactory, contextFactory));
}
}
return bean;
}

@ -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.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.NetUtils;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import java.util.LinkedHashMap;
/**
* Abstract {@link RegistrationFactory} implementation
* <p>
*
* @param <T> The subclass of {@link Registration}
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public abstract class AbstractRegistrationFactory<T extends Registration> implements RegistrationFactory<T> {
protected 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(url.toIdentityString(), serviceName, ip, port, false);
serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters()));
return serviceInstance;
}
}

@ -0,0 +1,35 @@
/*
* 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 org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext;
/**
* Default {@link RegistrationFactory}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class DefaultRegistrationFactory extends AbstractRegistrationFactory<Registration> {
@Override
public Registration create(String serviceName, URL url, ApplicationContext applicationContext) {
return new DelegatingRegistration(createServiceInstance(serviceName, url));
}
}

@ -27,11 +27,11 @@ import java.util.Map;
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
class DubboRegistration implements Registration {
class DelegatingRegistration implements Registration {
private final ServiceInstance delegate;
public DubboRegistration(ServiceInstance delegate) {
public DelegatingRegistration(ServiceInstance delegate) {
this.delegate = delegate;
}

@ -0,0 +1,42 @@
/*
* 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 org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext;
/**
* {@link Registration} Factory to createServiceInstance a instance of {@link Registration}
*
* @param <T> The subclass of {@link Registration}
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public interface RegistrationFactory<T extends Registration> {
/**
* Create a instance of {@link T}
*
* @param serviceName The service name of Dubbo service interface
* @param url The Dubbo's URL
* @param applicationContext {@link ApplicationContext}
* @return a instance of {@link T}
*/
T create(String serviceName, URL url, ApplicationContext applicationContext);
}

@ -18,7 +18,7 @@ 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.NamedThreadFactory;
import com.alibaba.dubbo.common.utils.UrlUtils;
import com.alibaba.dubbo.registry.NotifyListener;
import com.alibaba.dubbo.registry.RegistryFactory;
@ -26,11 +26,12 @@ 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.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
@ -38,11 +39,9 @@ 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;
@ -50,6 +49,13 @@ 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;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.springframework.beans.BeanUtils.instantiateClass;
import static org.springframework.core.ResolvableType.forInstance;
import static org.springframework.core.ResolvableType.forType;
import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames;
import static org.springframework.util.ClassUtils.isPresent;
import static org.springframework.util.ClassUtils.resolveClassName;
/**
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
@ -70,10 +76,6 @@ public class SpringCloudRegistry extends FailbackRegistry {
private static final int CATEGORY_INDEX = 0;
// private static final int PROTOCOL_INDEX = CATEGORY_INDEX + 1;
// private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1;
private static final int SERVICE_INTERFACE_INDEX = CATEGORY_INDEX + 1;
private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
@ -82,34 +84,122 @@ public class SpringCloudRegistry extends FailbackRegistry {
private static final String WILDCARD = "*";
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* The separator for service name
*/
private static final String SERVICE_NAME_SEPARATOR = ":";
private final ApplicationContext applicationContext;
private final ServiceRegistry<Registration> serviceRegistry;
private final DiscoveryClient discoveryClient;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final RegistrationFactory registrationFactory;
/**
* {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS)
* The {@link ScheduledExecutorService Scheduler} to lookup the registered services
*/
private volatile ScheduledExecutorService scheduledExecutorService;
private final ScheduledExecutorService registeredServicesLookupScheduler;
/**
* The {@link ScheduledExecutorService Scheduler} to lookup all services (only for Dubbo-OPS)
*/
private volatile ScheduledExecutorService allServicesLookupScheduler;
/**
* 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);
private static final long ALL_SERVICES_LOOKUP_INTERVAL = Long.getLong("dubbo.all.services.lookup.interval", 30);
/**
* The interval in second of lookup regigered service instances
*/
private static final long REGISTERED_SERVICES_LOOKUP_INTERVAL = Long.getLong("dubbo.registered.services.lookup.interval", 30);
public SpringCloudRegistry(URL url, ServiceRegistry<Registration> serviceRegistry,
DiscoveryClient discoveryClient) {
public SpringCloudRegistry(URL url, ApplicationContext applicationContext) {
super(url);
this.serviceRegistry = serviceRegistry;
this.discoveryClient = discoveryClient;
this.applicationContext = applicationContext;
this.serviceRegistry = applicationContext.getBean(ServiceRegistry.class);
this.registrationFactory = buildRegistrationFactory(serviceRegistry, applicationContext.getClassLoader());
this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
applicationContext.getClassLoader();
this.registeredServicesLookupScheduler = newSingleThreadScheduledExecutor(new NamedThreadFactory("dubbo-registered-services-lookup-"));
}
private RegistrationFactory buildRegistrationFactory(ServiceRegistry<Registration> serviceRegistry,
ClassLoader classLoader) {
RegistrationFactory registrationFactory = null;
List<String> factoryClassNames = loadFactoryNames(RegistrationFactory.class, classLoader);
ResolvableType serviceRegistryType = forInstance(serviceRegistry);
// Get first generic Class
Class<?> registrationClass = resolveGenericClass(serviceRegistryType, ServiceRegistry.class, 0);
for (String factoryClassName : factoryClassNames) {
if (isPresent(factoryClassName, classLoader)) { // ignore compilation issue
Class<?> factoryClass = resolveClassName(factoryClassName, classLoader);
ResolvableType registrationFactoryType = forType(factoryClass);
Class<?> actualRegistrationClass = resolveGenericClass(registrationFactoryType, RegistrationFactory.class, 0);
if (actualRegistrationClass.equals(registrationClass)) {
registrationFactory = (RegistrationFactory) instantiateClass(registrationFactoryType.getRawClass());
break;
}
}
}
if (registrationFactory == null) {
if (logger.isWarnEnabled()) {
logger.warn("{} implementation can't be resolved by ServiceRegistry[{}]",
registrationClass.getSimpleName(), serviceRegistry.getClass().getName());
}
registrationFactory = new DefaultRegistrationFactory();
} else {
if (logger.isInfoEnabled()) {
logger.info("{} has been resolved by ServiceRegistry[{}]",
registrationFactory.getClass().getName(), serviceRegistry.getClass().getName());
}
}
return registrationFactory;
}
private Class<?> resolveGenericClass(ResolvableType implementedType, Class<?> interfaceClass, int index) {
ResolvableType resolvableType = implementedType;
OUTER:
while (true) {
ResolvableType[] interfaceTypes = resolvableType.getInterfaces();
for (ResolvableType interfaceType : interfaceTypes) {
if (interfaceType.resolve().equals(interfaceClass)) {
resolvableType = interfaceType;
break OUTER;
}
}
ResolvableType superType = resolvableType.getSuperType();
Class<?> superClass = superType.resolve();
if (Object.class.equals(superClass)) {
break;
}
resolvableType = superType;
}
return resolvableType.resolveGeneric(index);
}
@Override
protected void doRegister(URL url) {
final String serviceName = getServiceName(url);
@ -128,6 +218,12 @@ public class SpringCloudRegistry extends FailbackRegistry {
protected void doSubscribe(URL url, NotifyListener listener) {
List<String> serviceNames = getServiceNames(url, listener);
doSubscribe(url, listener, serviceNames);
this.registeredServicesLookupScheduler.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
doSubscribe(url, listener, serviceNames);
}
}, REGISTERED_SERVICES_LOOKUP_INTERVAL, REGISTERED_SERVICES_LOOKUP_INTERVAL, TimeUnit.SECONDS);
}
@Override
@ -135,6 +231,10 @@ public class SpringCloudRegistry extends FailbackRegistry {
if (isAdminProtocol(url)) {
shutdownServiceNamesLookup();
}
if (registeredServicesLookupScheduler != null) {
registeredServicesLookupScheduler.shutdown();
}
}
@Override
@ -143,25 +243,13 @@ public class SpringCloudRegistry extends FailbackRegistry {
}
private void shutdownServiceNamesLookup() {
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdown();
if (allServicesLookupScheduler != null) {
allServicesLookupScheduler.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;
return registrationFactory.create(serviceName, url, applicationContext);
}
public static String getServiceName(URL url) {
@ -248,10 +336,6 @@ public class SpringCloudRegistry extends FailbackRegistry {
return segments[CATEGORY_INDEX];
}
// public static String getProtocol(String[] segments) {
// return segments[PROTOCOL_INDEX];
// }
public static String getServiceInterface(String[] segments) {
return segments[SERVICE_INTERFACE_INDEX];
}
@ -288,7 +372,7 @@ public class SpringCloudRegistry extends FailbackRegistry {
*/
private List<String> getServiceNames(URL url, NotifyListener listener) {
if (isAdminProtocol(url)) {
scheduleServiceNamesLookup(url, listener);
initAllServicesLookupScheduler(url, listener);
return getServiceNamesForOps(url);
} else {
return doGetServiceNames(url);
@ -300,10 +384,10 @@ public class SpringCloudRegistry extends FailbackRegistry {
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() {
private void initAllServicesLookupScheduler(final URL url, final NotifyListener listener) {
if (allServicesLookupScheduler == null) {
allServicesLookupScheduler = newSingleThreadScheduledExecutor(new NamedThreadFactory("dubbo-all-services-lookup-"));
allServicesLookupScheduler.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
List<String> serviceNames = getAllServiceNames();
@ -323,7 +407,7 @@ public class SpringCloudRegistry extends FailbackRegistry {
});
doSubscribe(url, listener, serviceNames);
}
}, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
}, ALL_SERVICES_LOOKUP_INTERVAL, ALL_SERVICES_LOOKUP_INTERVAL, TimeUnit.SECONDS);
}
}
@ -331,7 +415,6 @@ public class SpringCloudRegistry extends FailbackRegistry {
for (String serviceName : serviceNames) {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
notifySubscriber(url, listener, serviceInstances);
// TODO Support Update notification event
}
}

@ -20,9 +20,6 @@ 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;
/**
@ -38,9 +35,7 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
@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);
return new SpringCloudRegistry(url, applicationContext);
}
public static void setApplicationContext(ApplicationContext applicationContext) {

@ -0,0 +1,54 @@
/*
* 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.apache.zookeeper;
import com.alibaba.dubbo.common.URL;
import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory;
import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.zookeeper.discovery.ZookeeperInstance;
import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegistration;
import org.springframework.cloud.zookeeper.serviceregistry.ZookeeperRegistration;
import org.springframework.context.ApplicationContext;
/**
* Zookeeper {@link RegistrationFactory}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class ZookeeperRegistrationFactory extends AbstractRegistrationFactory<ZookeeperRegistration> {
@Override
public ZookeeperRegistration create(String serviceName, URL url, ApplicationContext applicationContext) {
ServiceInstance serviceInstance = createServiceInstance(serviceName, url);
ZookeeperInstance zookeeperInstance = new ZookeeperInstance(serviceInstance.getInstanceId(),
serviceInstance.getServiceId(), serviceInstance.getMetadata());
ZookeeperRegistration registration = ServiceInstanceRegistration
.builder()
.address(serviceInstance.getHost())
.name(serviceInstance.getServiceId())
.payload(zookeeperInstance)
.port(serviceInstance.getPort())
.build();
return registration;
}
}

@ -0,0 +1,62 @@
/*
* 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.netflix.eureka;
import com.alibaba.dubbo.common.URL;
import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.discovery.EurekaClientConfig;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
import org.springframework.context.ApplicationContext;
/**
* {@link EurekaRegistration} Factory
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class EurekaRegistrationFactory extends AbstractRegistrationFactory<EurekaRegistration> {
@Override
public EurekaRegistration create(String serviceName, URL url, ApplicationContext applicationContext) {
ServiceInstance serviceInstance = createServiceInstance(serviceName, url);
CloudEurekaInstanceConfig cloudEurekaInstanceConfig = applicationContext.getBean(CloudEurekaInstanceConfig.class);
ObjectProvider<HealthCheckHandler> healthCheckHandler = applicationContext.getBeanProvider(HealthCheckHandler.class);
EurekaClientConfig eurekaClientConfig = applicationContext.getBean(EurekaClientConfig.class);
InetUtils inetUtils = applicationContext.getBean(InetUtils.class);
EurekaInstanceConfigBean eurekaInstanceConfigBean = new EurekaInstanceConfigBean(inetUtils);
BeanUtils.copyProperties(cloudEurekaInstanceConfig, eurekaInstanceConfigBean);
String serviceId = serviceInstance.getServiceId();
eurekaInstanceConfigBean.setInstanceId(serviceInstance.getInstanceId());
eurekaInstanceConfigBean.setVirtualHostName(serviceId);
eurekaInstanceConfigBean.setSecureVirtualHostName(serviceId);
eurekaInstanceConfigBean.setAppname(serviceId);
eurekaInstanceConfigBean.setHostname(serviceInstance.getHost());
eurekaInstanceConfigBean.setMetadataMap(serviceInstance.getMetadata());
return EurekaRegistration.builder(eurekaInstanceConfigBean)
.with(healthCheckHandler)
.with(eurekaClientConfig, applicationContext)
.build();
}
}

@ -6,4 +6,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory=\
org.springframework.cloud.alibaba.dubbo.registry.DefaultRegistrationFactory,\
org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka.EurekaRegistrationFactory,\
org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper.ZookeeperRegistrationFactory

@ -1,222 +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.bootstrap;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported;
import org.springframework.cloud.alibaba.dubbo.service.RestService;
import org.springframework.cloud.alibaba.dubbo.service.User;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;
/**
* Dubbo Spring Cloud Bootstrap
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableFeignClients
@RestController
public class DubboSpringCloudBootstrap {
@Reference(version = "1.0.0")
private RestService restService;
@Autowired
@Lazy
private FeignRestService feignRestService;
@Autowired
@Lazy
private DubboFeignRestService dubboFeignRestService;
@Autowired
@LoadBalanced
private RestTemplate restTemplate;
@FeignClient("spring-cloud-alibaba-dubbo")
public interface FeignRestService {
@GetMapping(value = "/param")
String param(@RequestParam("param") String param);
@PostMapping("/params")
public String params(@RequestParam("b") String b, @RequestParam("a") int a);
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_UTF8_VALUE)
User requestBody(@RequestParam("param") String param, @RequestBody Map<String, Object> data);
@GetMapping("/headers")
@Path("/headers")
@GET
public String headers(@RequestHeader("h2") String header2,
@RequestHeader("h") String header,
@RequestParam("v") Integer value);
@GetMapping("/path-variables/{p1}/{p2}")
public String pathVariables(@PathVariable("p2") String path2,
@PathVariable("p1") String path1,
@RequestParam("v") String param);
}
@FeignClient("spring-cloud-alibaba-dubbo")
@DubboTransported
public interface DubboFeignRestService {
@GetMapping(value = "/param")
String param(@RequestParam("param") String param);
@PostMapping("/params")
String params(@RequestParam("b") String paramB, @RequestParam("a") int paramA);
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_UTF8_VALUE)
User requestBody(@RequestParam("param") String param, @RequestBody Map<String, Object> data);
@GetMapping("/headers")
@Path("/headers")
@GET
public String headers(@RequestHeader("h2") String header2,
@RequestParam("v") Integer value,
@RequestHeader("h") String header);
@GetMapping("/path-variables/{p1}/{p2}")
public String pathVariables(@RequestParam("v") String param,
@PathVariable("p2") String path2,
@PathVariable("p1") String path1);
}
@Bean
public ApplicationRunner paramRunner() {
return arguments -> {
// To call /path-variables
callPathVariables();
// To call /headers
callHeaders();
// To call /param
callParam();
// To call /params
callParams();
// To call /request/body/map
callRequestBodyMap();
};
}
private void callPathVariables() {
// Dubbo Service call
System.out.println(restService.pathVariables("a", "b", "c"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.pathVariables("c", "b", "a"));
// Spring Cloud Open Feign REST Call
System.out.println(feignRestService.pathVariables("b", "a", "c"));
// RestTemplate call
System.out.println(restTemplate.getForEntity("http://spring-cloud-alibaba-dubbo//path-variables/{p1}/{p2}?v=c", String.class, "a", "b"));
}
private void callHeaders() {
// Dubbo Service call
System.out.println(restService.headers("a", "b", 10));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.headers("b", 10, "a"));
// Spring Cloud Open Feign REST Call
System.out.println(feignRestService.headers("b", "a", 10));
}
private void callParam() {
// Dubbo Service call
System.out.println(restService.param("mercyblitz"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.param("mercyblitz"));
// Spring Cloud Open Feign REST Call
System.out.println(feignRestService.param("mercyblitz"));
}
private void callParams() {
// Dubbo Service call
System.out.println(restService.params(1, "1"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.params("1", 1));
// Spring Cloud Open Feign REST Call
System.out.println(feignRestService.params("1", 1));
// RestTemplate call
System.out.println(restTemplate.getForEntity("http://spring-cloud-alibaba-dubbo/param?param=小马哥", String.class));
}
private void callRequestBodyMap() {
Map<String, Object> data = new HashMap<>();
data.put("id", 1);
data.put("name", "小马哥");
data.put("age", 33);
// Dubbo Service call
System.out.println(restService.requestBodyMap(data, "Hello,World"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
// System.out.println(dubboFeignRestService.requestBody("Hello,World", data));
// Spring Cloud Open Feign REST Call
System.out.println(feignRestService.requestBody("Hello,World", data));
// RestTemplate call
System.out.println(restTemplate.postForObject("http://spring-cloud-alibaba-dubbo/request/body/map?param=小马哥", data, User.class));
}
@Bean
@LoadBalanced
@DubboTransported
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
.run(args);
}
}

@ -7,7 +7,7 @@ dubbo:
port: 12345
rest:
name: rest
port: 9090
port: 8081
server: netty
registry:
address: spring-cloud://nacos

@ -7,6 +7,9 @@ spring:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
zookeeper:
enabled: false
main:
allow-bean-definition-overriding: true
@ -27,4 +30,18 @@ eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
defaultZone: http://localhost:9090/eureka/
---
spring:
profiles: zookeeper
cloud:
nacos:
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: true
connect-string: localhost:2181

@ -0,0 +1,37 @@
/*
* 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 org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Dubbo Spring Cloud Provider Bootstrap
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
public class DubboSpringCloudProviderBootstrap {
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudProviderBootstrap.class)
.run(args);
}
}

@ -20,6 +20,7 @@ import com.alibaba.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -40,7 +41,6 @@ import javax.ws.rs.QueryParam;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
/**
@ -109,7 +109,7 @@ public class StandardRestService implements RestService {
}
@Override
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_UTF8_VALUE)
@PostMapping(value = "/request/body/map", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Path("/request/body/map")
@POST
@Produces(APPLICATION_JSON_VALUE)
@ -122,11 +122,11 @@ public class StandardRestService implements RestService {
return user;
}
@PostMapping(value = "/request/body/user", consumes = APPLICATION_JSON_UTF8_VALUE)
@PostMapping(value = "/request/body/user", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Path("/request/body/user")
@POST
@Override
@Consumes(APPLICATION_JSON_UTF8_VALUE)
@Consumes(MediaType.APPLICATION_JSON_UTF8_VALUE)
public Map<String, Object> requestBodyUser(@RequestBody User user) {
Map<String, Object> map = new HashMap<>();
map.put("id", user.getId());

@ -19,7 +19,7 @@ package org.springframework.cloud.alibaba.dubbo.service;
import java.util.Map;
/**
* Echo Service
* Rest Service
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ -38,5 +38,4 @@ public interface RestService {
User requestBodyMap(Map<String, Object> data, String param);
Map<String, Object> requestBodyUser(User user);
}

@ -16,21 +16,19 @@
*/
package org.springframework.cloud.alibaba.dubbo.service;
import javax.ws.rs.FormParam;
import java.io.Serializable;
/**
* User Entity
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class User implements Serializable {
@FormParam("id")
private Long id;
@FormParam("name")
private String name;
@FormParam("age")
private Integer age;
public Long getId() {
Loading…
Cancel
Save