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 +