From 21eb52fa2748020be6f8a7138ad2792c4e7231d9 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 29 Sep 2014 10:52:37 +0100 Subject: [PATCH] Ensure server port is registered late enough with Eureka server Because we were using Lifecycle to kick off the eureka registration the local server port wasn't available yet. The change is to use an ApplicationListener and listen for the event that contains the container with its port instead. Fixes gh-15 --- Guardfile | 11 +++ spring-cloud-netflix-core/pom.xml | 5 ++ .../eureka/EurekaClientConfiguration.java | 39 ++++++--- src/main/adoc/spring-cloud-netflix.adoc | 80 +++++++++++++++++++ 4 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 Guardfile create mode 100644 src/main/adoc/spring-cloud-netflix.adoc diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..826e7679 --- /dev/null +++ b/Guardfile @@ -0,0 +1,11 @@ +require 'asciidoctor' +require 'erb' + +options = {:mkdirs => true, :safe => :unsafe, :attributes => 'linkcss'} + +guard 'shell' do + watch(/^[A-Za-z].*\.adoc$/) {|m| + Asciidoctor.render_file('src/main/adoc/README.adoc', options.merge(:to_file => './README.md')) + Asciidoctor.render_file('src/main/adoc/spring-cloud-netflix.adoc', options.merge(:to_dir => 'target/docs')) + } +end diff --git a/spring-cloud-netflix-core/pom.xml b/spring-cloud-netflix-core/pom.xml index e04889a5..91e7bb5b 100644 --- a/spring-cloud-netflix-core/pom.xml +++ b/spring-cloud-netflix-core/pom.xml @@ -108,6 +108,11 @@ spring-boot-starter-test test + + org.neo4j + neo4j-cypher-compiler-2.1 + 2.1.2 + diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfiguration.java index f9eb86f7..62909820 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.netflix.servo.ServoMetricReader; import org.springframework.context.ApplicationListener; @@ -34,7 +35,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.Ordered; import com.netflix.appinfo.ApplicationInfoManager; @@ -54,8 +54,7 @@ import com.netflix.discovery.EurekaClientConfig; EurekaInstanceConfigBean.class }) @ConditionalOnClass(EurekaClientConfig.class) @ConditionalOnExpression("${eureka.client.enabled:true}") -public class EurekaClientConfiguration implements - ApplicationListener, SmartLifecycle, Ordered { +public class EurekaClientConfiguration implements SmartLifecycle, Ordered { private static final Logger logger = LoggerFactory .getLogger(EurekaClientConfiguration.class); @@ -64,19 +63,14 @@ public class EurekaClientConfiguration implements private int order = 0; + private int port = 0; + @Autowired private EurekaClientConfigBean clientConfig; @Autowired private EurekaInstanceConfigBean instanceConfig; - @Override - public void onApplicationEvent(ContextRefreshedEvent event) { - logger.info("Registering application {} with eureka with status UP", - instanceConfig.getAppname()); - ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.UP); - } - @PreDestroy public void close() { logger.info("Removing application {} from eureka", instanceConfig.getAppname()); @@ -85,11 +79,20 @@ public class EurekaClientConfiguration implements @Override public void start() { - DiscoveryManager.getInstance().initComponent(instanceConfig, clientConfig); + if (port != 0) { + instanceConfig.setNonSecurePort(port); + DiscoveryManager.getInstance().initComponent(instanceConfig, clientConfig); + logger.info("Registering application {} with eureka with status UP", + instanceConfig.getAppname()); + ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.UP); + } } @Override public void stop() { + logger.info("Unregistering application {} with eureka with status OUT_OF_SERVICE", + instanceConfig.getAppname()); + ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.OUT_OF_SERVICE); running = false; } @@ -134,4 +137,18 @@ public class EurekaClientConfiguration implements new ServoMetricReader(server), config); } + @Bean + protected ApplicationListener containerPortInitializer() { + return new ApplicationListener() { + + @Override + public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) { + // TODO: take SSL into account when Spring Boot 1.2 is available + EurekaClientConfiguration.this.port = event.getEmbeddedServletContainer() + .getPort(); + EurekaClientConfiguration.this.start(); + } + }; + } + } diff --git a/src/main/adoc/spring-cloud-netflix.adoc b/src/main/adoc/spring-cloud-netflix.adoc new file mode 100644 index 00000000..5d55f739 --- /dev/null +++ b/src/main/adoc/spring-cloud-netflix.adoc @@ -0,0 +1,80 @@ += Spring Cloud Netflix + +This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration +and binding to the Spring Environment and other Spring programming model idioms. + +== Service Discovery: Eureka Clients + +Example eureka client: + +``` +@Configuration +@ComponentScan +@EnableAutoConfiguration +@EnableEurekaClient +@RestController +public class Application { + + @RequestMapping("/") + public String home() { + return "Hello world"; + } + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} + +``` + +(i.e. utterly normal Spring Boot app). Configuration is required to locate the Eureka server. Example: + +``` +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8080/v2/ + default.defaultZone: http://localhost:8080/v2/ +``` + +The default application name, virtual host and non-secure port are taken from the `Environment` is +`${spring.application.name}`, `${spring.application.name}.mydomain.net` and `${server.port}` respectively. + +== Service Discovery: Eureka Server + +Example eureka server: + +``` +@Configuration +@EnableAutoConfiguration +@EnableEurekaServer +public class Application { + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} + +``` + +The server has a home page with a UI, and HTTP API endpoints per the +normal Eureka functionality under `/v2/*`. + +Eureka (apache -> tomcat) see https://github.com/cfregly/fluxcapacitor/wiki/NetflixOSS-FAQ#eureka-service-discovery-load-balancer[flux capacitor] and https://groups.google.com/forum/?fromgroups#!topic/eureka_netflix/g3p2r7gHnN0[google group discussion]. + +== Circuit Breaker: Hystrix Clients + +== Circuit Breaker: Hystrix Dashboard + +=== Turbine + +== Declarative REST Client: Feign + +== Client Side Load Balancer: Ribbon + +== External Configuration: Archaius + +== Router and Filter: Zuul +