diff --git a/pom.xml b/pom.xml index 3e5ac4ab..36cc1d8f 100644 --- a/pom.xml +++ b/pom.xml @@ -83,11 +83,6 @@ spring-cloud-zookeeper-core ${project.version} - - org.springframework.cloud - spring-cloud-zookeeper-bus - ${project.version} - org.springframework.cloud spring-cloud-zookeeper-config @@ -101,47 +96,17 @@ org.springframework.cloud spring-cloud-commons - ${spring.cloud.commons} + ${spring-cloud-commons.version} org.springframework.cloud - spring-cloud-bus - ${spring.cloud.bus} - - - org.springframework.boot - spring-boot-starter-amqp - - - org.springframework.integration - spring-integration-amqp - - - org.springframework.cloud - spring-cloud-spring-service-connector - - - - org.springframework.cloud - spring-cloud-localconfig-connector - - - - org.springframework.cloud - spring-cloud-cloudfoundry-connector - - - - - - org.springframework.cloud - spring-cloud-config-client - ${spring.cloud.config.client} + spring-cloud-context + ${spring-cloud-commons.version} org.springframework.cloud spring-cloud-netflix-core - ${spring.cloud.netflix.core} + ${spring-cloud-netflix.version} org.apache.curator @@ -164,6 +129,17 @@ ${curator.version} test + + com.netflix.archaius + archaius-core + ${archaius.version} + + + + commons-configuration + commons-configuration + 1.8 + com.netflix.ribbon ribbon @@ -174,6 +150,11 @@ ribbon-core ${ribbon.version} + + com.netflix.ribbon + ribbon-loadbalancer + ${ribbon.version} + com.netflix.ribbon ribbon-httpclient @@ -226,12 +207,11 @@ - 1.0.1.BUILD-SNAPSHOT - 1.0.1.BUILD-SNAPSHOT - 1.0.1.BUILD-SNAPSHOT - 1.0.1.BUILD-SNAPSHOT + 1.0.2.BUILD-SNAPSHOT + 1.0.3.BUILD-SNAPSHOT + 0.6.6 2.7.0 - 2.0-RC9 + 2.0.2 1.0-groovy-2.4 diff --git a/spring-cloud-zookeeper-config/pom.xml b/spring-cloud-zookeeper-config/pom.xml index a32f8a9a..b8966eb6 100644 --- a/spring-cloud-zookeeper-config/pom.xml +++ b/spring-cloud-zookeeper-config/pom.xml @@ -32,7 +32,7 @@ org.springframework.cloud - spring-cloud-config-client + spring-cloud-context org.apache.curator diff --git a/spring-cloud-zookeeper-discovery/pom.xml b/spring-cloud-zookeeper-discovery/pom.xml index 33c1dfc1..96a66cf2 100644 --- a/spring-cloud-zookeeper-discovery/pom.xml +++ b/spring-cloud-zookeeper-discovery/pom.xml @@ -45,6 +45,14 @@ org.springframework.cloud spring-cloud-netflix-core + + com.netflix.archaius + archaius-core + + + commons-configuration + commons-configuration + com.netflix.ribbon ribbon @@ -53,6 +61,10 @@ com.netflix.ribbon ribbon-core + + com.netflix.ribbon + ribbon-loadbalancer + com.netflix.ribbon ribbon-httpclient diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/AddressProviderConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/AddressProviderConfiguration.java deleted file mode 100644 index db8c35da..00000000 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/AddressProviderConfiguration.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2012-2015 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.zookeeper.discovery; - -import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.util.Enumeration; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; - -/** - * Configuration that registers a bean related to microservice's address and port providing. - * - * @see MicroserviceAddressProvider - * - * @author Marcin Grzejszczak, 4financeIT - * @author Tomasz Dziurko, 4financeIT - */ -@Configuration -public class AddressProviderConfiguration { - - @Autowired - private Environment environment; - - @Autowired - private ZookeeperDiscoveryProperties properties; - - public AddressProviderConfiguration(Environment environment, - ZookeeperDiscoveryProperties properties) { - this.environment = environment; - this.properties = properties; - } - - @Bean - public MicroserviceAddressProvider microserviceAddressProvider() { - String host = properties.getInstanceHost() == null? getIpAddress() : properties.getInstanceHost(); - Integer port = Integer.valueOf(environment.getProperty("server.port", "8080")); - return new MicroserviceAddressProvider(host, port); - } - - /** - * Return a non loopback IPv4 address for the machine running this process. - * If the machine has multiple network interfaces, the IP address for the - * first interface returned by {@link java.net.NetworkInterface#getNetworkInterfaces} - * is returned. - * - * @return non loopback IPv4 address for the machine running this process - * @see java.net.NetworkInterface#getNetworkInterfaces - * @see java.net.NetworkInterface#getInetAddresses - */ - public static String getIpAddress() { - try { - for (Enumeration enumNic = NetworkInterface.getNetworkInterfaces(); - enumNic.hasMoreElements(); ) { - NetworkInterface ifc = enumNic.nextElement(); - if (ifc.isUp()) { - for (Enumeration enumAddr = ifc.getInetAddresses(); - enumAddr.hasMoreElements(); ) { - InetAddress address = enumAddr.nextElement(); - if (address instanceof Inet4Address && !address.isLoopbackAddress()) { - return address.getHostAddress(); - } - } - } - } - } catch (IOException e) { - // ignore - } - return "unknown"; - } - -} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/MicroserviceAddressProvider.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/MicroserviceAddressProvider.java deleted file mode 100644 index 897bbc78..00000000 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/MicroserviceAddressProvider.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012-2015 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.zookeeper.discovery; - -/** - * Holder for microservice's host and port - * - * @author Marcin Grzejszczak, 4financeIT - * @author Adam Chudzik, 4financeIT - * - */ -public class MicroserviceAddressProvider { - private final String host; - private final int port; - - public MicroserviceAddressProvider(String microserviceHost, int microservicePort) { - this.host = microserviceHost; - this.port = microservicePort; - } - - public String getHost() { - return host; - } - - public int getPort() { - return port; - } -} \ No newline at end of file diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java index c32efb6e..56ac7bae 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java @@ -3,11 +3,13 @@ package org.springframework.cloud.zookeeper.discovery; import lombok.SneakyThrows; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceInstance; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import java.util.ArrayList; import java.util.Collection; @@ -21,17 +23,14 @@ import static org.springframework.util.ReflectionUtils.rethrowRuntimeException; */ public class ZookeeperDiscoveryClient implements DiscoveryClient { - @Autowired - ApplicationContext context; + private ZookeeperServiceDiscovery serviceDiscovery; - @Autowired(required = false) - ServiceInstance instance; + private ZookeeperDependencies zookeeperDependencies; - @Autowired - ServiceDiscovery discovery; - - @Autowired(required = false) - ZookeeperDependencies zookeeperDependencies; + public ZookeeperDiscoveryClient(ZookeeperServiceDiscovery serviceDiscovery, ZookeeperDependencies zookeeperDependencies) { + this.serviceDiscovery = serviceDiscovery; + this.zookeeperDependencies = zookeeperDependencies; + } @Override public String description() { @@ -40,12 +39,8 @@ public class ZookeeperDiscoveryClient implements DiscoveryClient { @Override public org.springframework.cloud.client.ServiceInstance getLocalServiceInstance() { - if (instance == null) { - throw new IllegalStateException("Unable to locate instance in zookeeper: " - + context.getId()); - } - - return createServiceInstance(instance.getId(), instance); + ServiceInstance serviceInstance = serviceDiscovery.getServiceInstance(); + return createServiceInstance(serviceInstance.getId(), serviceInstance); } private static org.springframework.cloud.client.ServiceInstance createServiceInstance(String serviceId, ServiceInstance serviceInstance) { @@ -64,7 +59,7 @@ public class ZookeeperDiscoveryClient implements DiscoveryClient { public List getInstances( final String serviceId) { String serviceIdToQuery = getServiceIdToQuery(serviceId); - Collection> zkInstances = discovery + Collection> zkInstances = serviceDiscovery.getServiceDiscovery() .queryForInstances(serviceIdToQuery); ArrayList instances = new ArrayList<>(); @@ -87,7 +82,7 @@ public class ZookeeperDiscoveryClient implements DiscoveryClient { public List getServices() { ArrayList services = null; try { - services = new ArrayList<>(discovery.queryForNames()); + services = new ArrayList<>(serviceDiscovery.getServiceDiscovery().queryForNames()); } catch (Exception e) { rethrowRuntimeException(e); diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java index e4a82e53..d4e5f3da 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java @@ -1,56 +1,46 @@ package org.springframework.cloud.zookeeper.discovery; import org.apache.curator.framework.CuratorFramework; -import org.apache.curator.x.discovery.ServiceDiscovery; -import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; -import org.apache.curator.x.discovery.ServiceInstance; -import org.apache.curator.x.discovery.UriSpec; import org.apache.curator.x.discovery.details.InstanceSerializer; import org.apache.curator.x.discovery.details.JsonInstanceSerializer; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.ApplicationContext; +import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.env.Environment; /** * @author Spencer Gibb */ @Configuration -@Import(AddressProviderConfiguration.class) @EnableConfigurationProperties public class ZookeeperDiscoveryClientConfiguration { + + @Autowired(required = false) + private ZookeeperDependencies zookeeperDependencies; + @Autowired - ApplicationContext context; + private CuratorFramework curator; @Bean public ZookeeperDiscoveryProperties zookeeperDiscoveryProperties() { return new ZookeeperDiscoveryProperties(); } + @Bean + public ZookeeperServiceDiscovery zookeeperServiceDiscovery() { + return new ZookeeperServiceDiscovery(curator, zookeeperDiscoveryProperties(), + instanceSerializer()); + } + @Bean public ZookeeperLifecycle zookeeperLifecycle() { - return new ZookeeperLifecycle(); + return new ZookeeperLifecycle(zookeeperDiscoveryProperties(), zookeeperServiceDiscovery()); } @Bean public ZookeeperDiscoveryClient zookeeperDiscoveryClient() { - return new ZookeeperDiscoveryClient(); - } - - @Bean - @ConditionalOnMissingBean - public ServiceInstance serviceInstance(MicroserviceAddressProvider microserviceAddressProvider) throws Exception { - Environment environment = context.getEnvironment(); - UriSpec uriSpec = new UriSpec(zookeeperDiscoveryProperties().getUriSpec()); - return ServiceInstance. builder() - .name(environment.getProperty("spring.application.name")) - .payload(new ZookeeperInstance(context.getId())).port(microserviceAddressProvider.getPort()) - .address(microserviceAddressProvider.getHost()) - .uriSpec(uriSpec).build(); + return new ZookeeperDiscoveryClient(zookeeperServiceDiscovery(), zookeeperDependencies); } @Bean @@ -58,18 +48,9 @@ public class ZookeeperDiscoveryClientConfiguration { return new JsonInstanceSerializer<>(ZookeeperInstance.class); } - @Bean - @ConditionalOnMissingBean - public ServiceDiscovery serviceDiscovery(CuratorFramework curator, ServiceInstance serviceInstance) - throws Exception { - return ServiceDiscoveryBuilder.builder(ZookeeperInstance.class).client(curator) - .basePath(zookeeperDiscoveryProperties().getRoot()) - .serializer(instanceSerializer()).thisInstance(serviceInstance).build(); - } - @Bean public ZookeeperDiscoveryHealthIndicator zookeeperDiscoveryHealthIndicator() { - return new ZookeeperDiscoveryHealthIndicator(); + return new ZookeeperDiscoveryHealthIndicator(zookeeperServiceDiscovery()); } } diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java index 3bc02833..42f04046 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java @@ -5,9 +5,7 @@ import java.util.Collection; import lombok.extern.slf4j.Slf4j; -import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceInstance; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -16,17 +14,21 @@ import org.springframework.boot.actuate.health.Health; */ @Slf4j public class ZookeeperDiscoveryHealthIndicator extends AbstractHealthIndicator { - @Autowired - ServiceDiscovery serviceDiscovery; + + private ZookeeperServiceDiscovery serviceDiscovery; + + public ZookeeperDiscoveryHealthIndicator(ZookeeperServiceDiscovery serviceDiscovery) { + this.serviceDiscovery = serviceDiscovery; + } @Override protected void doHealthCheck(Health.Builder builder) throws Exception { try { - Collection names = serviceDiscovery.queryForNames(); + Collection names = serviceDiscovery.getServiceDiscovery().queryForNames(); ArrayList> allInstances = new ArrayList<>(); for (String name : names) { Collection> instances = serviceDiscovery - .queryForInstances(name); + .getServiceDiscovery().queryForInstances(name); for (ServiceInstance instance : instances) { allInstances.add(instance); } diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java index db4cbab7..94e9f648 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java @@ -3,9 +3,6 @@ package org.springframework.cloud.zookeeper.discovery; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.curator.x.discovery.ServiceDiscovery; -import org.apache.curator.x.discovery.ServiceInstance; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle; /** @@ -14,19 +11,19 @@ import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle; @Slf4j public class ZookeeperLifecycle extends AbstractDiscoveryLifecycle { - @Autowired private ZookeeperDiscoveryProperties properties; + private ZookeeperServiceDiscovery serviceDiscovery; - @Autowired - private ServiceDiscovery serviceDiscovery; - - @Autowired - private ServiceInstance instance; + public ZookeeperLifecycle(ZookeeperDiscoveryProperties properties, + ZookeeperServiceDiscovery serviceDiscovery) { + this.properties = properties; + this.serviceDiscovery = serviceDiscovery; + } @Override @SneakyThrows protected void register() { - serviceDiscovery.start(); + this.serviceDiscovery.getServiceDiscovery().start(); } // TODO: implement registerManagement @@ -34,7 +31,8 @@ public class ZookeeperLifecycle extends AbstractDiscoveryLifecycle { @Override @SneakyThrows protected void deregister() { - serviceDiscovery.unregisterService(instance); + this.serviceDiscovery.getServiceDiscovery().unregisterService( + this.serviceDiscovery.getServiceInstance()); } // TODO: implement deregisterManagement @@ -44,6 +42,17 @@ public class ZookeeperLifecycle extends AbstractDiscoveryLifecycle { return properties.isEnabled(); } + @Override + protected int getConfiguredPort() { + return serviceDiscovery.getPort(); + } + + @Override + protected void setConfiguredPort(int port) { + serviceDiscovery.setPort(port); + serviceDiscovery.build(); + } + @Override protected Object getConfiguration() { return properties; diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java index 8f8e78fb..c97f24cb 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java @@ -21,7 +21,6 @@ import com.netflix.config.ConfigurationManager; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; import com.netflix.loadbalancer.ServerList; -import org.apache.curator.x.discovery.ServiceDiscovery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -50,8 +49,10 @@ import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity public class ZookeeperRibbonClientConfiguration { protected static final String VALUE_NOT_SET = "__not__set__"; protected static final String DEFAULT_NAMESPACE = "ribbon"; + @Autowired - private ServiceDiscovery serviceDiscovery; + private ZookeeperServiceDiscovery serviceDiscovery; + @Value("${ribbon.client.name}") private String serviceId = "client"; @@ -63,7 +64,7 @@ public class ZookeeperRibbonClientConfiguration { @Conditional(DependenciesPassedCondition.class) @ConditionalOnProperty(value = "zookeeper.dependencies.enabled", matchIfMissing = true) public ServerList ribbonServerListFromDependencies(IClientConfig config, ZookeeperDependencies zookeeperDependencies) { - ZookeeperServerList serverList = new ZookeeperServerList(serviceDiscovery); + ZookeeperServerList serverList = new ZookeeperServerList(serviceDiscovery.getServiceDiscovery()); serverList.initFromDependencies(config, zookeeperDependencies); return serverList; } @@ -71,7 +72,7 @@ public class ZookeeperRibbonClientConfiguration { @Bean @ConditionalOnMissingBean public ServerList ribbonServerList(IClientConfig config) { - ZookeeperServerList serverList = new ZookeeperServerList(serviceDiscovery); + ZookeeperServerList serverList = new ZookeeperServerList(serviceDiscovery.getServiceDiscovery()); serverList.initWithNiwsConfig(config); return serverList; } diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServiceDiscovery.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServiceDiscovery.java new file mode 100644 index 00000000..f7cee2d2 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServiceDiscovery.java @@ -0,0 +1,151 @@ +package org.springframework.cloud.zookeeper.discovery; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import lombok.SneakyThrows; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; +import org.apache.curator.x.discovery.ServiceInstance; +import org.apache.curator.x.discovery.UriSpec; +import org.apache.curator.x.discovery.details.InstanceSerializer; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.util.Assert; + +/** + * @author Spencer Gibb + */ +public class ZookeeperServiceDiscovery implements ApplicationContextAware { + + private CuratorFramework curator; + + private ZookeeperDiscoveryProperties properties; + + private InstanceSerializer instanceSerializer; + + private ApplicationContext context; + + private AtomicBoolean built = new AtomicBoolean(false); + + private AtomicInteger port = new AtomicInteger(); + + private AtomicReference> serviceInstance = new AtomicReference<>(); + + private AtomicReference> serviceDiscovery = new AtomicReference<>(); + + @Value("${spring.application.name:application}") + private String appName; + + public ZookeeperServiceDiscovery(CuratorFramework curator, ZookeeperDiscoveryProperties properties, InstanceSerializer instanceSerializer) { + this.curator = curator; + this.properties = properties; + this.instanceSerializer = instanceSerializer; + } + + public int getPort() { + return this.port.get(); + } + + public void setPort(int port) { + this.port.set(port); + } + + public ServiceInstance getServiceInstance() { + Assert.notNull(serviceInstance.get(), "serviceInstance has not been built"); + return serviceInstance.get(); + } + + public ServiceDiscovery getServiceDiscovery() { + Assert.notNull(serviceDiscovery.get(), "serviceDiscovery has not been built"); + return serviceDiscovery.get(); + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + this.context = context; + } + + @SneakyThrows + public void build() { + if (built.compareAndSet(false, true)) { + if (port.get() <= 0) { + throw new IllegalStateException("Cannot create instance whose port is not greater than 0"); + } + String host = properties.getInstanceHost() == null? getIpAddress() : properties.getInstanceHost(); + UriSpec uriSpec = new UriSpec(properties.getUriSpec()); + // @formatter:off + serviceInstance.set(ServiceInstance.builder() + .name(appName) + .payload(new ZookeeperInstance(context.getId())) + .port(port.get()) + .address(host) + .uriSpec(uriSpec).build()); + + serviceDiscovery.set(ServiceDiscoveryBuilder.builder(ZookeeperInstance.class) + .client(curator) + .basePath(properties.getRoot()) + .serializer(instanceSerializer) + .thisInstance(serviceInstance.get()) + .build()); + // @formatter:on + } + } + + + /** + * Return a non loopback IPv4 address for the machine running this process. + * If the machine has multiple network interfaces, the IP address for the + * first interface returned by {@link java.net.NetworkInterface#getNetworkInterfaces} + * is returned. + * + * @return non loopback IPv4 address for the machine running this process + * @see java.net.NetworkInterface#getNetworkInterfaces + * @see java.net.NetworkInterface#getInetAddresses + */ + public static String getIpAddress() { + try { + for (Enumeration enumNic = NetworkInterface.getNetworkInterfaces(); + enumNic.hasMoreElements(); ) { + NetworkInterface ifc = enumNic.nextElement(); + if (ifc.isUp()) { + for (Enumeration enumAddr = ifc.getInetAddresses(); + enumAddr.hasMoreElements(); ) { + InetAddress address = enumAddr.nextElement(); + if (address instanceof Inet4Address && !address.isLoopbackAddress()) { + return address.getHostAddress(); + } + } + } + } + } catch (IOException e) { + // ignore + } + return "unknown"; + } + + protected AtomicReference> getServiceDiscoveryRef() { + return this.serviceDiscovery; + } + + protected AtomicReference> getServiceInstanceRef() { + return this.serviceInstance; + } + + protected AtomicBoolean getBuilt() { + return this.built; + } + + protected CuratorFramework getCurator() { + return curator; + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/dependency/LoadBalancerType.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/dependency/LoadBalancerType.java index 139f3e80..217ffbdb 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/dependency/LoadBalancerType.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/dependency/LoadBalancerType.java @@ -15,32 +15,23 @@ */ package org.springframework.cloud.zookeeper.discovery.dependency; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections.Predicate; - -import java.util.Arrays; - -import static org.apache.commons.lang.StringUtils.EMPTY; -import static org.apache.commons.lang.StringUtils.defaultIfEmpty; - /** * @author Marcin Grzejszczak, 4financeIT + * @author Spencer Gibb */ public enum LoadBalancerType { STICKY, RANDOM, ROUND_ROBIN; - public static LoadBalancerType fromName(final String strategyName) { - LoadBalancerType loadBalancerType = (LoadBalancerType) CollectionUtils.find(Arrays.asList(values()), new Predicate() { - @Override - public boolean evaluate(Object o) { - LoadBalancerType input = (LoadBalancerType) o; - return input.name().equals(defaultIfEmpty(strategyName, EMPTY).toUpperCase()); - } - }); - if (loadBalancerType == null) { + public static LoadBalancerType fromName(String strategyName) { + if (strategyName == null) { return ROUND_ROBIN; } - return loadBalancerType; + for (LoadBalancerType type : values()) { + if (type.name().equals(strategyName.toUpperCase())) { + return type; + } + } + return ROUND_ROBIN; } } diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcher.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcher.java index d3ef8f24..a0ecf344 100755 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcher.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcher.java @@ -15,30 +15,33 @@ */ package org.springframework.cloud.zookeeper.discovery.watcher; -import org.apache.curator.x.discovery.ServiceCache; -import org.apache.curator.x.discovery.ServiceDiscovery; -import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies; -import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies.ZookeeperDependency; -import org.springframework.cloud.zookeeper.discovery.watcher.presence.DependencyPresenceOnStartupVerifier; - import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.SneakyThrows; +import org.apache.curator.x.discovery.ServiceCache; +import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; +import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceDiscovery; +import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies; +import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies.ZookeeperDependency; +import org.springframework.cloud.zookeeper.discovery.watcher.presence.DependencyPresenceOnStartupVerifier; +import org.springframework.context.ApplicationListener; + /** * @author Marcin Grzejszczak, 4financeIT * @author Michal Chmielarz, 4financeIT */ -public class DefaultDependencyWatcher implements DependencyRegistrationHookProvider { +public class DefaultDependencyWatcher implements DependencyRegistrationHookProvider, ApplicationListener { - private final ServiceDiscovery serviceDiscovery; + private final ZookeeperServiceDiscovery serviceDiscovery; private final Map dependencyRegistry = new HashMap<>(); private final List listeners; private final DependencyPresenceOnStartupVerifier dependencyPresenceOnStartupVerifier; private final ZookeeperDependencies zookeeperDependencies; - public DefaultDependencyWatcher(ServiceDiscovery serviceDiscovery, + public DefaultDependencyWatcher(ZookeeperServiceDiscovery serviceDiscovery, DependencyPresenceOnStartupVerifier dependencyPresenceOnStartupVerifier, List dependencyWatcherListeners, ZookeeperDependencies zookeeperDependencies) { @@ -48,12 +51,19 @@ public class DefaultDependencyWatcher implements DependencyRegistrationHookProvi this.zookeeperDependencies = zookeeperDependencies; } + @Override + @SneakyThrows + public void onApplicationEvent(InstanceRegisteredEvent event) { + registerDependencyRegistrationHooks(); + } + @Override @SuppressWarnings("unchecked") public void registerDependencyRegistrationHooks() throws Exception { for (ZookeeperDependency zookeeperDependency : zookeeperDependencies.getDependencyConfigurations()) { String dependencyPath = zookeeperDependency.getPath(); - ServiceCache serviceCache = serviceDiscovery.serviceCacheBuilder().name(dependencyPath).build(); + ServiceCache serviceCache = serviceDiscovery.getServiceDiscovery() + .serviceCacheBuilder().name(dependencyPath).build(); serviceCache.start(); dependencyPresenceOnStartupVerifier.verifyDependencyPresence(dependencyPath, serviceCache, zookeeperDependency.isRequired()); dependencyRegistry.put(dependencyPath, serviceCache); diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DependencyWatcherAutoConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DependencyWatcherAutoConfiguration.java index a0b62a1c..d4b2042c 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DependencyWatcherAutoConfiguration.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/watcher/DependencyWatcherAutoConfiguration.java @@ -15,12 +15,15 @@ */ package org.springframework.cloud.zookeeper.discovery.watcher; -import org.apache.curator.x.discovery.ServiceDiscovery; +import java.util.ArrayList; +import java.util.List; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceDiscovery; import org.springframework.cloud.zookeeper.discovery.dependency.DependenciesPassedCondition; import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies; import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependenciesAutoConfiguration; @@ -30,9 +33,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import java.util.ArrayList; -import java.util.List; - /** * Provides hooks for observing dependency lifecycle in Zookeeper. * Needs custom dependencies to be set in order to work. @@ -57,9 +57,10 @@ public class DependencyWatcherAutoConfiguration { return new DefaultDependencyPresenceOnStartupVerifier(); } - @Bean(initMethod = "registerDependencyRegistrationHooks", destroyMethod = "clearDependencyRegistrationHooks") + @Bean(destroyMethod = "clearDependencyRegistrationHooks") @ConditionalOnMissingBean - public DependencyRegistrationHookProvider dependencyWatcher(ServiceDiscovery serviceDiscovery, + public DependencyRegistrationHookProvider dependencyWatcher( + ZookeeperServiceDiscovery serviceDiscovery, DependencyPresenceOnStartupVerifier dependencyPresenceOnStartupVerifier, ZookeeperDependencies zookeeperDependencies) { return new DefaultDependencyWatcher(serviceDiscovery, diff --git a/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryISpec.groovy b/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryISpec.groovy index 2553776f..896c2146 100644 --- a/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryISpec.groovy +++ b/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryISpec.groovy @@ -38,7 +38,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.* @ContextConfiguration(classes = Config, loader = SpringApplicationContextLoader) @ActiveProfiles('ribbon') -@WebIntegrationTest +@WebIntegrationTest(randomPort = true) class ZookeeperDiscoveryISpec extends Specification { public static final String TEST_INSTANCE_NAME = 'testInstance' @@ -46,6 +46,7 @@ class ZookeeperDiscoveryISpec extends Specification { @Autowired TestRibbonClient testRibbonClient @Autowired WireMockServer wiremockServer @Autowired DiscoveryClient discoveryClient + @Autowired ZookeeperServiceDiscovery serviceDiscovery WireMock wireMock def setup() { @@ -73,7 +74,7 @@ class ZookeeperDiscoveryISpec extends Specification { def 'should properly find local instance'() { expect: - AddressProviderConfiguration.ipAddress == discoveryClient.localServiceInstance.host + serviceDiscovery.serviceInstance.address == discoveryClient.localServiceInstance.host } @Configuration diff --git a/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryWithDependenciesISpec.groovy b/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryWithDependenciesISpec.groovy index 0feab1c0..d7cbcee1 100644 --- a/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryWithDependenciesISpec.groovy +++ b/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryWithDependenciesISpec.groovy @@ -20,6 +20,7 @@ import com.github.tomakehurst.wiremock.client.WireMock import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.boot.test.SpringApplicationContextLoader +import org.springframework.boot.test.WebIntegrationTest import org.springframework.cloud.client.ServiceInstance import org.springframework.cloud.client.discovery.DiscoveryClient import org.springframework.cloud.client.discovery.EnableDiscoveryClient @@ -36,6 +37,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.* @ContextConfiguration(classes = Config, loader = SpringApplicationContextLoader) @ActiveProfiles('watcher') +@WebIntegrationTest(randomPort = true) class ZookeeperDiscoveryWithDependenciesISpec extends Specification { @Autowired TestRibbonClient testRibbonClient diff --git a/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcherSpringISpec.groovy b/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcherSpringISpec.groovy index 3245501a..7f604fc4 100644 --- a/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcherSpringISpec.groovy +++ b/spring-cloud-zookeeper-discovery/src/test/groovy/org/springframework/cloud/zookeeper/discovery/watcher/DefaultDependencyWatcherSpringISpec.groovy @@ -19,10 +19,14 @@ import org.apache.curator.framework.CuratorFramework import org.apache.curator.framework.CuratorFrameworkFactory import org.apache.curator.retry.ExponentialBackoffRetry import org.apache.curator.test.TestingServer -import org.apache.curator.x.discovery.* +import org.apache.curator.x.discovery.ServiceCache +import org.apache.curator.x.discovery.ServiceDiscoveryBuilder +import org.apache.curator.x.discovery.ServiceInstance +import org.apache.curator.x.discovery.UriSpec import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.boot.test.SpringApplicationContextLoader +import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceDiscovery import org.springframework.cloud.zookeeper.discovery.watcher.presence.DependencyPresenceOnStartupVerifier import org.springframework.cloud.zookeeper.discovery.watcher.presence.LogMissingDependencyChecker import org.springframework.context.annotation.Bean @@ -34,14 +38,16 @@ import org.springframework.util.SocketUtils import spock.lang.Specification import spock.util.concurrent.PollingConditions +import javax.annotation.PreDestroy + @ContextConfiguration(classes = Config, loader = SpringApplicationContextLoader) @ActiveProfiles('watcher') class DefaultDependencyWatcherSpringISpec extends Specification { @Autowired AssertableDependencyPresenceOnStartupVerifier dependencyPresenceOnStartupVerifier @Autowired AssertableDependencyWatcherListener dependencyWatcherListener - @Autowired ServiceDiscovery serviceDiscovery - @Autowired ServiceInstance serviceInstance + @Autowired + ZookeeperServiceDiscovery serviceDiscovery def 'should verify that presence of a dependency has been checked'() { expect: @@ -50,7 +56,7 @@ class DefaultDependencyWatcherSpringISpec extends Specification { def 'should verify that dependency watcher listener is successfully registered and operational'() { when: - serviceDiscovery.unregisterService(serviceInstance) + serviceDiscovery.serviceDiscovery.unregisterService(serviceDiscovery.serviceInstance) then: new PollingConditions().eventually { dependencyWatcherListener.dependencyState == DependencyState.DISCONNECTED @@ -71,24 +77,12 @@ class DefaultDependencyWatcherSpringISpec extends Specification { return new TestingServer(SocketUtils.findAvailableTcpPort()) } - @Bean - ServiceInstance serviceInstance() { - return ServiceInstance.builder().uriSpec(new UriSpec("{scheme}://{address}:{port}/")) - .address('anyUrl') - .port(10) - .name('testInstance') - .build() - } + @Bean + ZookeeperServiceDiscovery zookeeperServiceDiscovery() { + return new MyZookeeperServiceDiscovery(curatorFramework()) { - @Bean(initMethod = 'start', destroyMethod = 'close') - ServiceDiscovery serviceDiscovery() { - return ServiceDiscoveryBuilder - .builder(Void) - .basePath('/') - .client(curatorFramework()) - .thisInstance(serviceInstance()) - .build() - } + } + } @Bean(initMethod = 'start', destroyMethod = 'close') CuratorFramework curatorFramework() { @@ -107,6 +101,41 @@ class DefaultDependencyWatcherSpringISpec extends Specification { } + static class MyZookeeperServiceDiscovery extends ZookeeperServiceDiscovery { + MyZookeeperServiceDiscovery(CuratorFramework curator) { + super(curator, null, null) + build() + } + + @Override + void build() { + setPort(10) + + + def instance = ServiceInstance.builder().uriSpec(new UriSpec("{scheme}://{address}:{port}/")) + .address('anyUrl') + .port(10) + .name('testInstance') + .build() + getServiceInstanceRef().set(instance) + + + def discovery = ServiceDiscoveryBuilder + .builder(Void) + .basePath('/') + .client(getCurator()) + .thisInstance(instance) + .build() + getServiceDiscoveryRef().set(discovery) + discovery.start() + } + + @PreDestroy + void close() { + getServiceDiscoveryRef().get().close() + } + } + static class AssertableDependencyWatcherListener implements DependencyWatcherListener { DependencyState dependencyState = DependencyState.CONNECTED diff --git a/spring-cloud-zookeeper-sample/pom.xml b/spring-cloud-zookeeper-sample/pom.xml index 40fb7488..0f72bc38 100644 --- a/spring-cloud-zookeeper-sample/pom.xml +++ b/spring-cloud-zookeeper-sample/pom.xml @@ -43,11 +43,6 @@ spring-cloud-zookeeper-discovery test - - org.springframework.cloud - spring-cloud-zookeeper-bus - test - org.projectlombok lombok diff --git a/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java b/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java index f71d2dde..26b66e8f 100644 --- a/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java +++ b/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java @@ -3,16 +3,13 @@ package org.springframework.cloud.zookeeper.sample; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.bind.RelaxedPropertyResolver; -import org.springframework.cloud.bus.jackson.SubtypeModule; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; -import org.springframework.cloud.zookeeper.bus.SimpleRemoteEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestMapping; @@ -27,18 +24,19 @@ import org.springframework.web.bind.annotation.RestController; @EnableDiscoveryClient @RestController @Slf4j -public class SampleApplication implements ApplicationListener { +public class SampleApplication { - public static final String CLIENT_NAME = "testZookeeperApp"; + @Value("${spring.application.name:testZookeeperApp}") + private String appName; @Autowired - LoadBalancerClient loadBalancer; + private LoadBalancerClient loadBalancer; @Autowired - Environment env; + private Environment env; @Autowired(required = false) - RelaxedPropertyResolver resolver; + private RelaxedPropertyResolver resolver; public static void main(String[] args) { SpringApplication.run(SampleApplication.class, args); @@ -46,7 +44,7 @@ public class SampleApplication implements ApplicationListener @RequestMapping("/") public ServiceInstance lb() { - return loadBalancer.choose(CLIENT_NAME); + return loadBalancer.choose(appName); } @RequestMapping("/myenv") @@ -54,14 +52,4 @@ public class SampleApplication implements ApplicationListener String property = new RelaxedPropertyResolver(env).getProperty(prop, "Not Found"); return property; } - - @Bean - public SubtypeModule sampleSubtypeModule() { - return new SubtypeModule(SimpleRemoteEvent.class); - } - - @Override - public void onApplicationEvent(SimpleRemoteEvent event) { - log.info("Received event: {}", event); - } }