diff --git a/README.adoc b/README.adoc index 48042760..a2a7826d 100644 --- a/README.adoc +++ b/README.adoc @@ -95,11 +95,11 @@ a modified file in the correct place. Just commit it and push the change. If you don't have an IDE preference we would recommend that you use http://www.springsource.com/developer/sts[Spring Tools Suite] or http://eclipse.org[Eclipse] when working with the code. We use the -http://eclipse.org/m2e/[m2eclipe] eclipse plugin for maven support. Other IDEs and tools +http://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools should also work without issue as long as they use Maven 3.3.3 or better. ==== Importing into eclipse with m2eclipse -We recommend the http://eclipse.org/m2e/[m2eclipe] eclipse plugin when working with +We recommend the http://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with eclipse. If you don't already have m2eclipse installed it is available from the "eclipse marketplace". 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 dff20400..ad79cc3c 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 @@ -84,6 +84,9 @@ public class ZookeeperDiscoveryClient implements DiscoveryClient { public List getInstances( final String serviceId) { try { + if (this.serviceDiscovery.getServiceDiscovery() == null) { + return Collections.EMPTY_LIST; + } String serviceIdToQuery = getServiceIdToQuery(serviceId); Collection> zkInstances = this.serviceDiscovery .getServiceDiscovery().queryForInstances(serviceIdToQuery); 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 daf3e7af..3234fec6 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 @@ -43,6 +43,7 @@ public class ZookeeperLifecycle extends AbstractDiscoveryLifecycle { this.serviceDiscovery.setPort(this.properties.getInstancePort()); this.serviceDiscovery.build(); } + this.serviceDiscovery.buildServiceDiscovery(); } @Override @@ -91,6 +92,7 @@ public class ZookeeperLifecycle extends AbstractDiscoveryLifecycle { protected void setConfiguredPort(int port) { this.serviceDiscovery.setPort(port); this.serviceDiscovery.build(); + this.serviceDiscovery.buildServiceDiscovery(); } @Override diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java index 4393f0ac..7bbae49e 100644 --- a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java @@ -21,14 +21,14 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.AbstractServerList; - import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceInstance; import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies; import org.springframework.util.StringUtils; +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractServerList; + import static org.springframework.util.ReflectionUtils.rethrowRuntimeException; /** @@ -76,6 +76,9 @@ public class ZookeeperServerList extends AbstractServerList { @SuppressWarnings("unchecked") private List getServers() { try { + if (this.serviceDiscovery == null) { + return Collections.EMPTY_LIST; + } Collection> instances = this.serviceDiscovery .queryForInstances(this.serviceId); if (instances == null || instances.isEmpty()) { 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 index 11c6fa31..53ec0965 100644 --- 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 @@ -90,9 +90,13 @@ public class ZookeeperServiceDiscovery implements ApplicationContextAware { this.context = context; } + /** + * Builds Service Instance - needs to be used when you want to register your application + * in Zookeeper + */ public void build() { if (this.built.compareAndSet(false, true)) { - if (this.port.get() <= 0) { + if (this.port.get() <= 0 && this.properties.isRegister()) { throw new IllegalStateException("Cannot create instance whose port is not greater than 0"); } String host = this.properties.getInstanceHost(); @@ -100,13 +104,22 @@ public class ZookeeperServiceDiscovery implements ApplicationContextAware { throw new IllegalStateException("instanceHost must not be empty"); } UriSpec uriSpec = new UriSpec(this.properties.getUriSpec()); - configureServiceInstance(this.serviceInstance, this.appName, - this.context, this.port, host, uriSpec); - configureServiceDiscovery(this.serviceDiscovery, this.curator, this.properties, - this.instanceSerializer, this.serviceInstance); + if (this.properties.isRegister()) { + configureServiceInstance(this.serviceInstance, this.appName, + this.context, this.port, host, uriSpec); + } } } + /** + * Builds Service Discovery - needs to be used if you want to use Zookeeper as a client application. + * You don't have to register in Zookeeper to use Service Discovery. + */ + public void buildServiceDiscovery() { + configureServiceDiscovery(this.serviceDiscovery, this.curator, this.properties, + this.instanceSerializer, this.serviceInstance); + } + /** * One can override this method to provide custom way of registering a service * instance (e.g. when no payload is required). diff --git a/spring-cloud-zookeeper-discovery/src/test/java/org/springframework/cloud/zookeeper/discovery/issues/issue91/Issue91Tests.java b/spring-cloud-zookeeper-discovery/src/test/java/org/springframework/cloud/zookeeper/discovery/issues/issue91/Issue91Tests.java new file mode 100644 index 00000000..abc4a08d --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/test/java/org/springframework/cloud/zookeeper/discovery/issues/issue91/Issue91Tests.java @@ -0,0 +1,101 @@ +package org.springframework.cloud.zookeeper.discovery.issues.issue91; + +import org.apache.curator.test.TestingServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.SocketUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import com.jayway.awaitility.Awaitility; + +import static org.assertj.core.api.BDDAssertions.then; + +/** + * @author Marcin Grzejszczak + */ +public class Issue91Tests { + + TestingServer server; + String connectionString; + + @Before + public void setup() throws Exception { + this.server = new TestingServer(SocketUtils.findAvailableTcpPort()); + this.connectionString = "--spring.cloud.zookeeper.connectString=" + this.server.getConnectString(); + } + + @After + public void cleanup() throws Exception { + this.server.close(); + } + + @Test + public void should_work_when_using_web_client_without_the_web_environment() + throws Exception { + SpringApplication producerApp = new SpringApplication(HelloProducer.class); + producerApp.setWebEnvironment(true); + SpringApplication clientApplication = new SpringApplication(HelloClient.class); + clientApplication.setWebEnvironment(false); + + try (ConfigurableApplicationContext producerContext = producerApp.run(this.connectionString, "--server.port=0", + "--spring.application.name=hello-world")) { + try (final ConfigurableApplicationContext context = clientApplication.run(this.connectionString, + "--spring.cloud.zookeeper.discovery.register=false")) { + Awaitility.await().until(new Runnable() { + @Override public void run() { + try { + HelloClient bean = context.getBean(HelloClient.class); + then(bean.discoveryClient.getServices()).isNotEmpty(); + then(bean.discoveryClient.getInstances("hello-world")).isNotEmpty(); + String string = bean.restTemplate.getForObject("http://hello-world/", String.class); + then(string).isEqualTo("foo"); + } catch (IllegalStateException e) { + throw new AssertionError(e); + } + } + }); + } + } + } +} + +@EnableAutoConfiguration(exclude = {EndpointMBeanExportAutoConfiguration.class, + JmxAutoConfiguration.class}) +@EnableDiscoveryClient +@Configuration +class HelloClient { + @LoadBalanced @Bean RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Autowired DiscoveryClient discoveryClient; + + @Autowired RestTemplate restTemplate; +} + +@EnableAutoConfiguration(exclude = {EndpointMBeanExportAutoConfiguration.class, + JmxAutoConfiguration.class}) +@EnableDiscoveryClient +@RestController +class HelloProducer { + + @RequestMapping("/") + public String foo() { + return "foo"; + } + +} \ No newline at end of file