Merge pull request #1 from spring-cloud-incubator/master

merge
pull/581/head
Kai 6 years ago committed by GitHub
commit 707dd54d09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -61,6 +61,10 @@
<email>mercyblitz@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/mercyblitz</url>
</developer>
<developer>
<name>yunzheng</name>
<email>yunzheng1228@gmail.com</email>
</developer>
</developers>

@ -26,11 +26,6 @@
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config-server</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>

@ -17,6 +17,9 @@
<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>
<spring-cloud-consul.version>2.1.0.RELEASE</spring-cloud-consul.version>
<curator.version>4.0.1</curator.version>
</properties>
<dependencyManagement>
@ -90,63 +93,85 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
</dependency>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<optional>true</optional>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<!-- Zookeeper Service Discovery -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<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>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<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>
<!-- Netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
<optional>true</optional>
</dependency>
<!-- REST support dependencies -->
<!-- Spring Cloud Consul -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
<optional>true</optional>
</dependency>
<!-- Nacos Service Discovery -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Cloud Open Feign -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-netty4</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<optional>true</optional>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Netty -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
@ -162,11 +187,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 +212,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>

@ -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,6 +65,7 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
if (isPresent(TARGETER_CLASS_NAME, classLoader)) {
Class<?> beanClass = getUserClass(bean.getClass());
Class<?> targetClass = resolveClassName(TARGETER_CLASS_NAME, classLoader);
if (targetClass.isAssignableFrom(beanClass)) {
@ -71,6 +73,7 @@ public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLo
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,14 @@ 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.lang.Long.getLong;
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 +77,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;
@ -83,33 +86,124 @@ public class SpringCloudRegistry extends FailbackRegistry {
private static final String WILDCARD = "*";
/**
* The separator for service name
* The interval in second of lookup service names(only for Dubbo-OPS)
*/
private static final String SERVICE_NAME_SEPARATOR = ":";
private static final long ALL_SERVICES_LOOKUP_INTERVAL = getLong("dubbo.all.services.lookup.interval", 30);
private final ServiceRegistry<Registration> serviceRegistry;
private final DiscoveryClient discoveryClient;
/**
* The interval in second of lookup regigered service instances
*/
private static final long REGISTERED_SERVICES_LOOKUP_INTERVAL = getLong("dubbo.registered.services.lookup.interval", 300);
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* The {@link ScheduledExecutorService Scheduler} to lookup the registered services
*/
private static final ScheduledExecutorService registeredServicesLookupScheduler = newSingleThreadScheduledExecutor(new NamedThreadFactory("dubbo-registered-services-lookup-"));
/**
* {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS)
* The {@link ScheduledExecutorService Scheduler} to lookup all services (only for Dubbo-OPS)
*/
private volatile ScheduledExecutorService scheduledExecutorService;
private static volatile ScheduledExecutorService allServicesLookupScheduler;
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* The interval in second of lookup service names(only for Dubbo-OPS)
* The separator for service name
*/
private static final long LOOKUP_INTERVAL = Long.getLong("dubbo.service.names.lookup.interval", 30);
private static final String SERVICE_NAME_SEPARATOR = ":";
private final ApplicationContext applicationContext;
private final ServiceRegistry<Registration> serviceRegistry;
public SpringCloudRegistry(URL url, ServiceRegistry<Registration> serviceRegistry,
DiscoveryClient discoveryClient) {
private final DiscoveryClient discoveryClient;
private final RegistrationFactory registrationFactory;
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();
}
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 (registrationClass.equals(actualRegistrationClass)) {
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;
try {
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;
}
} catch (Throwable e) {
resolvableType = ResolvableType.forType(void.class);
}
return resolvableType.resolveGeneric(index);
}
@Override
protected void doRegister(URL url) {
final String serviceName = getServiceName(url);
@ -128,6 +222,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 +235,10 @@ public class SpringCloudRegistry extends FailbackRegistry {
if (isAdminProtocol(url)) {
shutdownServiceNamesLookup();
}
// if (registeredServicesLookupScheduler != null) {
// registeredServicesLookupScheduler.shutdown();
// }
}
@Override
@ -143,25 +247,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 +340,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 +376,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 +388,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 +411,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 +419,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,92 @@
/*
* 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.hashicorp.consul;
import com.alibaba.dubbo.common.URL;
import com.ecwid.consul.v1.agent.model.NewService;
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.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.cloud.consul.discovery.ConsulServerUtils;
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
import org.springframework.context.ApplicationContext;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* {@link ConsulRegistration} {@link RegistrationFactory} implementation
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class ConsulRegistrationFactory extends AbstractRegistrationFactory<ConsulRegistration> {
@Override
public ConsulRegistration create(String serviceName, URL url, ApplicationContext applicationContext) {
ServiceInstance serviceInstance = createServiceInstance(serviceName, url);
Map<String, String> metadata = getMetadata(serviceInstance);
List<String> tags = createTags(metadata);
NewService service = new NewService();
service.setId(serviceInstance.getInstanceId());
service.setName(serviceInstance.getServiceId());
service.setAddress(serviceInstance.getHost());
service.setPort(serviceInstance.getPort());
service.setMeta(metadata);
service.setTags(tags);
ConsulDiscoveryProperties properties = applicationContext.getBean(ConsulDiscoveryProperties.class);
ConsulRegistration registration = new ConsulRegistration(service, properties);
return registration;
}
/**
* @param metadata
* @return
* @see ConsulServerUtils#getMetadata(java.util.List)
*/
private List<String> createTags(Map<String, String> metadata) {
List<String> tags = new LinkedList<>();
for (Map.Entry<String, String> entry : metadata.entrySet()) {
String tag = entry.getKey() + "=" + entry.getValue();
tags.add(tag);
}
return tags;
}
private Map<String, String> getMetadata(ServiceInstance serviceInstance) {
Map<String, String> metadata = serviceInstance.getMetadata();
Set<String> removedKeys = new LinkedHashSet<>();
for (String key : metadata.keySet()) {
if (key.contains(".")) {
removedKeys.add(key);
}
}
for (String removedKey : removedKeys) {
metadata.remove(removedKey);
}
return metadata;
}
}

@ -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();
}
}

@ -7,3 +7,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.context.ApplicationContextInitializer=\
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,\
org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul.ConsulRegistrationFactory

@ -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

@ -1,4 +1,4 @@
spring.application.name=sca-nacos-config
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.shared-data-ids=base-common.properties,common.properties
spring.cloud.nacos.config.refreshable-dataids=common.properties

@ -38,6 +38,7 @@
<module>sms-example</module>
<module>spring-cloud-bus-rocketmq-example</module>
<module>schedulerx-example/schedulerx-simple-task-example</module>
<module>spring-cloud-alibaba-dubbo-examples</module>
</modules>
<build>

@ -0,0 +1,182 @@
<?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-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<name>Spring Cloud Alibaba Dubbo Examples</name>
<packaging>pom</packaging>
<modules>
<module>spring-cloud-dubbo-sample-api</module>
<module>spring-cloud-dubbo-provider-sample</module>
<module>spring-cloud-dubbo-consumer-sample</module>
</modules>
<properties>
<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>
<spring-cloud-consul.version>2.1.0.RELEASE</spring-cloud-consul.version>
<curator.version>4.0.1</curator.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Apache Dubbo dependencies-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</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>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<profiles>
<!-- Nacos -->
<profile>
<id>nacos</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<!-- Nacos Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>eureka</id>
<dependencies>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</profile>
<!-- Zookeeper -->
<profile>
<id>zookeeper</id>
<dependencies>
<!-- Zookeeper Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<version>${spring-cloud-zookeeper.version}</version>
<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>
</dependency>
</dependencies>
</profile>
<profile>
<id>consul</id>
<dependencies>
<!-- Spring Cloud Consul -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

@ -0,0 +1,38 @@
<?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-dubbo-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-consumer-sample</artifactId>
<name>Spring Cloud Dubbo Consumer Sample</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sample API -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Cloud Open Feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>

@ -19,6 +19,7 @@ package org.springframework.cloud.alibaba.dubbo.bootstrap;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
@ -37,24 +38,20 @@ 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
* Dubbo Spring Cloud Consumer Bootstrap
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableFeignClients
@RestController
public class DubboSpringCloudBootstrap {
public class DubboSpringCloudConsumerBootstrap {
@Reference(version = "1.0.0")
private RestService restService;
@ -67,11 +64,14 @@ public class DubboSpringCloudBootstrap {
@Lazy
private DubboFeignRestService dubboFeignRestService;
@Value("${provider.application.name}")
private String providerApplicationName;
@Autowired
@LoadBalanced
private RestTemplate restTemplate;
@FeignClient("spring-cloud-alibaba-dubbo")
@FeignClient("${provider.application.name}")
public interface FeignRestService {
@GetMapping(value = "/param")
@ -84,8 +84,6 @@ public class DubboSpringCloudBootstrap {
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);
@ -96,7 +94,7 @@ public class DubboSpringCloudBootstrap {
@RequestParam("v") String param);
}
@FeignClient("spring-cloud-alibaba-dubbo")
@FeignClient("${provider.application.name}")
@DubboTransported
public interface DubboFeignRestService {
@ -110,8 +108,6 @@ public class DubboSpringCloudBootstrap {
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);
@ -122,7 +118,6 @@ public class DubboSpringCloudBootstrap {
@PathVariable("p1") String path1);
}
@Bean
public ApplicationRunner paramRunner() {
return arguments -> {
@ -154,7 +149,7 @@ public class DubboSpringCloudBootstrap {
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"));
System.out.println(restTemplate.getForEntity("http://" + providerApplicationName + "//path-variables/{p1}/{p2}?v=c", String.class, "a", "b"));
}
private void callHeaders() {
@ -184,7 +179,7 @@ public class DubboSpringCloudBootstrap {
System.out.println(feignRestService.params("1", 1));
// RestTemplate call
System.out.println(restTemplate.getForEntity("http://spring-cloud-alibaba-dubbo/param?param=小马哥", String.class));
System.out.println(restTemplate.getForEntity("http://" + providerApplicationName + "/param?param=小马哥", String.class));
}
private void callRequestBodyMap() {
@ -202,7 +197,7 @@ public class DubboSpringCloudBootstrap {
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));
System.out.println(restTemplate.postForObject("http://" + providerApplicationName + "/request/body/map?param=小马哥", data, User.class));
}
@Bean
@ -213,7 +208,8 @@ public class DubboSpringCloudBootstrap {
}
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
new SpringApplicationBuilder(DubboSpringCloudConsumerBootstrap.class)
.profiles("nacos")
.run(args);
}
}

@ -0,0 +1,74 @@
spring:
application:
name: spring-cloud-alibaba-dubbo-consumer
main:
allow-bean-definition-overriding: true
# default disable all
cloud:
nacos:
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: false
consul:
enabled: false
eureka:
client:
enabled: false
ribbon:
nacos:
enabled: false
provider:
application:
name: spring-cloud-alibaba-dubbo-provider
---
spring:
profiles: nacos
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: 127.0.0.1:8848
ribbon:
nacos:
enabled: true
---
spring:
profiles: eureka
eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:9090/eureka/
---
spring:
profiles: zookeeper
cloud:
zookeeper:
enabled: true
connect-string: 127.0.0.1:2181
---
spring:
profiles: consul
cloud:
consul:
enabled: true
host: 127.0.0.1
port: 8500

@ -0,0 +1,65 @@
<?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-dubbo-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-provider-sample</artifactId>
<name>Spring Cloud Dubbo Provider Sample</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sample API -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</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>
</dependencies>
</project>

@ -0,0 +1,38 @@
/*
* 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)
.profiles("nacos")
.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());

@ -0,0 +1,20 @@
dubbo:
scan:
base-packages: org.springframework.cloud.alibaba.dubbo.service
protocols:
dubbo:
name: dubbo
port: 12345
rest:
name: rest
port: 8081
server: netty
registry:
address: spring-cloud://nacos
feign:
hystrix:
enabled: true
server:
port: 8080

@ -0,0 +1,63 @@
spring:
application:
name: spring-cloud-alibaba-dubbo-provider
main:
allow-bean-definition-overriding: true
# default disable all
cloud:
nacos:
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: false
consul:
enabled: false
eureka:
client:
enabled: false
---
spring:
profiles: nacos
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: 127.0.0.1:8848
---
spring:
profiles: eureka
eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:9090/eureka/
---
spring:
profiles: zookeeper
cloud:
zookeeper:
enabled: true
connect-string: 127.0.0.1:2181
---
spring:
profiles: consul
cloud:
consul:
enabled: true
host: 127.0.0.1
port: 8500

@ -0,0 +1,16 @@
<?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-dubbo-examples</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.2.2.BUILD-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<name>Spring Cloud Dubbo Sample API</name>
</project>

@ -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() {

@ -1,43 +0,0 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.nacos;
import org.junit.Test;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpoint;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author pbting
* @date 2019-01-17 2:25 PM
*/
public class EndpointTests extends NacosPowerMockitBaseTests {
@Test
public void nacosConfigEndpoint() {
NacosConfigEndpoint nacosConfigEndpoint = super.context
.getBean(NacosConfigEndpoint.class);
assertThat(nacosConfigEndpoint != null).isEqualTo(true);
}
@Test
public void endpointInvoke() {
NacosConfigEndpoint nacosConfigEndpoint = this.context
.getBean(NacosConfigEndpoint.class);
assertThat(nacosConfigEndpoint.invoke() != null).isEqualTo(true);
}
}

@ -1,76 +0,0 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.nacos;
import org.junit.Test;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator;
import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author xiaojing
* @author pbting
*/
public class NacosConfigAutoConfigurationTests extends NacosPowerMockitBaseTests {
@Test
public void testNacosConfigProperties() {
NacosConfigProperties nacosConfigProperties = context.getParent()
.getBean(NacosConfigProperties.class);
assertThat(nacosConfigProperties.getFileExtension()).isEqualTo("properties");
assertThat(nacosConfigProperties.getPrefix() == null).isEqualTo(true);
assertThat(nacosConfigProperties.getNamespace() == null).isEqualTo(true);
assertThat(nacosConfigProperties.getName()).isEqualTo("sca-nacos-config");
assertThat(nacosConfigProperties.getServerAddr()).isEqualTo("127.0.0.1:8848");
assertThat(nacosConfigProperties.getEncode()).isEqualTo("utf-8");
assertThat(nacosConfigProperties.getActiveProfiles())
.isEqualTo(new String[] { "develop" });
assertThat(nacosConfigProperties.getSharedDataids())
.isEqualTo("base-common.properties,common.properties");
assertThat(nacosConfigProperties.getRefreshableDataids())
.isEqualTo("common.properties");
assertThat(nacosConfigProperties.getExtConfig().size()).isEqualTo(3);
assertThat(nacosConfigProperties.getExtConfig().get(0).getDataId())
.isEqualTo("ext00.yaml");
assertThat(nacosConfigProperties.getExtConfig().get(1).getGroup())
.isEqualTo("EXT01_GROUP");
assertThat(nacosConfigProperties.getExtConfig().get(1).isRefresh())
.isEqualTo(true);
}
@Test
public void nacosPropertySourceLocator() {
NacosPropertySourceLocator nacosPropertySourceLocator = this.context
.getBean(NacosPropertySourceLocator.class);
PropertySource propertySource = nacosPropertySourceLocator
.locate(this.context.getEnvironment());
assertThat(propertySource instanceof CompositePropertySource).isEqualTo(true);
}
@Test
public void testNacosRefreshProperties() {
NacosRefreshProperties nacosRefreshProperties = this.context
.getBean(NacosRefreshProperties.class);
assertThat(nacosRefreshProperties.isEnabled()).isEqualTo(true);
}
}

@ -1,67 +0,0 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.nacos;
import org.junit.Test;
import org.springframework.boot.actuate.health.Health;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigHealthIndicator;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author pbting
* @date 2019-01-17 2:58 PM
*/
public class NacosConfigHealthIndicatorTests extends NacosPowerMockitBaseTests {
@Test
public void nacosConfigHealthIndicatorInstance() {
NacosConfigHealthIndicator nacosConfigHealthIndicator = this.context
.getBean(NacosConfigHealthIndicator.class);
assertThat(nacosConfigHealthIndicator != null).isEqualTo(true);
}
@Test
public void testHealthCheck() {
NacosConfigHealthIndicator nacosConfigHealthIndicator = this.context
.getBean(NacosConfigHealthIndicator.class);
Health.Builder builder = Health.up();
Method method = ReflectionUtils.findMethod(NacosConfigHealthIndicator.class,
"doHealthCheck", Health.Builder.class);
ReflectionUtils.makeAccessible(method);
assertThat(method != null).isEqualTo(true);
try {
method.invoke(nacosConfigHealthIndicator, builder);
assertThat(builder != null).isEqualTo(true);
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,157 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.nacos;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationExtConfigTests.TestConfig.class, properties = {
"spring.application.name=myTestService1", "spring.profiles.active=dev,test",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.encode=utf-8",
"spring.cloud.nacos.config.timeout=1000",
"spring.cloud.nacos.config.file-extension=properties",
"spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties",
"spring.cloud.nacos.config.ext-config[1].data-id=ext-config-common02.properties",
"spring.cloud.nacos.config.ext-config[1].group=GLOBAL_GROUP",
"spring.cloud.nacos.config.shared-dataids=common1.properties,common2.properties",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey" }, webEnvironment = NONE)
public class NacosConfigurationExtConfigTests {
static {
try {
// when(any(ConfigService.class).getConfig(eq("test-name.properties"),
// eq("test-group"), any())).thenReturn("user.name=hello");
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common2=common2";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@Autowired
private NacosPropertySourceLocator locator;
@Autowired
private NacosConfigProperties properties;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosPropertySourceLocator was not created", locator);
assertNotNull("NacosConfigProperties was not created", properties);
Assert.assertEquals(environment.getProperty("test-ext-config1"), "config1");
Assert.assertEquals(environment.getProperty("test-ext-config2"), "config2");
Assert.assertEquals(environment.getProperty("test-common1"), "common1");
Assert.assertEquals(environment.getProperty("test-common2"), "common2");
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ NacosConfigEndpointAutoConfiguration.class,
NacosConfigAutoConfiguration.class, NacosConfigBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -0,0 +1,268 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.nacos;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpoint;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationTests.TestConfig.class, properties = {
"spring.application.name=myTestService1", "spring.profiles.active=dev,test",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.endpoint=test-endpoint",
"spring.cloud.nacos.config.namespace=test-namespace",
"spring.cloud.nacos.config.encode=utf-8",
"spring.cloud.nacos.config.timeout=1000",
"spring.cloud.nacos.config.group=test-group",
"spring.cloud.nacos.config.name=test-name",
"spring.cloud.nacos.config.cluster-name=test-cluster",
"spring.cloud.nacos.config.file-extension=properties",
"spring.cloud.nacos.config.contextPath=test-contextpath",
"spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties",
"spring.cloud.nacos.config.ext-config[1].data-id=ext-config-common02.properties",
"spring.cloud.nacos.config.ext-config[1].group=GLOBAL_GROUP",
"spring.cloud.nacos.config.shared-dataids=common1.properties,common2.properties",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey" }, webEnvironment = NONE)
public class NacosConfigurationTests {
static {
try {
// when(any(ConfigService.class).getConfig(eq("test-name.properties"),
// eq("test-group"), any())).thenReturn("user.name=hello");
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common2=common2";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@Autowired
private NacosPropertySourceLocator locator;
@Autowired
private NacosConfigProperties properties;
@Autowired
private NacosRefreshHistory refreshHistory;
@Test
public void contextLoads() throws Exception {
assertNotNull("NacosPropertySourceLocator was not created", locator);
assertNotNull("NacosConfigProperties was not created", properties);
checkoutNacosConfigServerAddr();
checkoutNacosConfigEndpoint();
checkoutNacosConfigNamespace();
checkoutNacosConfigClusterName();
checkoutNacosConfigAccessKey();
checkoutNacosConfigSecrectKey();
checkoutNacosConfigName();
checkoutNacosConfigGroup();
checkoutNacosConfigContextPath();
checkoutNacosConfigFileExtension();
checkoutNacosConfigTimeout();
checkoutNacosConfigEncode();
checkoutNacosConfigProfiles();
checkoutNacosConfigExtConfig();
checkoutEndpoint();
Assert.assertEquals(environment.getProperty("user.name"), "dev");
Assert.assertEquals(environment.getProperty("user.age"), "12");
}
private void checkoutNacosConfigServerAddr() {
assertEquals("NacosConfigProperties server address is wrong", "127.0.0.1:8848",
properties.getServerAddr());
}
private void checkoutNacosConfigEndpoint() {
assertEquals("NacosConfigProperties endpoint is wrong", "test-endpoint",
properties.getEndpoint());
}
private void checkoutNacosConfigNamespace() {
assertEquals("NacosConfigProperties namespace is wrong", "test-namespace",
properties.getNamespace());
}
private void checkoutNacosConfigClusterName() {
assertEquals("NacosConfigProperties' cluster is wrong", "test-cluster",
properties.getClusterName());
}
private void checkoutNacosConfigAccessKey() {
assertEquals("NacosConfigProperties' is access key is wrong", "test-accessKey",
properties.getAccessKey());
}
private void checkoutNacosConfigSecrectKey() {
assertEquals("NacosConfigProperties' is secret key is wrong", "test-secretKey",
properties.getSecretKey());
}
private void checkoutNacosConfigContextPath() {
assertEquals("NacosConfigProperties' context path is wrong", "test-contextpath",
properties.getContextPath());
}
private void checkoutNacosConfigName() {
assertEquals("NacosConfigProperties' name is wrong", "test-name",
properties.getName());
}
private void checkoutNacosConfigGroup() {
assertEquals("NacosConfigProperties' group is wrong", "test-group",
properties.getGroup());
}
private void checkoutNacosConfigFileExtension() {
assertEquals("NacosConfigProperties' file extension is wrong", "properties",
properties.getFileExtension());
}
private void checkoutNacosConfigTimeout() {
assertEquals("NacosConfigProperties' timeout is wrong", 1000,
properties.getTimeout());
}
private void checkoutNacosConfigEncode() {
assertEquals("NacosConfigProperties' encode is wrong", "utf-8",
properties.getEncode());
}
private void checkoutNacosConfigExtConfig() {
assertEquals("NacosConfigProperties' ext config is wrong",
"ext-config-common01.properties",
properties.getExtConfig().get(0).getDataId());
assertEquals("NacosConfigProperties' ext config is wrong",
"ext-config-common02.properties",
properties.getExtConfig().get(1).getDataId());
assertEquals("NacosConfigProperties' ext config is wrong", "GLOBAL_GROUP",
properties.getExtConfig().get(1).getGroup());
}
private void checkoutNacosConfigProfiles() {
assertEquals("NacosConfigProperties' profiles is wrong",
new String[] { "dev", "test" }, properties.getActiveProfiles());
}
private void checkoutEndpoint() throws Exception {
NacosConfigEndpoint nacosConfigEndpoint = new NacosConfigEndpoint(properties,
refreshHistory);
Map<String, Object> map = nacosConfigEndpoint.invoke();
assertEquals(map.get("NacosConfigProperties"), properties);
assertEquals(map.get("RefreshHistory"), refreshHistory.getRecords());
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ NacosConfigEndpointAutoConfiguration.class,
NacosConfigAutoConfiguration.class, NacosConfigBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -0,0 +1,98 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.nacos;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosFileExtensionTest.TestConfig.class, properties = {
"spring.application.name=test-name",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.file-extension=yaml" }, webEnvironment = NONE)
public class NacosFileExtensionTest {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.yaml".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user:\n name: hello\n age: 12";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@Test
public void contextLoads() throws Exception {
Assert.assertEquals(environment.getProperty("user.name"), "hello");
Assert.assertEquals(environment.getProperty("user.age"), "12");
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ NacosConfigEndpointAutoConfiguration.class,
NacosConfigAutoConfiguration.class, NacosConfigBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -1,177 +0,0 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.nacos;
import com.alibaba.nacos.api.config.ConfigService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceBuilder;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ReflectionUtils;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* @author pbting
* @date 2019-01-17 8:54 PM
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({ "javax.management.*", "javax.net.ssl.*" })
@PrepareForTest({ NacosPropertySourceBuilder.class })
@SpringBootTest(classes = { NacosConfigBootstrapConfiguration.class,
NacosConfigEndpointAutoConfiguration.class, NacosConfigAutoConfiguration.class,
NacosPowerMockitBaseTests.TestConfiguration.class }, properties = {
"spring.application.name=sca-nacos-config",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.name=sca-nacos-config",
// "spring.cloud.nacos.config.refresh.enabled=false",
"spring.cloud.nacos.config.encode=utf-8",
"spring.cloud.nacos.config.shared-data-ids=base-common.properties,common.properties",
"spring.cloud.nacos.config.refreshable-dataids=common.properties",
"spring.cloud.nacos.config.ext-config[0].data-id=ext00.yaml",
"spring.cloud.nacos.config.ext-config[1].data-id=ext01.yml",
"spring.cloud.nacos.config.ext-config[1].group=EXT01_GROUP",
"spring.cloud.nacos.config.ext-config[1].refresh=true",
"spring.cloud.nacos.config.ext-config[2].data-id=ext02.yaml",
"spring.profiles.active=develop", "server.port=19090" })
public class NacosPowerMockitBaseTests {
private final static List<String> DATAIDS = Arrays.asList("common.properties",
"base-common.properties", "ext00.yaml", "ext01.yml", "ext02.yaml",
"sca-nacos-config.properties", "sca-nacos-config-develop.properties");
private final static HashMap<String, Properties> VALUES = new HashMap<>();
@Autowired
protected ApplicationContext context;
static {
initDataIds();
try {
final Constructor constructor = ReflectionUtils.accessibleConstructor(
NacosPropertySource.class, String.class, String.class, Map.class,
Date.class, boolean.class);
Method method = PowerMockito.method(NacosPropertySourceBuilder.class, "build",
String.class, String.class, String.class, boolean.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Properties properties = VALUES.get(args[0].toString());
if (properties == null) {
properties = new Properties();
properties.put("user.name", args[0].toString());
}
Object instance = constructor.newInstance(args[1].toString(),
args[0].toString(), properties, new Date(), args[3]);
return instance;
}
});
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private static void initDataIds() {
DATAIDS.forEach(dataId -> {
String realpath = "/" + dataId;
ClassPathResource classPathResource = new ClassPathResource(realpath);
if (realpath.endsWith("properties")) {
Properties properties = new Properties();
try {
properties.load(classPathResource.getInputStream());
VALUES.put(dataId, properties);
}
catch (IOException e) {
e.printStackTrace();
}
}
if (realpath.endsWith("yaml") || realpath.endsWith("yml")) {
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
yamlFactory.setResources(classPathResource);
try {
VALUES.put(dataId, yamlFactory.getObject());
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
public NacosPropertySourceBuilder nacosPropertySourceBuilderInstance() {
NacosConfigProperties nacosConfigProperties = this.context
.getBean(NacosConfigProperties.class);
ConfigService configService = nacosConfigProperties.configServiceInstance();
long timeout = nacosConfigProperties.getTimeout();
NacosPropertySourceBuilder nacosPropertySourceBuilder = new NacosPropertySourceBuilder(
configService, timeout);
return nacosPropertySourceBuilder;
}
@Configuration
@AutoConfigureBefore(NacosConfigAutoConfiguration.class)
static class TestConfiguration {
@Autowired
ConfigurableApplicationContext context;
@Bean
ContextRefresher contextRefresher() {
RefreshScope refreshScope = new RefreshScope();
refreshScope.setApplicationContext(context);
return new ContextRefresher(context, refreshScope);
}
}
@Test
public void testAppContext() {
System.err.println(this.context);
}
}

@ -1,190 +0,0 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.nacos;
import org.junit.Test;
import org.powermock.api.support.MethodProxy;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceBuilder;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author pbting
* @date 2019-01-17 11:49 AM
*/
public class NacosPropertySourceBuilderTests extends NacosPowerMockitBaseTests {
@Test
public void nacosPropertySourceBuilder() {
assertThat(nacosPropertySourceBuilderInstance() != null).isEqualTo(true);
}
@Test
public void getConfigByProperties() {
try {
final HashMap<String, String> value = new HashMap<>();
value.put("dev.mode", "local-mock");
final Constructor constructor = ReflectionUtils.accessibleConstructor(
NacosPropertySource.class, String.class, String.class, Map.class,
Date.class, boolean.class);
NacosPropertySourceBuilder nacosPropertySourceBuilder = nacosPropertySourceBuilderInstance();
Method method = ReflectionUtils.findMethod(NacosPropertySourceBuilder.class,
"build", String.class, String.class, String.class, boolean.class);
ReflectionUtils.makeAccessible(method);
assertThat(method != null).isEqualTo(true);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object instance = constructor.newInstance(args[1].toString(),
args[0].toString(), value, new Date(), args[3]);
return instance;
}
});
Object result = method.invoke(nacosPropertySourceBuilder,
"mock-nacos-config.properties", "DEFAULT_GROUP", "properties", true);
assertThat(result != null).isEqualTo(true);
assertThat(result instanceof NacosPropertySource).isEqualTo(true);
NacosPropertySource nacosPropertySource = (NacosPropertySource) result;
assertThat(nacosPropertySource.getProperty("dev.mode"))
.isEqualTo("local-mock");
}
catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void getConfigByYaml() {
try {
//
final HashMap<String, String> value = new HashMap<>();
value.put("mock-ext-config", "mock-ext-config-value");
final Constructor constructor = ReflectionUtils.accessibleConstructor(
NacosPropertySource.class, String.class, String.class, Map.class,
Date.class, boolean.class);
Method method = ReflectionUtils.findMethod(NacosPropertySourceBuilder.class,
"build", String.class, String.class, String.class, boolean.class);
ReflectionUtils.makeAccessible(method);
assertThat(method != null).isEqualTo(true);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object instance = constructor.newInstance(args[1].toString(),
args[0].toString(), value, new Date(), args[3]);
return instance;
}
});
NacosPropertySourceBuilder nacosPropertySourceBuilder = nacosPropertySourceBuilderInstance();
Object result = method.invoke(nacosPropertySourceBuilder, "ext-config.yaml",
"DEFAULT_GROUP", "yaml", true);
assertThat(result != null).isEqualTo(true);
assertThat(result instanceof NacosPropertySource).isEqualTo(true);
NacosPropertySource nacosPropertySource = (NacosPropertySource) result;
assertThat(nacosPropertySource.getProperty("mock-ext-config"))
.isEqualTo("mock-ext-config-value");
}
catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void getConfigByYml() {
try {
//
final HashMap<String, String> value = new HashMap<>();
value.put("mock-ext-config-yml", "mock-ext-config-yml-value");
final Constructor constructor = ReflectionUtils.accessibleConstructor(
NacosPropertySource.class, String.class, String.class, Map.class,
Date.class, boolean.class);
Method method = ReflectionUtils.findMethod(NacosPropertySourceBuilder.class,
"build", String.class, String.class, String.class, boolean.class);
ReflectionUtils.makeAccessible(method);
assertThat(method != null).isEqualTo(true);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object instance = constructor.newInstance(args[1].toString(),
args[0].toString(), value, new Date(), args[3]);
return instance;
}
});
NacosPropertySourceBuilder nacosPropertySourceBuilder = nacosPropertySourceBuilderInstance();
Object result = method.invoke(nacosPropertySourceBuilder, "ext-config.yml",
"DEFAULT_GROUP", "yml", true);
assertThat(result != null).isEqualTo(true);
assertThat(result instanceof NacosPropertySource).isEqualTo(true);
NacosPropertySource nacosPropertySource = (NacosPropertySource) result;
assertThat(nacosPropertySource.getProperty("mock-ext-config-yml"))
.isEqualTo("mock-ext-config-yml-value");
}
catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void getEmpty() {
NacosPropertySourceBuilder nacosPropertySourceBuilder = nacosPropertySourceBuilderInstance();
Method method = ReflectionUtils.findMethod(NacosPropertySourceBuilder.class,
"build", String.class, String.class, String.class, boolean.class);
ReflectionUtils.makeAccessible(method);
assertThat(method != null).isEqualTo(true);
try {
Object result = method.invoke(nacosPropertySourceBuilder, "nacos-empty.yml",
"DEFAULT_GROUP", "yml", true);
assertThat(result != null).isEqualTo(true);
assertThat(result instanceof NacosPropertySource).isEqualTo(true);
NacosPropertySource nacosPropertySource = (NacosPropertySource) result;
assertThat(nacosPropertySource.getProperty("address")).isEqualTo(null);
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

@ -1,91 +0,0 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.nacos;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author pbting
* @date 2019-01-17 11:46 AM
*/
public class NacosSharedAndExtConfigTests extends NacosPowerMockitBaseTests {
private final static Logger log = LoggerFactory
.getLogger(NacosSharedAndExtConfigTests.class);
@Test
public void testSharedConfigPriority() {
String userName = this.context.getEnvironment().getProperty("user.address");
assertThat(userName).isEqualTo("zhejiang-ningbo");
}
@Test
public void testSharedConfigRefresh() {
while (true) {
// ContextRefresher contextRefresher = this.context
// .getBean(ContextRefresher.class);
// contextRefresher.refresh();
String userName = this.context.getEnvironment().getProperty("user.address");
try {
assertThat(userName).isEqualTo("zhejiang-ningbo");
TimeUnit.SECONDS.sleep(1);
log.info("user name is {}", userName);
}
catch (InterruptedException e) {
e.printStackTrace();
}
// 真实测试时将这里 注释掉
break;
}
}
@Test
public void testExtConfigPriority() {
String extKey = this.context.getEnvironment().getProperty("ext.key");
assertThat(extKey).isEqualTo("ext.value02");
}
@Test
public void testExtOtherGroup() {
String userExt = this.context.getEnvironment().getProperty("user.ext");
assertThat(userExt).isEqualTo("EXT01_GROUP-value");
}
@Test
public void testExtRefresh() {
while (true) {
// ContextRefresher contextRefresher = this.context
// .getBean(ContextRefresher.class);
// contextRefresher.refresh();
String userExt = this.context.getEnvironment().getProperty("user.ext");
try {
assertThat(userExt).isEqualTo("EXT01_GROUP-value");
TimeUnit.SECONDS.sleep(1);
log.info("user name is {}", userExt);
}
catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
}

@ -0,0 +1,141 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.nacos.endpoint;
import static org.junit.Assert.assertEquals;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alibaba.nacos.NacosConfigAutoConfiguration;
import org.springframework.cloud.alibaba.nacos.NacosConfigBootstrapConfiguration;
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigEndpointTests.TestConfig.class, properties = {
"spring.application.name=test-name",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.file-extension=properties" }, webEnvironment = NONE)
public class NacosConfigEndpointTests {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private NacosConfigProperties properties;
@Autowired
private NacosRefreshHistory refreshHistory;
@Test
public void contextLoads() throws Exception {
checkoutEndpoint();
checkoutAcmHealthIndicator();
}
private void checkoutAcmHealthIndicator() {
try {
Builder builder = new Builder();
NacosConfigHealthIndicator healthIndicator = new NacosConfigHealthIndicator(
properties, properties.configServiceInstance());
healthIndicator.doHealthCheck(builder);
Builder builder1 = new Builder();
List<String> dataIds = new ArrayList<>();
dataIds.add("test-name.properties");
builder1.up().withDetail("dataIds", dataIds);
Assert.assertTrue(builder.build().equals(builder1.build()));
}
catch (Exception ignoreE) {
}
}
private void checkoutEndpoint() throws Exception {
NacosConfigEndpoint endpoint = new NacosConfigEndpoint(properties,
refreshHistory);
Map<String, Object> map = endpoint.invoke();
assertEquals(map.get("NacosConfigProperties"), properties);
assertEquals(map.get("RefreshHistory"), refreshHistory.getRecords());
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ NacosConfigEndpointAutoConfiguration.class,
NacosConfigAutoConfiguration.class, NacosConfigBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -1,2 +0,0 @@
user.name=base-common-value
user.address=zhejiang-hangzhou

@ -1,2 +0,0 @@
user.name=common-value
user.address=zhejiang-ningbo

@ -1,4 +0,0 @@
user:
name: ext-00-value
ext:
key: ext.value00

@ -1,5 +0,0 @@
user:
name: ext-01-value
ext: EXT01_GROUP-value
ext:
key: ext.value01

@ -1,5 +0,0 @@
user:
name: ext-02-value
ext:
key: ext.value02
app-local-common: update app local shared cguration for Nacos

@ -28,6 +28,7 @@ import org.springframework.cloud.alibaba.nacos.discovery.NacosDiscoveryClientAut
import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration;
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
@ -43,7 +44,8 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureBefore(NacosDiscoveryClientAutoConfiguration.class)
@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class })
public class NacosDiscoveryAutoConfiguration {
@Bean

@ -57,7 +57,7 @@ import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
@ConfigurationProperties("spring.cloud.nacos.discovery")
public class NacosDiscoveryProperties {
private static final Logger LOGGER = LoggerFactory
private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryProperties.class);
/**
@ -413,7 +413,7 @@ public class NacosDiscoveryProperties {
namingService = NacosFactory.createNamingService(properties);
}
catch (Exception e) {
LOGGER.error("create naming service error!properties={},e=,", this, e);
log.error("create naming service error!properties={},e=,", this, e);
return null;
}
return namingService;

@ -33,7 +33,7 @@ import java.util.*;
*/
public class NacosDiscoveryClient implements DiscoveryClient {
private static final Logger LOGGER = LoggerFactory
private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryClient.class);
public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";
@ -100,7 +100,7 @@ public class NacosDiscoveryClient implements DiscoveryClient {
return services.getData();
}
catch (Exception e) {
LOGGER.error("get service name from nacos server fail,", e);
log.error("get service name from nacos server fail,", e);
return Collections.emptyList();
}
}

@ -37,7 +37,7 @@ import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
@Endpoint(id = "nacos-discovery")
public class NacosDiscoveryEndpoint {
private static final Logger LOGGER = LoggerFactory
private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryEndpoint.class);
private NacosDiscoveryProperties nacosDiscoveryProperties;
@ -61,7 +61,7 @@ public class NacosDiscoveryEndpoint {
subscribe = namingService.getSubscribeServices();
}
catch (Exception e) {
LOGGER.error("get subscribe services from nacos fail,", e);
log.error("get subscribe services from nacos fail,", e);
}
result.put("subscribe", subscribe);
return result;

@ -31,7 +31,7 @@ import org.springframework.util.StringUtils;
*/
public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<Registration> {
private static final Logger LOGGER = LoggerFactory
private static final Logger log = LoggerFactory
.getLogger(NacosAutoServiceRegistration.class);
private NacosRegistration registration;
@ -65,7 +65,7 @@ public class NacosAutoServiceRegistration
@Override
protected void register() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
LOGGER.debug("Registration disabled.");
log.debug("Registration disabled.");
return;
}
if (this.registration.getPort() < 0) {

@ -32,7 +32,7 @@ import org.springframework.util.StringUtils;
*/
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);
private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);
private final NacosDiscoveryProperties nacosDiscoveryProperties;
@ -47,7 +47,7 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No service to register for nacos client...");
log.warn("No service to register for nacos client...");
return;
}
@ -62,11 +62,11 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
try {
namingService.registerInstance(serviceId, instance);
logger.info("nacos registry, {} {}:{} register finished", serviceId,
log.info("nacos registry, {} {}:{} register finished", serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
logger.error("nacos registry, {} register failed...{},", serviceId,
log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
}
}
@ -74,10 +74,10 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
@Override
public void deregister(Registration registration) {
logger.info("De-registering from Nacos Server now...");
log.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No dom to de-register for nacos client...");
log.warn("No dom to de-register for nacos client...");
return;
}
@ -89,11 +89,11 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
registration.getPort(), nacosDiscoveryProperties.getClusterName());
}
catch (Exception e) {
logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
log.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
logger.info("De-registration finished.");
log.info("De-registration finished.");
}
@Override

@ -67,6 +67,20 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

@ -42,6 +42,8 @@ public class AcmPropertySourceLocator implements PropertySourceLocator {
CompositePropertySource compositePropertySource = new CompositePropertySource(
DIAMOND_PROPERTY_SOURCE_NAME);
acmIntegrationProperties.setActiveProfiles(environment.getActiveProfiles());
for (String dataId : acmIntegrationProperties.getGroupConfigurationDataIds()) {
loadDiamondDataIfPresent(compositePropertySource, dataId,
acmIntegrationProperties.getAcmProperties().getGroup(), true);

@ -1,40 +0,0 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.alicloud.acm.diagnostics.analyzer;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
/**
* A {@code FailureAnalyzer} that performs analysis of failures caused by a
* {@code DiamondConnectionFailureException}.
*
* @author juven.xuxb, 07/11/2016.
*/
public class DiamondConnectionFailureAnalyzer
extends AbstractFailureAnalyzer<DiamondConnectionFailureException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure,
DiamondConnectionFailureException cause) {
return new FailureAnalysis(
"Application failed to connect to Diamond, unable to access http://"
+ cause.getDomain() + ":" + cause.getPort()
+ "/diamond-server/diamond",
"config the right endpoint", cause);
}
}

@ -1,52 +0,0 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.alicloud.acm.diagnostics.analyzer;
/**
* A {@code DiamondConnectionFailureException} is thrown when the application fails to
* connect to Diamond Server.
*
* @author juven.xuxb, 07/11/2016.
*/
public class DiamondConnectionFailureException extends RuntimeException {
private final String domain;
private final String port;
public DiamondConnectionFailureException(String domain, String port, String message) {
super(message);
this.domain = domain;
this.port = port;
}
public DiamondConnectionFailureException(String domain, String port, String message,
Throwable cause) {
super(message, cause);
this.domain = domain;
this.port = port;
}
String getDomain() {
return domain;
}
String getPort() {
return port;
}
}

@ -4,6 +4,3 @@ org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySourceLocator
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alicloud.acm.AcmAutoConfiguration,\
org.springframework.cloud.alicloud.acm.endpoint.AcmEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.alicloud.acm.diagnostics.analyzer.DiamondConnectionFailureAnalyzer

@ -0,0 +1,195 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.alicloud.acm;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.alibaba.edas.acm.ConfigService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alicloud.acm.bootstrap.AcmPropertySourceLocator;
import org.springframework.cloud.alicloud.acm.endpoint.AcmEndpointAutoConfiguration;
import org.springframework.cloud.alicloud.context.acm.AcmContextBootstrapConfiguration;
import org.springframework.cloud.alicloud.context.acm.AcmIntegrationProperties;
import org.springframework.cloud.alicloud.context.acm.AcmProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ ConfigService.class })
@SpringBootTest(classes = AcmConfigurationTests.TestConfig.class, properties = {
"spring.application.name=test-name", "spring.profiles.active=dev,test",
"spring.cloud.alicloud.acm.server-list=127.0.0.1",
"spring.cloud.alicloud.acm.server-port=8848",
"spring.cloud.alicloud.acm.endpoint=test-endpoint",
"spring.cloud.alicloud.acm.namespace=test-namespace",
"spring.cloud.alicloud.acm.timeout=1000",
"spring.cloud.alicloud.acm.group=test-group",
"spring.cloud.alicloud.acm.refresh-enabled=false",
"spring.cloud.alicloud.acm.file-extension=properties" }, webEnvironment = NONE)
public class AcmConfigurationTests {
static {
try {
Method method = PowerMockito.method(ConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=dev";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@Autowired
private AcmPropertySourceLocator locator;
@Autowired
private AcmIntegrationProperties integrationProperties;
@Autowired
private AcmProperties properties;
@Test
public void contextLoads() throws Exception {
assertNotNull("AcmPropertySourceLocator was not created", locator);
assertNotNull("AcmProperties was not created", properties);
assertNotNull("AcmIntegrationProperties was not created", integrationProperties);
checkoutAcmServerAddr();
checkoutAcmServerPort();
checkoutAcmEndpoint();
checkoutAcmNamespace();
checkoutAcmGroup();
checkoutAcmFileExtension();
checkoutAcmTimeout();
checkoutAcmProfiles();
checkoutAcmRefreshEnabled();
checkoutDataLoad();
checkoutProfileDataLoad();
}
private void checkoutAcmServerAddr() {
assertEquals("AcmProperties server address is wrong", "127.0.0.1",
properties.getServerList());
}
private void checkoutAcmServerPort() {
assertEquals("AcmProperties server port is wrong", "8848",
properties.getServerPort());
}
private void checkoutAcmEndpoint() {
assertEquals("AcmProperties endpoint is wrong", "test-endpoint",
properties.getEndpoint());
}
private void checkoutAcmNamespace() {
assertEquals("AcmProperties namespace is wrong", "test-namespace",
properties.getNamespace());
}
private void checkoutAcmGroup() {
assertEquals("AcmProperties' group is wrong", "test-group",
properties.getGroup());
}
private void checkoutAcmFileExtension() {
assertEquals("AcmProperties' file extension is wrong", "properties",
properties.getFileExtension());
}
private void checkoutAcmTimeout() {
assertEquals("AcmProperties' timeout is wrong", 1000, properties.getTimeout());
}
private void checkoutAcmRefreshEnabled() {
assertEquals("AcmProperties' refresh enabled is wrong", false,
properties.isRefreshEnabled());
}
private void checkoutAcmProfiles() {
assertArrayEquals("AcmProperties' profiles is wrong",
new String[] { "dev", "test" },
integrationProperties.getActiveProfiles());
}
private void checkoutDataLoad() {
Assert.assertEquals(environment.getProperty("user.age"), "12");
}
private void checkoutProfileDataLoad() {
Assert.assertEquals(environment.getProperty("user.name"), "dev");
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AcmEndpointAutoConfiguration.class,
AcmAutoConfiguration.class, AcmContextBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -0,0 +1,98 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.alicloud.acm;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alicloud.acm.endpoint.AcmEndpointAutoConfiguration;
import org.springframework.cloud.alicloud.context.acm.AcmContextBootstrapConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.edas.acm.ConfigService;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ ConfigService.class })
@SpringBootTest(classes = AcmFileExtensionTest.TestConfig.class, properties = {
"spring.application.name=test-name",
"spring.cloud.alicloud.acm.server-list=127.0.0.1",
"spring.cloud.alicloud.acm.server-port=8080",
"spring.cloud.alicloud.acm.file-extension=yaml" }, webEnvironment = NONE)
public class AcmFileExtensionTest {
static {
try {
Method method = PowerMockito.method(ConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.yaml".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user:\n name: hello\n age: 12";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@Test
public void contextLoads() throws Exception {
Assert.assertEquals(environment.getProperty("user.name"), "hello");
Assert.assertEquals(environment.getProperty("user.age"), "12");
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AcmEndpointAutoConfiguration.class,
AcmAutoConfiguration.class, AcmContextBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -0,0 +1,106 @@
/*
* Copyright (C) 2019 the original author or authors.
*
* Licensed 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.alicloud.acm;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.alibaba.edas.acm.ConfigService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alicloud.acm.endpoint.AcmEndpointAutoConfiguration;
import org.springframework.cloud.alicloud.context.acm.AcmContextBootstrapConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ ConfigService.class })
@SpringBootTest(classes = AcmGroupConfigurationTest.TestConfig.class, properties = {
"spring.application.name=test-name", "spring.application.group=com.test.hello",
"spring.cloud.alicloud.acm.server-list=127.0.0.1",
"spring.cloud.alicloud.acm.server-port=8080",
"spring.cloud.alicloud.acm.timeout=1000",
"spring.cloud.alicloud.acm.group=test-group" }, webEnvironment = NONE)
public class AcmGroupConfigurationTest {
static {
try {
Method method = PowerMockito.method(ConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("com.test:application.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "com.test.value=com.test\ntest.priority=1";
}
if ("com.test.hello:application.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "com.test.hello.value=com.test.hello\ntest.priority=2";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@Test
public void contextLoads() throws Exception {
Assert.assertEquals(environment.getProperty("com.test.value"), "com.test");
Assert.assertEquals(environment.getProperty("test.priority"), "2");
Assert.assertEquals(environment.getProperty("com.test.hello.value"),
"com.test.hello");
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AcmEndpointAutoConfiguration.class,
AcmAutoConfiguration.class, AcmContextBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -0,0 +1,148 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed 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.alicloud.acm.endpoint;
import static org.junit.Assert.assertEquals;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alicloud.acm.AcmAutoConfiguration;
import org.springframework.cloud.alicloud.acm.AcmPropertySourceRepository;
import org.springframework.cloud.alicloud.acm.refresh.AcmRefreshHistory;
import org.springframework.cloud.alicloud.context.acm.AcmContextBootstrapConfiguration;
import org.springframework.cloud.alicloud.context.acm.AcmProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.edas.acm.ConfigService;
/**
* @author xiaojing
*/
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ ConfigService.class })
@SpringBootTest(classes = AcmEndpointTests.TestConfig.class, properties = {
"spring.application.name=test-name",
"spring.cloud.alicloud.acm.server-list=127.0.0.1",
"spring.cloud.alicloud.acm.server-port=8848",
"spring.cloud.alicloud.acm.file-extension=properties" }, webEnvironment = NONE)
public class AcmEndpointTests {
static {
try {
Method method = PowerMockito.method(ConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private AcmProperties properties;
@Autowired
private AcmRefreshHistory refreshHistory;
@Autowired
private AcmPropertySourceRepository propertySourceRepository;
@Autowired
private AcmPropertySourceRepository acmPropertySourceRepository;
@Test
public void contextLoads() throws Exception {
checkoutEndpoint();
checkoutAcmHealthIndicator();
}
private void checkoutAcmHealthIndicator() {
try {
Builder builder = new Builder();
AcmHealthIndicator healthIndicator = new AcmHealthIndicator(properties,
acmPropertySourceRepository);
healthIndicator.doHealthCheck(builder);
Builder builder1 = new Builder();
List<String> dataIds = new ArrayList<>();
dataIds.add("test-name.properties");
builder1.up().withDetail("dataIds", dataIds);
Assert.assertTrue(builder.build().equals(builder1.build()));
}
catch (Exception ignoreE) {
}
}
private void checkoutEndpoint() throws Exception {
AcmEndpoint acmEndpoint = new AcmEndpoint(properties, refreshHistory,
propertySourceRepository);
Map<String, Object> map = acmEndpoint.invoke();
assertEquals(map.get("config"), properties);
assertEquals(((Map) map.get("runtime")).get("refreshHistory"),
refreshHistory.getRecords());
}
@Configuration
@EnableAutoConfiguration
@ImportAutoConfiguration({ AcmEndpointAutoConfiguration.class,
AcmAutoConfiguration.class, AcmContextBootstrapConfiguration.class })
public static class TestConfig {
}
}

@ -21,16 +21,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
import org.springframework.cloud.alicloud.ans.registry.AnsAutoServiceRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
@ -38,11 +37,11 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@EnableConfigurationProperties
@Conditional(MigrateOnConditionMissingClass.class)
@ConditionalOnClass(name = "org.springframework.boot.web.context.WebServerInitializedEvent")
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@ConditionalOnAnsEnabled
@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class })
public class AnsAutoConfiguration {
@Bean

@ -22,12 +22,7 @@ import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author xiaolongzuo

@ -19,11 +19,9 @@ package org.springframework.cloud.alicloud.ans;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
@ -31,7 +29,6 @@ import org.springframework.context.annotation.Configuration;
* @author pbting
*/
@Configuration
@Conditional(MigrateOnConditionMissingClass.class)
@ConditionalOnMissingBean(DiscoveryClient.class)
@EnableConfigurationProperties
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)

@ -19,8 +19,8 @@ package org.springframework.cloud.alicloud.ans.endpoint;
import com.alibaba.ans.core.NamingService;
import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
@ -37,7 +37,7 @@ import java.util.Set;
@Endpoint(id = "ans")
public class AnsEndpoint {
private static final Log log = LogFactory.getLog(AnsEndpoint.class);
private static final Logger log = LoggerFactory.getLogger(AnsEndpoint.class);
private AnsProperties ansProperties;

@ -1,31 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
@Endpoint(id = "migrate")
public class MigrateEndpoint {
private static final Logger log = LoggerFactory.getLogger(MigrateEndpoint.class);
public MigrateEndpoint() {
}
/**
* @return ans endpoint
*/
@ReadOperation
public Map<String, ConcurrentMap<String, ServerWrapper>> invoke() {
Map<String, ConcurrentMap<String, ServerWrapper>> result = ServerListInvocationHandler
.getServerRegistry();
log.info("migrate server list :" + result);
return result;
}
}

@ -1,21 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
/**
* @author pbting
*/
@ConditionalOnWebApplication
@ConditionalOnClass(value = Endpoint.class)
@Conditional(MigrateOnConditionClass.class)
public class MigrateEndpointAutoConfiguration {
@Bean
public MigrateEndpoint ansEndpoint() {
return new MigrateEndpoint();
}
}

@ -1,48 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
/**
* @author pbting
*/
public abstract class MigrateOnCondition implements Condition, BeanClassLoaderAware {
final String[] conditionOnClass = new String[] {
"org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistration",
"org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration" };
ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public abstract boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata);
boolean isPresent(String className, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = ClassUtils.getDefaultClassLoader();
}
try {
forName(className, classLoader);
return true;
}
catch (Throwable throwable) {
return false;
}
}
Class<?> forName(String className, ClassLoader classLoader)
throws ClassNotFoundException {
return classLoader != null ? classLoader.loadClass(className)
: Class.forName(className);
}
}

@ -1,23 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author pbting
*/
public class MigrateOnConditionClass extends MigrateOnCondition {
private static final Logger log = LoggerFactory
.getLogger(MigrateOnConditionClass.class);
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
boolean result = isPresent(conditionOnClass[0], classLoader)
|| isPresent(conditionOnClass[1], classLoader);
log.info("the result of matcher is " + result);
return result;
}
}

@ -1,22 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author pbting
*/
public class MigrateOnConditionMissingClass extends MigrateOnConditionClass {
private static final Logger log = LoggerFactory
.getLogger(MigrateOnConditionMissingClass.class);
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
boolean result = !super.matches(context, metadata);
log.info(" the result of matcher is " + result);
return result;
}
}

@ -1,97 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import org.aopalliance.aop.Advice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.framework.ProxyFactory;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author pbting
*/
final class MigrateProxyManager {
private static final Logger log = LoggerFactory.getLogger(MigrateProxyManager.class);
private final static AtomicBoolean IS_PROXY = new AtomicBoolean(true);
private final static Set<String> SERVICES_ID = new ConcurrentSkipListSet<>();
private static Object springProxyFactory(Object target, ClassLoader classLoader,
List<Advice> adviceList, Class... interfaces) {
final ProxyFactory proxyFactory = new ProxyFactory(interfaces);
proxyFactory.setTarget(target);
adviceList.forEach(advice -> proxyFactory.addAdvice(advice));
return proxyFactory.getProxy(classLoader);
}
static Object newServerListProxy(Object bean, ClassLoader classLoader,
IClientConfig clientConfig) {
bean = springProxyFactory(bean, classLoader,
Arrays.asList(new ServerListInvocationHandler(clientConfig)),
new Class[] { ServerList.class });
log.info("[service id]" + clientConfig.getClientName()
+ " new a ServerList proxy instance for spring cloud netflix to spring cloud alibaba ");
collectServiceId(clientConfig.getClientName());
return bean;
}
static Object newLoadBalancerProxy(Object bean, ClassLoader classLoader,
final IClientConfig clientConfig) {
bean = springProxyFactory(bean, classLoader,
Arrays.asList(new AfterReturningAdvice() {
private final IClientConfig iclientConfig = clientConfig;
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) {
String methodName = method.getName();
if ("chooseServer".equals(methodName)) {
String serviceId = iclientConfig.getClientName();
Server server = (Server) returnValue;
server = ServerListInvocationHandler
.checkAndGetServiceServer(serviceId, server);
ServerListInvocationHandler.incrementCallService(serviceId,
server);
}
}
}), new Class[] { ILoadBalancer.class });
log.info("[service id]" + clientConfig.getClientName()
+ " new a ILoadBalancer proxy instance for spring cloud netflix to spring cloud alibaba ");
return bean;
}
static void migrateProxyClose() {
IS_PROXY.set(false);
}
static void migrateProxyUp() {
IS_PROXY.set(true);
}
static boolean isMigrateProxy() {
return IS_PROXY.get();
}
static void collectServiceId(String serviceId) {
SERVICES_ID.add(serviceId);
}
static Set<String> getServicesId() {
return Collections.unmodifiableSet(SERVICES_ID);
}
}

@ -1,78 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import com.netflix.loadbalancer.ILoadBalancer;
import org.springframework.cloud.context.named.NamedContextFactory;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author pbting
*/
@Component
public class MigrateRefreshEventListener implements ApplicationListener<RefreshEvent> {
private final static int CHECK_INTERVAL = 1;
private final static String MIGRATE_SWITCH = "spring.cloud.alicloud.migrate.ans.switch";
private volatile String lastScaMigrateAnsSwitchValue = "true";
private Environment environment;
private NamedContextFactory namedContextFactory;
public MigrateRefreshEventListener(Environment environment,
NamedContextFactory namedContextFactory) {
this.environment = environment;
this.namedContextFactory = namedContextFactory;
}
@PostConstruct
public void initTimerCheck() {
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(
() -> onApplicationEvent(null), CHECK_INTERVAL, CHECK_INTERVAL,
TimeUnit.SECONDS);
}
@Override
public void onApplicationEvent(RefreshEvent event) {
String value = environment.getProperty(MIGRATE_SWITCH, "true");
// check 1: check the value
if (value.equals(lastScaMigrateAnsSwitchValue)) {
return;
}
updateLastScaMigrateAnsResetValue(value);
// step 1: migrate up
if ("true".equals(value)) {
MigrateProxyManager.migrateProxyUp();
serviceIdContextInit();
return;
}
// step 2: migrate close
if ("false".equals(value)) {
MigrateProxyManager.migrateProxyClose();
serviceIdContextInit();
return;
}
}
private void serviceIdContextInit() {
namedContextFactory.destroy();
// initializer each spring context for service id
MigrateProxyManager.getServicesId().forEach(serviceId -> namedContextFactory
.getInstance(serviceId, ILoadBalancer.class));
}
private synchronized void updateLastScaMigrateAnsResetValue(String value) {
this.lastScaMigrateAnsSwitchValue = value;
}
}

@ -1,52 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.ServerList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MigrateRibbonBeanPostProcessor
implements BeanPostProcessor, BeanClassLoaderAware {
private static final Logger log = LoggerFactory.getLogger(MigrateOnCondition.class);
private ClassLoader classLoader;
private IClientConfig clientConfig;
public MigrateRibbonBeanPostProcessor(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
// step 1 : check the bean whether proxy or not
if (!MigrateProxyManager.isMigrateProxy()) {
log.info("Migrate proxy is Close.");
return bean;
}
// step 2 : proxy the designated bean
if (bean instanceof ServerList) {
bean = MigrateProxyManager.newServerListProxy(bean, classLoader,
clientConfig);
}
if (bean instanceof ILoadBalancer) {
bean = MigrateProxyManager.newLoadBalancerProxy(bean, classLoader,
clientConfig);
}
return bean;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}

@ -1,52 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.cloud.alicloud.ans.registry.AnsRegistration;
import org.springframework.cloud.alicloud.ans.registry.AnsServiceRegistry;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author pbting
*/
@Component
public class MigrateServiceRegistry {
private static final Logger log = LoggerFactory
.getLogger(MigrateServiceRegistry.class);
private AtomicBoolean running = new AtomicBoolean(false);
private ServiceRegistry serviceRegistry;
private AnsRegistration ansRegistration;
public MigrateServiceRegistry(AnsProperties ansProperties,
ApplicationContext context) {
this.ansRegistration = new AnsRegistration(ansProperties, context);
this.ansRegistration.init();
this.serviceRegistry = new AnsServiceRegistry();
}
@EventListener(WebServerInitializedEvent.class)
public void onApplicationEvent(WebServerInitializedEvent event) {
int serverPort = event.getWebServer().getPort();
this.ansRegistration.setPort(serverPort);
log.info("[ Migrate ] change the port to " + serverPort);
if (!this.running.get()) {
long s = System.currentTimeMillis();
log.info("[Migrate] start to registry server to ANS");
this.serviceRegistry.register(this.ansRegistration);
log.info("[migrate] end to registry server to ANS cost time with "
+ (System.currentTimeMillis() - s) + " ms.");
this.running.set(true);
}
}
}

@ -1,39 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alicloud.ans.ConditionalOnAnsEnabled;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.context.named.NamedContextFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* @author pbting
*/
@Configuration
@EnableConfigurationProperties
@Conditional(MigrateOnConditionClass.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@ConditionalOnAnsEnabled
public class MigrationAutoconfiguration {
@Bean
public MigrateServiceRegistry migrationManger(AnsProperties ansProperties,
ApplicationContext applicationContext) {
return new MigrateServiceRegistry(ansProperties, applicationContext);
}
@Bean
public MigrateRefreshEventListener migrateRefreshEventListener(
Environment environment,
@Qualifier(value = "springClientFactory") NamedContextFactory namedContextFactory) {
return new MigrateRefreshEventListener(environment, namedContextFactory);
}
}

@ -1,170 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.alicloud.ans.ribbon.AnsServer;
import org.springframework.cloud.alicloud.ans.ribbon.AnsServerList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author pbting
*/
class ServerListInvocationHandler implements MethodInterceptor {
private static final Logger log = LoggerFactory
.getLogger(ServerListInvocationHandler.class);
private final static ConcurrentMap<String, AnsServerList> SERVER_LIST_CONCURRENT_MAP = new ConcurrentHashMap<>();
private final static ConcurrentMap<String, ConcurrentMap<String, ServerWrapper>> CALL_SERVICE_COUNT = new ConcurrentHashMap<>();
private final static Set<String> INTERCEPTOR_METHOD_NAME = new ConcurrentSkipListSet();
private IClientConfig clientConfig;
private AnsServerList ansServerList;
private AtomicBoolean isFirst = new AtomicBoolean(false);
static {
INTERCEPTOR_METHOD_NAME.add("getInitialListOfServers");
INTERCEPTOR_METHOD_NAME.add("getUpdatedListOfServers");
}
ServerListInvocationHandler(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
this.ansServerList = new AnsServerList(clientConfig.getClientName());
SERVER_LIST_CONCURRENT_MAP.put(ansServerList.getDom(), ansServerList);
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String methodName = invocation.getMethod().getName();
// step 1: check the method is not interceptor
if (!INTERCEPTOR_METHOD_NAME.contains(methodName)) {
return invocation.proceed();
}
// step 2: interceptor the method
List<Server> serverList = (List<Server>) invocation.proceed();
long s = System.currentTimeMillis();
log.info("[ START ] merage server list for " + clientConfig.getClientName());
serverList = mergeAnsServerList(serverList);
log.info("[ END ] merage server list for " + clientConfig.getClientName()
+ ", cost time " + (System.currentTimeMillis() - s) + " ms .");
return serverList;
}
/**
* 线 Eureka Merage List Server. ANS
*/
private List<Server> mergeAnsServerList(final List<Server> source) {
if (isFirst.compareAndSet(false, true)) {
return source;
}
// step 1: get all of server list and filter the alive
List<AnsServer> ansServerList = filterAliveAnsServer(
this.ansServerList.getInitialListOfServers());
if (ansServerList.isEmpty()) {
return source;
}
log.info("[" + this.clientConfig.getClientName() + "] Get Server List from ANS:"
+ ansServerList + "; loadbalancer server list override before:" + source);
// step 2:remove servers of that have in load balancer list
final Iterator<Server> serverIterator = source.iterator();
while (serverIterator.hasNext()) {
final Server server = serverIterator.next();
ansServerList.forEach(ansServer -> {
if (server.getHostPort()
.equals(ansServer.getHealthService().toInetAddr())) {
// by: ZoneAffinityPredicate
serverIterator.remove();
log.info("Source Server is remove " + server.getHostPort()
+ ", and from ANS Server is override"
+ ansServer.toString());
}
// fix bug: mast be set the zone, update server list,will filter
ansServer.setZone(server.getZone());
ansServer.setSchemea(server.getScheme());
ansServer.setId(ansServer.getHealthService().toInetAddr());
ansServer.setReadyToServe(true);
});
}
ansServerList.forEach(ansServer -> source.add(ansServer));
log.info("[" + this.clientConfig.getClientName() + "] "
+ "; loadbalancer server list override after:" + source);
// override
return source;
}
private List<AnsServer> filterAliveAnsServer(List<AnsServer> sourceServerList) {
final List<AnsServer> resultServerList = new LinkedList<>();
sourceServerList.forEach(ansServer -> {
boolean isAlive = ansServer.isAlive(3);
if (isAlive) {
resultServerList.add(ansServer);
}
log.warn(ansServer.toString() + " isAlive :" + isAlive);
});
return resultServerList;
}
static Map<String, ConcurrentMap<String, ServerWrapper>> getServerRegistry() {
return Collections.unmodifiableMap(CALL_SERVICE_COUNT);
}
static Server checkAndGetServiceServer(String serviceId, Server server) {
if (server != null) {
return server;
}
log.warn(String.format("[%s] refers the server is null", server));
List<AnsServer> ansServerList = SERVER_LIST_CONCURRENT_MAP.get(serviceId)
.getInitialListOfServers();
if (!ansServerList.isEmpty()) {
return ansServerList.get(0);
}
return server;
}
static void incrementCallService(String serviceId, Server server) {
ConcurrentMap<String, ServerWrapper> concurrentHashMap = CALL_SERVICE_COUNT
.putIfAbsent(serviceId, new ConcurrentHashMap<>());
if (concurrentHashMap == null) {
concurrentHashMap = CALL_SERVICE_COUNT.get(serviceId);
}
String ipPort = server.getHostPort();
ServerWrapper serverWraper = concurrentHashMap.putIfAbsent(ipPort,
new ServerWrapper(server, new AtomicLong()));
if (serverWraper == null) {
serverWraper = concurrentHashMap.get(ipPort);
}
serverWraper.setServer(server);
serverWraper.getCallCount().incrementAndGet();
}
}

@ -1,38 +0,0 @@
package org.springframework.cloud.alicloud.ans.migrate;
import com.netflix.loadbalancer.Server;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author pbting
*/
public class ServerWrapper {
private Server server;
private AtomicLong callCount;
public ServerWrapper() {
}
public ServerWrapper(Server server, AtomicLong callCount) {
this.server = server;
this.callCount = callCount;
}
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
}
public AtomicLong getCallCount() {
return callCount;
}
public void setCallCount(AtomicLong callCount) {
this.callCount = callCount;
}
}

@ -18,7 +18,6 @@ package org.springframework.cloud.alicloud.ans.registry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
@ -34,7 +33,6 @@ public class AnsAutoServiceRegistration
private static final Logger log = LoggerFactory
.getLogger(AnsAutoServiceRegistration.class);
@Autowired
private AnsRegistration registration;
public AnsAutoServiceRegistration(ServiceRegistry<AnsRegistration> serviceRegistry,

@ -41,11 +41,11 @@ public class AnsServiceRegistry implements ServiceRegistry<AnsRegistration> {
public void register(AnsRegistration registration) {
if (!registration.isRegisterEnabled()) {
log.info("Registration is disabled...");
log.warn("Registration is disabled...");
return;
}
if (StringUtils.isEmpty(registration.getServiceId())) {
log.info("No service to register for client...");
log.warn("No service to register for client...");
return;
}
@ -63,14 +63,13 @@ public class AnsServiceRegistry implements ServiceRegistry<AnsRegistration> {
NamingService.regDom(dom, registration.getHost(), registration.getPort(),
registration.getRegisterWeight(dom), registration.getCluster(),
tags);
log.info("INFO_ANS_REGISTER, " + dom + " "
+ registration.getAnsProperties().getClientIp() + ":"
+ registration.getAnsProperties().getClientPort()
+ " register finished");
log.info("INFO_ANS_REGISTER, {} {}:{} register finished", dom,
registration.getAnsProperties().getClientIp(),
registration.getAnsProperties().getClientPort());
}
catch (Exception e) {
log.error("ERR_ANS_REGISTER, " + dom + " register failed..."
+ registration.toString() + ",", e);
log.error("ERR_ANS_REGISTER, {} register failed...{},", dom,
registration.toString(), e);
}
}
}
@ -81,7 +80,7 @@ public class AnsServiceRegistry implements ServiceRegistry<AnsRegistration> {
log.info("De-registering from ANSServer now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
log.info("No dom to de-register for client...");
log.warn("No dom to de-register for client...");
return;
}
@ -90,8 +89,8 @@ public class AnsServiceRegistry implements ServiceRegistry<AnsRegistration> {
registration.getPort(), registration.getCluster());
}
catch (Exception e) {
log.error("ERR_ANS_DEREGISTER, de-register failed..."
+ registration.toString() + ",", e);
log.error("ERR_ANS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
log.info("De-registration finished.");

@ -19,9 +19,7 @@ package org.springframework.cloud.alicloud.ans.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
@ -29,7 +27,6 @@ import org.springframework.context.annotation.Configuration;
* @author pbting
*/
@Configuration
@Conditional(MigrateOnConditionMissingClass.class)
public class AnsRibbonClientConfiguration {
@Bean

@ -16,16 +16,12 @@
package org.springframework.cloud.alicloud.ans.ribbon;
import java.util.Collections;
import java.util.Map;
import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import com.netflix.loadbalancer.Server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author xiaolongzuo
*/
@ -38,8 +34,7 @@ public class AnsServer extends Server {
public AnsServer(final Host host, final String dom) {
super(host.getIp(), host.getPort());
this.host = host;
this.metadata = new HashMap();
this.metadata.put("source", "ANS");
this.metadata = Collections.emptyMap();
metaInfo = new MetaInfo() {
@Override
public String getAppName() {
@ -64,33 +59,6 @@ public class AnsServer extends Server {
};
}
@Override
public boolean isAlive() {
return true;
}
/**
*
* @param timeOut Unit: Seconds
* @return
*/
public boolean isAlive(long timeOut) {
try {
String hostName = this.host.getHostname();
hostName = hostName != null && hostName.trim().length() > 0 ? hostName
: this.host.getIp();
Socket socket = new Socket();
socket.connect(new InetSocketAddress(hostName, this.host.getPort()),
(int) TimeUnit.SECONDS.toMillis(timeOut));
socket.close();
return true;
}
catch (IOException e) {
return false;
}
}
@Override
public MetaInfo getMetaInfo() {
return metaInfo;

@ -16,23 +16,19 @@
package org.springframework.cloud.alicloud.ans.ribbon;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.ans.core.NamingService;
import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
import java.util.ArrayList;
import java.util.List;
/**
* @author xiaolongzuo
* @author pbting
*/
public class AnsServerList extends AbstractServerList<AnsServer> {
private final static int CONNECT_TIME_OUT = 3;
private String dom;
public AnsServerList(String dom) {
@ -64,12 +60,10 @@ public class AnsServerList extends AbstractServerList<AnsServer> {
List<AnsServer> result = new ArrayList<AnsServer>(hosts.size());
for (Host host : hosts) {
if (host.isValid()) {
AnsServer ansServer = hostToServer(host);
if (ansServer.isAlive(CONNECT_TIME_OUT)) {
result.add(ansServer);
}
result.add(hostToServer(host));
}
}
return result;
}

@ -1,19 +0,0 @@
package org.springframework.cloud.alicloud.ans.ribbon;
import com.netflix.client.config.IClientConfig;
import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionClass;
import org.springframework.cloud.alicloud.ans.migrate.MigrateRibbonBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
@Conditional(MigrateOnConditionClass.class)
public class MigrateRibbonCofiguration {
@Bean
public MigrateRibbonBeanPostProcessor migrateBeanPostProcessor(IClientConfig clientConfig) {
return new MigrateRibbonBeanPostProcessor(clientConfig);
}
}

@ -34,7 +34,6 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnRibbonAns
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = { AnsRibbonClientConfiguration.class,
MigrateRibbonCofiguration.class })
@RibbonClients(defaultConfiguration = AnsRibbonClientConfiguration.class)
public class RibbonAnsAutoConfiguration {
}

@ -2,6 +2,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alicloud.ans.endpoint.AnsEndpointAutoConfiguration,\
org.springframework.cloud.alicloud.ans.ribbon.RibbonAnsAutoConfiguration,\
org.springframework.cloud.alicloud.ans.AnsAutoConfiguration,\
org.springframework.cloud.alicloud.ans.migrate.MigrateEndpointAutoConfiguration,\
org.springframework.cloud.alicloud.ans.migrate.MigrationAutoconfiguration,\
org.springframework.cloud.alicloud.ans.AnsDiscoveryClientAutoConfiguration

@ -71,8 +71,6 @@ public class AnsServerListTests {
PowerMockito.mockStatic(NamingService.class);
when(NamingService.getHosts(anyString())).thenReturn(hosts);
PowerMockito.stub(PowerMockito.method(AnsServer.class, "isAlive", long.class))
.toReturn(true);
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
@ -101,8 +99,6 @@ public class AnsServerListTests {
when(NamingService.getHosts(eq("test-service"))).thenReturn(
hosts.stream().filter(Host::isValid).collect(Collectors.toList()));
PowerMockito.stub(PowerMockito.method(AnsServer.class, "isAlive", long.class))
.toReturn(true);
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");
@ -132,8 +128,6 @@ public class AnsServerListTests {
PowerMockito.mockStatic(NamingService.class);
when(NamingService.getHosts(eq("test-service"))).thenReturn(
hosts.stream().filter(Host::isValid).collect(Collectors.toList()));
PowerMockito.stub(PowerMockito.method(AnsServer.class, "isAlive", long.class))
.toReturn(true);
IClientConfig clientConfig = mock(IClientConfig.class);
when(clientConfig.getClientName()).thenReturn("test-service");

@ -88,6 +88,10 @@ public class AcmIntegrationProperties {
this.activeProfiles = activeProfiles;
}
public String[] getActiveProfiles() {
return activeProfiles;
}
public void setAcmProperties(AcmProperties acmProperties) {
this.acmProperties = acmProperties;
}

Loading…
Cancel
Save