├── README.md
├── code
├── config-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── ConfigServiceApplication.java
│ │ └── resources
│ │ │ └── application.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── ConfigServiceApplicationTests.java
├── eureka-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── EurekaServiceApplication.java
│ │ └── resources
│ │ │ └── bootstrap.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── EurekaServiceApplicationTests.java
├── hystrix-dashboard
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── HystrixDashboardApplication.java
│ │ └── resources
│ │ │ └── bootstrap.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── HystrixDashboardApplicationTests.java
├── reservation-client
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── ReservationClientApplication.java
│ │ └── resources
│ │ │ └── bootstrap.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── ReservationClientApplicationTests.java
├── reservation-service
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── ReservationServiceApplication.java
│ │ └── resources
│ │ │ ├── banner.txt
│ │ │ └── bootstrap.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── ReservationServiceApplicationTests.java
└── zipkin-service
│ ├── pom.xml
│ └── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── ZipkinServiceApplication.java
│ └── resources
│ │ └── bootstrap.properties
│ └── test
│ └── java
│ └── com
│ └── example
│ └── ZipkinServiceApplicationTests.java
└── images
├── git-config-repo.png
├── graphite.png
├── hystrix-dashboard.png
├── spring-cloud-netflix-eureka.png
└── zipkin-traces.png
/README.md:
--------------------------------------------------------------------------------
1 | # Microservices
2 | by [Josh Long](http://twitter.com/starbuxman)
3 |
4 |
5 | ## Survival is Not Mandatory
6 | > It is not necessary to change. Survival is not mandatory. -W. Edwards Deming
7 |
8 | In today's hypercompetitive international market, _all_ businesses are software businesses (or they're quickly replaced by software businesses) and speed-to-market is a differentiator, sometimes _the only_ one! Organizations look for small batches of work that they can move from concept to production, quickly. These small batches of work demand fewer people to finish, are easier to iterate on, and can be moved to production independently; they are microservices.
9 |
10 | It is critical that an organization be prepared to address the complexities of standing up new services and to address the complexities implied by moving to a distributed systems world.
11 |
12 | ### Moving Beyond the Wiki Page: "500 Easy Steps to Production"
13 |
14 | Microservices are APIs. How quickly can you standup a new service? Microframeworks like [Spring Boot](http://start.spring.io), [Grails](http://grails.org), [Dropwizard](http://dropwizard.io), [Play framework](https://www.playframework.com/), [Wildfly Swarm](http://wildfly.org/swarm/) and [Payara Micro](http://www.payara.fish/payara_micro) are optimized for quickly standing up REST services with a minimum of fuss. Extra points go to technologies that make it easy to build smart, self-describing _hypermedia_ APIs as Spring Boot does with Spring HATEOAS.
15 |
16 | ### You Can't Fix What You Can't Measure
17 | A microservice must support visibility and transparency, indicators of its own state and of system state, in a single-pane-of-glass experience. The [DropWizard Metrics library](http://www.dropwizard.io) is one of the more popular approaches to capturing application metrics (gauges, meters, histograms, and counters). [Spring Boot's _Actuator_](http://start.spring.io) module provides deep integration with the DropWizard Metrics library, and supports exposing health endpoints, environment information, endpoint mapping information, request logs, and more. Time-series databases like Statsd, Graphite, InfluxDB and OpenTSDB support visualization and processing of metrics. DropWizard Metrics and Spring Boot Actuator can transparently export collected metrics to these time-series databases.
18 |
19 |
20 | ```java
21 | @SpringBootApplication
22 | public class DemoApplication {
23 |
24 | public static void main(String args[]) {
25 | SpringApplication.run(DemoApplication.class, args);
26 | }
27 |
28 | @Bean
29 | GraphiteReporter graphite(@Value("${graphite.prefix}") String prefix,
30 | @Value("${graphite.url}") URL url,
31 | @Value("${graphite.port}") int port,
32 | MetricRegistry registry) {
33 |
34 | GraphiteReporter reporter = GraphiteReporter.forRegistry(registry)
35 | .prefixedWith(prefix)
36 | .build(new Graphite(url.getHost(), port));
37 | reporter.start(1, TimeUnit.SECONDS);
38 | return reporter;
39 | }
40 | }
41 |
42 | @RestController
43 | class FulfillmentRestController {
44 |
45 | @Autowired
46 | private CounterService counterService;
47 |
48 | @RequestMapping("/customers/{customerId}/fulfillment")
49 | Fulfillment fulfill(@PathVariable long customerId) {
50 | // ..
51 | counterService.increment("meter.customers-fulfilled");
52 | // ..
53 | }
54 | }
55 | ```
56 |
57 |
58 |
59 |
60 | Log multiplexers like Logstash or Cloud Foundry's Loggregator funnel the logs from application instances and ship them to downstream log analysis tools like ElasticSearch, Splunk, or PaperTrail.
61 |
62 | Getting all of this out of the box is a good start, but not enough. There is often much more to be done before a service can get to production. Spring Boot uses a mechanism called auto-configuration that lets developers codify things - identity provider integrations, connection pools, frameworks, auditing infrastructure, literally _anything_ - and have it stood up as part of the Spring Boot application just by being on the CLASSPATH _if_ all the conditions stipulated by the auto-configuration are met! These conditions can be anything, and Spring Boot ships with many common and reusable conditions: is a library on the `CLASSPATH`? Is a bean of a certain type defined (or not defined)? Is an environment property specified? Starting a new service need not be more complex than a `public static void main` entry-point and a library on the `CLASSPATH` if you use the right technology.
63 |
64 | ### Centralized Configuration
65 | The [12 Factor manifesto](http://12factor.net/) provides a set of guidelines for building applications with good, clean cloud hygiene. One tenant is that environment specific configuration should live external to the application itself. It might live in environment variables, `-D` arguments, externalized `.properties`, and `.yml` files, or any other place, so long as the application code itself need not be recompiled. Dropwizard, Spring Boot, [Apache Commons Configuration](http://commons.apache.org/proper/commons-configuration/) and others support this foundational requirement. However, this approach fails a few key use-cases: how do you change configuration centrally and propagate those changes? How do you support symmetric encryption and decryption of things like connection credentials? How do you support _feature flags_ which toggle configuration values at runtime, without restarting the process?
66 |
67 | [Spring Cloud](http://start.spring.io) provides the Spring Cloud Config Server which stands up a REST API in front of a version controlled repository of configuration files, and Spring Cloud provides support for using Apache Zookeeper and [Hashicorpo Consul](https://www.consul.io) as configuration sources. Spring Cloud provides various clients for all of these so that all properties, whether they come from the Config Server, Consul, a `-D` argument or an environment variable, work the same way for a Spring client. Netflix provides a solution called [Archaius](https://github.com/Netflix/archaius) which acts as a client to a pollable configuration source. This is a bit too low-level for many organizations and lacks a supported, open-source configuration source counterpart, but Spring Cloud bridges the Archaius properties with Spring's, too.
68 |
69 |
70 | *the Config Server*
71 |
72 | ```properties
73 | # application.properties
74 | spring.cloud.config.server.git.uri=https://github.com/joshlong/my-config.git
75 | server.port=8888
76 | ```
77 |
78 | ```java
79 | @EnableConfigServer
80 | @SpringBootApplication
81 | public class ConfigServiceApplication {
82 |
83 | public static void main(String[] args) {
84 | SpringApplication.run(ConfigServiceApplication.class, args);
85 | }
86 | }
87 | ```
88 |
89 | *the Config Client*
90 |
91 | ```properties
92 | # application.properties
93 | spring.cloud.config.uri=http://localhost:8888
94 | spring.application.name=message-client
95 | # will read https://github.com/joshlong/my-config/message-client.properties
96 | ```
97 |
98 | ```java
99 | @SpringBootApplication
100 | public class ConfigClientApplication {
101 |
102 | public static void main(String[] args) {
103 | SpringApplication.run(ConfigClientApplication.class, args);
104 | }
105 | }
106 |
107 | // supports dynamic re-configuration:
108 | // curl -d{} http://localhost:8000/refresh
109 | @RestController
110 | @RefreshScope
111 | class MessageRestController {
112 |
113 | @Value("${message}")
114 | private String message;
115 |
116 | @RequestMapping("/message")
117 | String read() {
118 | return this.message;
119 | }
120 | }
121 | ```
122 |
123 | ### Service Registration and Discovery
124 | DNS is sometimes a poor fit for intra-service communication. DNS benefits from layers of caching and time-to-liveness that works against services in a dynamic cloud environment. In most cloud environments, DNS resolution requires a trip out of the platform to the router and then back again, introducing latency. DNS doesn't provide a way to answer the question: is the service I am trying to call still alive and responding? A request to such a fallen service will block until the service responds, unless the client specifies a timeout (which it should!). DNS is often paired with load-balancers, but third-party load-balancers are not sophisticated things: they may support round-robin load-balancing, or even availability-zone aware load-balancing, but may not be able to accomodate business-logic specific routing like routing a request with an OAuth token to a specific node, or routing requests to nodes collocated with data, etc.) It's important to decouple the client from the location of the service, but DNS might be a poor fit. A little bit of indirection is required. A service registry provides that indirection. A service registry is a phonebook, letting clients look up services by their logical name. There are many such service registries out there. [Netflix's Eureka](https://github.com/Netflix/eureka), [Apache Zookeeper](https://zookeeper.apache.org/), and [Hashicorp Consul](https://www.consul.io/) are three good examples. Spring Cloud's `DiscoveryClient` abstraction provides a convenient client-side API implementations for working with service registries.
125 |
126 |
127 |
128 | ```java
129 | @Autowired
130 | public void enumerateServiceInstances(DiscoveryClient client){
131 | client.getInstances("reservation-service")
132 | .forEach( si -> System.out.println( si.getHost() + ":" + si.getPort() ));
133 | }
134 |
135 | ```
136 |
137 | ### Client Side Load Balancing
138 | A big benefit of using a service registry is client-side load-balancing. Client-side load-balancing let's the client pick from among the registered instances of a given service - if there are 10 or a thousand they're all discovered through the registry - and then choose from among the candidate instances which one to route requests to. The client can programmatically decide based on whatever criteria it likes - capacity, round-robin, cloud-provider availability-zone awareness, multi-tenancy, etc., to which node a request should be sent. Netlfix provide a great client-side load-balancer called [Ribbon](https://github.com/Netflix/ribbon). Spring Cloud readily integrates Ribbon and it is automatically in play at all layers of the framework, whether you're using the `RestTemplate`, declarative REST clients powered by Netflix's Feign, or the Zuul microproxy.
139 |
140 | ```java
141 | @EnableDiscoveryClient
142 | @SpringBootApplication
143 | public class ReservationClientApplication {
144 |
145 | @Bean
146 | @LoadBalanced // lets us use service registry service IDs as hosts
147 | RestTemplate restTemplate() {
148 | return new RestTemplate();
149 | }
150 |
151 | public static void main(String[] args) {
152 | SpringApplication.run(ReservationClientApplication.class, args);
153 | }
154 | }
155 |
156 | @RestController
157 | class ApiClientRestController {
158 |
159 | @Autowired
160 | private RestTemplate restTemplate;
161 |
162 | @RequestMapping(method = RequestMethod.GET, value = "/reservations/names")
163 | public Collection names() {
164 |
165 | ResponseEntity responseEntity =
166 | restTemplate.exchange("http://reservation-service/reservations",
167 | HttpMethod.GET, null, JsonNode.class);
168 | // ...
169 | }
170 | }
171 | ```
172 |
173 | ### Edge Services: Micro Proxies and API Gateways
174 |
175 | Client-side load-balancing works for intra-service communication, usually behind a firewall. External clients - iPhones, HTML5 clients, Android clients, etc. - have client-specific security, payload and protocol requirements. An edge service may proxy or mediate requests and replies between the system of services and the clients. An edge service is exposed via DNS and forwards requests using service discovery. Edge services are intermediaries and an ideal place to insert API translation or protocol translation. HTML5 clients, for example, exist in a sandbox and must issue requests to the same origin host and port. HTML5 clients may reach across their origin server to other resources so long as those resources have been configured to support CORS. This requirement is untenable and unscalable as you add more clients connecting to more microservices. A microproxy, like [Netflix's Zuul](https://github.com/Netflix/zuul) forwards all requests at the edge service to microservices, often to those it discovers in a service registry. If your application is an HTML5 application it might be enough to standup a microproxy, insert HTTP BASIC or OAuth security, support HTTPS, and be done with it.
176 |
177 | Sometimes the client needs a coarser-grained view of the data coming from the services. This implies API translation. An edge service, stood up using something like Spring Boot, might use Reactive programming technologies like [Netflix's RxJava](https://github.com/ReactiveX/RxJava), Typesafe's [Akka](http://Akka.io), [RedHat's Vert.x](http://vertx.io/), and [Pivotal's Reactor](http://projectreactor.io/) to compose requests and transformations across multiple services into a single response. Indeed, all of these technologies implement a common API called the [reactive streams API](http://www.reactive-streams.org/) because this subset of problems is so common.
178 |
179 |
180 | An edge service is the last line of defense from the outside world and must be tolerant to service outages and failure.
181 |
182 | ```java
183 | @EnableZuulProxy
184 | @EnableCircuitBreaker
185 | @EnableDiscoveryClient
186 | @SpringBootApplication
187 | public class EdgeServiceApplication {
188 |
189 | public static void main(String[] args) {
190 | SpringApplication.run(EdgeServiceApplication.class, args);
191 | }
192 | }
193 |
194 | @RestController
195 | class TradesStreamingApiGateway {
196 |
197 | @Autowired
198 | private MarketService marketService;
199 |
200 | @RequestMethod(method=HttpMethod.GET, value = "/market/trades")
201 | public SseEmitter trades() {
202 | SseEmitter sseEmitter = new SseEmitter();
203 | Observable trades = marketService.observeTrades(); // RxJava
204 | trades.subscribe( value -> publishNewTrade(sseEmitter, value),
205 | sseEmitter::completeWithError,
206 | sseEmitter::complete
207 | );
208 | return sseEmitter;
209 | }
210 |
211 | private void publishNewTrade(SseEmitter sseEmitter, Trade t) {
212 | try {
213 | sseEmitter.send(t);
214 | } catch (IOException e) {
215 | e.printStackTrace();
216 | }
217 | }
218 | }
219 | ```
220 |
221 |
222 | ### Clustering Primitives
223 | In a complex distributed systems, there are many actors with many roles to play. Cluster coordination and cluster consensus is one of the most difficult problems to solve. How do you handle leadership election, active/passive handoff or global locks? Thankfully, many technologies provide the primitives required to support this sort of coordination, including Apache Zookeeper, [Redis](http://redis.io) and [Hazelcast](https://hazelcast.com/). [Spring Cloud's Cluster](http://start.spring.io) support provides a clean integration with all of these technologies.
224 |
225 | In the following example, we've configured a component to change its state whenever Spring Cloud Cluster emits a `OnGrantedEvent` or a `OnRevokedEvent`, which it'll do when it the underlying coordination technology promotes and demotes a leader node.
226 |
227 | ```java
228 | @Component
229 | class LeadershipApplicationListener {
230 |
231 | @EventListener
232 | public void leadershipGranted(OnGrantedEvent evt){
233 | // ..
234 | }
235 |
236 | @EventListener
237 | public void leadershipRevoked(OnRevokedEvent evt){
238 | // ..
239 | }
240 | }
241 | ```
242 |
243 | ### Messaging, CQRS and Stream Processing
244 | When you move into the world of microservices, state synchronization becomes more difficult. The reflex of the experienced architect might be to reach for distributed transactions, a la JTA. Ignore this urge at all costs. Transactions are a stop-the-world approach to state synchronization and slow the system as a whole; the worst possible outcome in a distributed system. Instead, services today use eventual consistency through messaging to ensure that state eventually reflects the correct system worldview. REST is a fine technology for _reading_ data but it doesn't provide any guarantees about the propagation and eventual processing of a transaction. Actor systems like [Typesafe Akka](http://akka.io) and message brokers like [Apache ActiveMQ](http://activemq.apache.org/), [Apache Kafka](http://kafka.apache.org/), [RabbitMQ](http://rabbitmq.com) or [even Redis](http://redis.io/) have become the norm. Akka provides a supervisory system guarantees a message will be processed at-least once. If you're using messaging, there are many APIs that can simplify the chore including [Apache Camel](http://camel.apache.org/), [Spring Integration](http://projects.spring.io/spring-integration/) and - at a higher abstraction level - Spring Cloud Stream. Using messaging for writes and use REST for reads optimizes reads separately from writes. The [Command Query Responsibility Segregation](http://martinfowler.com/bliki/CQRS.html), or CQRS, design pattern specifically describes this approach.
245 |
246 | ```java
247 |
248 | @EnableBinding(CrmChannels.class)
249 | @SpringBootApplication
250 | public class ProductsEdgeService {
251 |
252 | public static void main(String[] args) {
253 | SpringApplication.run(ReservationClientApplication.class, args);
254 | }
255 | }
256 |
257 | interface CrmChannels {
258 |
259 | @Output
260 | MessageChannel orders();
261 |
262 | @Output
263 | MessageChannel customers();
264 |
265 | @Output
266 | MessageChannel products();
267 | }
268 |
269 |
270 | @RestController
271 | @RequestMapping("/products")
272 | class ProductsApiGatewayRestController {
273 |
274 | @Autowired
275 | private MessageChannel products;
276 |
277 | @RequestMapping(method = RequestMethod.POST)
278 | public void write(@RequestBody Product p) {
279 | Message msg = MessageBuilder.withPayload (p).build();
280 | products.send(msg);
281 | }
282 | }
283 | ```
284 |
285 | ```java
286 | @EnableBinding(Sink.class)
287 | public class ProductHandler {
288 |
289 | @Autowired
290 | private ProductRepository products;
291 |
292 | @StreamListener(Sink.INPUT)
293 | public void handle(Product p) {
294 | products.addProduct(vote);
295 | }
296 | }
297 | ```
298 |
299 | ### Circuit Breakers
300 | Circuit breakers, like [Netflix's Hystrix](https://github.com/Netflix/Hystrix) or [JRugged](https://github.com/Comcast/jrugged), help prevent a downstream service from being overwhelmed and help isolate failures, permitting downstream services time to recover. Systems are complex, living things. Failure in one system can trigger a domino effect across other systems if care isn't taken to isolate them. A circuit breaker will slowly attempt to reintroduce traffic. Circuit breakers represent connections between services in a system; it is important to monitor them. Hystrix provides a dashboard for its circuits. Wildfly Swarm has support for using Hystrix. The [Play framework](https://www.playframework.com/) provides support for circuit breakers. Spring Cloud also has deep support for Hystrix and the dashboard, as well as multiplexing the server-sent event streams emitted from different components into a single stream using Spring Cloud Turbine.
301 |
302 | ```java
303 | @RestController
304 | class EdgeService {
305 |
306 | public Collection fallback(){
307 | // ..
308 | }
309 |
310 | // the dashboard will show a circuit named 'reservation-service'
311 | @HystrixCommand(fallbackMethod = "fallback")
312 | @RequestMapping(method = RequestMethod.GET, value = "/names")
313 | public Collection names() {
314 | // ..
315 | }
316 | }
317 | ```
318 |
319 | Here is the dashboard:
320 |
321 |
322 |
323 | ### Distributed Tracing
324 | It is difficult to reason about a microservice system with REST-based, messaging-based and proxy-based egress and ingress points. How do you trace (correllate) requests across a series of services and understand where something has failed? This is difficult enough a challenge _without_ a sufficient upfront investment in a tracing strategy. Google introduced their distributed tracing strategy in their [Dapper paper](http://research.google.com/pubs/pub36356.html). [Apache HTRace](http://incubator.apache.org/projects/htrace.html) is a Dapper-inspired alternative.
325 | [Twitter's Zipkin](https://blog.twitter.com/2012/distributed-systems-tracing-with-zipkin) is another Dapper-inspired tracing system. It provides the trace collection infrastructure and a UI in which you can view waterfall graphs of calls across services along with their timings and trace-specific information. Spring Cloud Sleuth provides an abstraction around the concepts of distributed tracing. Spring Cloud Sleuth automatically traces common ingress and egress points in the system. Spring Cloud Zipkin integrates Twitter Zipkin in terms of the Spring Cloud Sleuth abstraction.
326 |
327 |
328 |
329 |
330 | ### Single Sign-On and Security
331 |
332 | Security is hard. In a distributed system, it is critical to ascertain the providence and authenticity of a request in a consistent way across all services. OAuth and OpenID Connect are very popular on the open web and SAML rules the enterprise. OAuth 2 provides explicit integration with SAML. API gateway tools like [Apigee](http://apigee.com/) and SaaS identity providers like [Stormpath](https://stormpath.com/) can act as a security hub, exposing OAuth (for example) and connecting the backend to more traditional identity providers like ActiveDirectory, SiteMinder, or LDAP. Finally, [Spring Security OAuth](http://projects.spring.io/spring-security-oauth/) provides an identity server which can then talk to any identity provider in the backend. Whatever your choice of identity provider, it should be trivial to protect services based on some sort of token. Spring Cloud Security makes short work of protecting any REST API with tokens from _any_ OAuth 2 provider - Google, Facebook, the Spring Security OAuth server, Stormpath, etc. [Apache Shiro](http://shiro.apache.org/) can also act as an OAuth client using the Scribe OAuth client.
333 |
334 |
335 | ### A Cloud Native Architecture is an Agile Architecture
336 |
337 | Instead, systems must optimize for time-to-remediation; when a service goes down, how quickly can the system replace it? If time-to-remediation is 0 seconds, then the system is (apparently) highly available 100% of the time. The apparent appearance of the system is the same in a single-node service that is 100% highly available, but it has _profound_ impacts on the architecture of the system. The patterns we've looked at in this refcard support building systems that are tolerant of failure and service topology changes common in a dynamic cloud environment. Remember: the goal here is to achieve velocity, and to waste as little time as possible on non-functional requirements. Automation at the platform and application tiers support this velocity. Embracing one without the other only invites undifferentiating complexity into an architecture and defeats the purpose of moving to this architecture in the first place.
338 |
--------------------------------------------------------------------------------
/code/config-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | config-service
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | config-service
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.3.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-config-server
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-test
35 | test
36 |
37 |
38 |
39 |
40 |
41 |
42 | org.springframework.cloud
43 | spring-cloud-dependencies
44 | Brixton.RC1
45 | pom
46 | import
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-maven-plugin
56 |
57 |
58 |
59 |
60 |
61 |
62 | spring-snapshots
63 | Spring Snapshots
64 | https://repo.spring.io/snapshot
65 |
66 | true
67 |
68 |
69 |
70 | spring-milestones
71 | Spring Milestones
72 | https://repo.spring.io/milestone
73 |
74 | false
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/code/config-service/src/main/java/com/example/ConfigServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.config.server.EnableConfigServer;
6 |
7 | @EnableConfigServer
8 | @SpringBootApplication
9 | public class ConfigServiceApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(ConfigServiceApplication.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/code/config-service/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.cloud.config.server.git.uri=${HOME}/Desktop/config
2 | server.port=8888
--------------------------------------------------------------------------------
/code/config-service/src/test/java/com/example/ConfigServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 |
8 | @RunWith(SpringJUnit4ClassRunner.class)
9 | @SpringApplicationConfiguration(classes = ConfigServiceApplication.class)
10 | public class ConfigServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/code/eureka-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | eureka-service
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | eureka-service
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.3.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-starter-config
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-eureka-server
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-test
39 | test
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.springframework.cloud
47 | spring-cloud-dependencies
48 | Brixton.RC1
49 | pom
50 | import
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | org.springframework.boot
59 | spring-boot-maven-plugin
60 |
61 |
62 |
63 |
64 |
65 |
66 | spring-snapshots
67 | Spring Snapshots
68 | https://repo.spring.io/snapshot
69 |
70 | true
71 |
72 |
73 |
74 | spring-milestones
75 | Spring Milestones
76 | https://repo.spring.io/milestone
77 |
78 | false
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/code/eureka-service/src/main/java/com/example/EurekaServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
6 |
7 | @EnableEurekaServer
8 | @SpringBootApplication
9 | public class EurekaServiceApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(EurekaServiceApplication.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/code/eureka-service/src/main/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | spring.cloud.config.uri=http://localhost:8888
2 | spring.application.name=eureka-service
3 |
--------------------------------------------------------------------------------
/code/eureka-service/src/test/java/com/example/EurekaServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 |
8 | @RunWith(SpringJUnit4ClassRunner.class)
9 | @SpringApplicationConfiguration(classes = EurekaServiceApplication.class)
10 | public class EurekaServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/code/hystrix-dashboard/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | hystrix-dashboard
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | hystrix-dashboard
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.3.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-starter-config
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-eureka
34 |
35 |
36 | org.springframework.cloud
37 | spring-cloud-starter-hystrix-dashboard
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-test
43 | test
44 |
45 |
46 |
47 |
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-dependencies
52 | Brixton.RC1
53 | pom
54 | import
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-maven-plugin
64 |
65 |
66 |
67 |
68 |
69 |
70 | spring-snapshots
71 | Spring Snapshots
72 | https://repo.spring.io/snapshot
73 |
74 | true
75 |
76 |
77 |
78 | spring-milestones
79 | Spring Milestones
80 | https://repo.spring.io/milestone
81 |
82 | false
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/code/hystrix-dashboard/src/main/java/com/example/HystrixDashboardApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.netflix.hystrix.EnableHystrix;
7 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
8 |
9 | @EnableHystrixDashboard
10 | @EnableDiscoveryClient
11 | @SpringBootApplication
12 | public class HystrixDashboardApplication {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(HystrixDashboardApplication.class, args);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/code/hystrix-dashboard/src/main/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | spring.cloud.config.uri=http://localhost:8888
2 | spring.application.name=hystrix-dashboard
3 |
--------------------------------------------------------------------------------
/code/hystrix-dashboard/src/test/java/com/example/HystrixDashboardApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 |
8 | @RunWith(SpringJUnit4ClassRunner.class)
9 | @SpringApplicationConfiguration(classes = HystrixDashboardApplication.class)
10 | public class HystrixDashboardApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/code/reservation-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | reservation-client
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | reservation-client
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.3.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-starter-config
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-eureka
34 |
35 |
36 | org.springframework.cloud
37 | spring-cloud-starter-hystrix
38 |
39 |
40 | org.springframework.cloud
41 | spring-cloud-starter-zipkin
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-data-rest
46 |
47 |
48 | org.springframework.cloud
49 | spring-cloud-starter-stream-rabbit
50 |
51 |
52 | org.springframework.cloud
53 | spring-cloud-starter-zuul
54 |
55 |
56 | org.springframework.cloud
57 | spring-cloud-starter-feign
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-starter-web
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-starter-test
67 | test
68 |
69 |
70 |
71 |
72 |
73 |
74 | org.springframework.cloud
75 | spring-cloud-dependencies
76 | Brixton.RC1
77 | pom
78 | import
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-maven-plugin
88 |
89 |
90 |
91 |
92 |
93 |
94 | spring-snapshots
95 | Spring Snapshots
96 | https://repo.spring.io/snapshot
97 |
98 | true
99 |
100 |
101 |
102 | spring-milestones
103 | Spring Milestones
104 | https://repo.spring.io/milestone
105 |
106 | false
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/code/reservation-client/src/main/java/com/example/ReservationClientApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
8 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
9 | import org.springframework.cloud.client.loadbalancer.LoadBalanced;
10 | import org.springframework.cloud.netflix.feign.EnableFeignClients;
11 | import org.springframework.cloud.netflix.feign.FeignClient;
12 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
13 | import org.springframework.cloud.stream.annotation.EnableBinding;
14 | import org.springframework.cloud.stream.annotation.Output;
15 | import org.springframework.context.annotation.Bean;
16 | import org.springframework.hateoas.Resources;
17 | import org.springframework.integration.support.MessageBuilder;
18 | import org.springframework.messaging.MessageChannel;
19 | import org.springframework.web.bind.annotation.RequestBody;
20 | import org.springframework.web.bind.annotation.RequestMapping;
21 | import org.springframework.web.bind.annotation.RequestMethod;
22 | import org.springframework.web.bind.annotation.RestController;
23 | import org.springframework.web.client.RestTemplate;
24 |
25 | import java.util.ArrayList;
26 | import java.util.Collection;
27 | import java.util.stream.Collectors;
28 |
29 |
30 | interface ReservationChannels {
31 |
32 | @Output
33 | MessageChannel output();
34 | }
35 |
36 |
37 | @FeignClient("reservation-service")
38 | interface ReservationReader {
39 |
40 | @RequestMapping(method = RequestMethod.GET, value = "/reservations")
41 | Resources read();
42 | }
43 |
44 | @EnableFeignClients
45 | @EnableZuulProxy
46 | @EnableCircuitBreaker
47 | @EnableBinding(ReservationChannels.class)
48 | @EnableDiscoveryClient
49 | @SpringBootApplication
50 | public class ReservationClientApplication {
51 |
52 | @Bean
53 | @LoadBalanced
54 | RestTemplate restTemplate() {
55 | return new RestTemplate();
56 | }
57 |
58 | public static void main(String[] args) {
59 | SpringApplication.run(ReservationClientApplication.class, args);
60 | }
61 | }
62 |
63 | @RestController
64 | @RequestMapping("/reservations")
65 | class ReservationsApiGatewayRestController {
66 |
67 | @Autowired
68 | private RestTemplate restTemplate;
69 |
70 |
71 | public Collection fallback() {
72 | return new ArrayList<>();
73 | }
74 |
75 | @Autowired
76 | private ReservationChannels channels;
77 |
78 |
79 | @RequestMapping(method = RequestMethod.POST)
80 | public void write(@RequestBody Reservation r) {
81 |
82 | MessageChannel output = this.channels.output();
83 | output.send(MessageBuilder.withPayload(r.getReservationName()).build());
84 | }
85 |
86 |
87 | @HystrixCommand(fallbackMethod = "fallback")
88 | @RequestMapping(method = RequestMethod.GET, value = "/names")
89 | public Collection names() {
90 |
91 | /*ParameterizedTypeReference> ptr =
92 | new ParameterizedTypeReference>() {
93 | };
94 |
95 | ResponseEntity> responseEntity =
96 | this.restTemplate.exchange("http://reservation-service/reservations", HttpMethod.GET, null, ptr);
97 |
98 | return responseEntity
99 | .getBody()
100 | .getContent()
101 | .stream()
102 | .map(Reservation::getReservationName)
103 | .collect(Collectors.toList());
104 | */
105 |
106 | return this.reservationReader.read()
107 | .getContent()
108 | .stream()
109 | .map(Reservation::getReservationName)
110 | .collect(Collectors.toList());
111 |
112 |
113 | }
114 |
115 | @Autowired
116 | private ReservationReader reservationReader;
117 |
118 | }
119 |
120 | class Reservation {
121 | private String reservationName;
122 |
123 | public String getReservationName() {
124 | return reservationName;
125 | }
126 | }
--------------------------------------------------------------------------------
/code/reservation-client/src/main/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | spring.cloud.config.uri=http://localhost:8888
2 | spring.application.name=reservation-client
--------------------------------------------------------------------------------
/code/reservation-client/src/test/java/com/example/ReservationClientApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 | import org.springframework.test.context.web.WebAppConfiguration;
8 |
9 | @RunWith(SpringJUnit4ClassRunner.class)
10 | @SpringApplicationConfiguration(classes = ReservationClientApplication.class)
11 | @WebAppConfiguration
12 | public class ReservationClientApplicationTests {
13 |
14 | @Test
15 | public void contextLoads() {
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/code/reservation-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | reservation-service
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | reservation-service
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.3.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jpa
31 |
32 |
33 | org.springframework.cloud
34 | spring-cloud-starter-config
35 |
36 |
37 |
38 | org.springframework.cloud
39 | spring-cloud-starter-eureka
40 |
41 |
42 | org.springframework.cloud
43 | spring-cloud-starter-zipkin
44 |
45 |
46 | org.springframework.cloud
47 | spring-cloud-starter-stream-rabbit
48 |
49 |
50 |
51 |
52 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-web
58 |
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-starter-actuator
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-starter-data-rest
67 |
68 |
69 | com.h2database
70 | h2
71 | runtime
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-starter-test
76 | test
77 |
78 |
79 |
80 |
81 |
82 |
83 | org.springframework.cloud
84 | spring-cloud-dependencies
85 | Brixton.RC1
86 | pom
87 | import
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | org.springframework.boot
96 | spring-boot-maven-plugin
97 |
98 |
99 |
100 |
101 |
102 |
103 | spring-snapshots
104 | Spring Snapshots
105 | https://repo.spring.io/snapshot
106 |
107 | true
108 |
109 |
110 |
111 | spring-milestones
112 | Spring Milestones
113 | https://repo.spring.io/milestone
114 |
115 | false
116 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/code/reservation-service/src/main/java/com/example/ReservationServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.jboss.logging.annotations.Message;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.beans.factory.annotation.Value;
6 | import org.springframework.boot.CommandLineRunner;
7 | import org.springframework.boot.SpringApplication;
8 | import org.springframework.boot.actuate.health.Health;
9 | import org.springframework.boot.actuate.health.HealthIndicator;
10 | import org.springframework.boot.autoconfigure.SpringBootApplication;
11 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
12 | import org.springframework.cloud.context.config.annotation.RefreshScope;
13 | import org.springframework.cloud.stream.annotation.EnableBinding;
14 | import org.springframework.cloud.stream.messaging.Sink;
15 | import org.springframework.data.jpa.repository.JpaRepository;
16 | import org.springframework.data.repository.query.Param;
17 | import org.springframework.data.rest.core.annotation.RepositoryRestResource;
18 | import org.springframework.data.rest.core.annotation.RestResource;
19 | import org.springframework.integration.annotation.MessageEndpoint;
20 | import org.springframework.integration.annotation.ServiceActivator;
21 | import org.springframework.stereotype.Component;
22 | import org.springframework.web.bind.annotation.RequestMapping;
23 | import org.springframework.web.bind.annotation.RestController;
24 |
25 | import javax.persistence.Entity;
26 | import javax.persistence.GeneratedValue;
27 | import javax.persistence.Id;
28 | import java.util.Collection;
29 | import java.util.stream.Stream;
30 |
31 | @EnableBinding(Sink.class)
32 | @EnableDiscoveryClient
33 | @SpringBootApplication
34 | public class ReservationServiceApplication {
35 |
36 | public static void main(String[] args) {
37 | SpringApplication.run(ReservationServiceApplication.class, args);
38 | }
39 | }
40 |
41 | @MessageEndpoint
42 | class ReservationProcessor {
43 |
44 | @Autowired
45 | private ReservationRepository reservationRepository ;
46 |
47 | @ServiceActivator (inputChannel = "input")
48 | public void acceptNewReservationsPlease ( String rn) {
49 | this.reservationRepository.save(new Reservation(rn)) ;
50 | }
51 |
52 | }
53 |
54 | @RestController
55 | @RefreshScope
56 | class MessageRestController {
57 |
58 | @Value("${message}")
59 | private String message;
60 |
61 | @RequestMapping("/message")
62 | String m() {
63 | return this.message;
64 | }
65 |
66 | }
67 |
68 | @Component
69 | class CustomHealthIndicator implements HealthIndicator {
70 |
71 | @Override
72 | public Health health() {
73 | return Health.status("I <3 First Data!").build();
74 | }
75 | }
76 |
77 | @Component
78 | class DummyCLR implements CommandLineRunner {
79 |
80 | @Autowired
81 | private ReservationRepository reservationRepository;
82 |
83 | @Override
84 | public void run(String... args) throws Exception {
85 |
86 | Stream.of("Josh", "Ritesh", "Yoram", "Boris", "Tony", "Joe", "Gsaravanan", "Ian")
87 | .forEach(name -> reservationRepository.save(new Reservation(name)));
88 |
89 | reservationRepository.findAll().forEach(System.out::println);
90 |
91 | }
92 | }
93 |
94 | @RepositoryRestResource
95 | interface ReservationRepository extends JpaRepository {
96 |
97 | // select * from reservatins where reservation_name = :rn
98 | @RestResource(path = "by-name")
99 | Collection findByReservationName(@Param("rn") String rn);
100 | }
101 |
102 |
103 | @Entity
104 | class Reservation {
105 |
106 | @Id
107 | @GeneratedValue
108 | private Long id;
109 |
110 | private String reservationName; // reservation_name
111 |
112 | @Override
113 | public String toString() {
114 | return "Reservation{" +
115 | "id=" + id +
116 | ", reservationName='" + reservationName + '\'' +
117 | '}';
118 | }
119 |
120 | public Long getId() {
121 | return id;
122 | }
123 |
124 | public String getReservationName() {
125 | return reservationName;
126 | }
127 |
128 | public Reservation() {
129 |
130 | }
131 |
132 | public Reservation(String reservationName) {
133 |
134 | this.reservationName = reservationName;
135 | }
136 | }
--------------------------------------------------------------------------------
/code/reservation-service/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ${AnsiColor.BRIGHT_BLUE}████████████████████████████████████████████████████████████████████████████████
2 | ${AnsiColor.BRIGHT_BLUE}████████████████████████████████████████████████████████████████████████████████
3 | ${AnsiColor.RED}██████████████████${AnsiColor.BRIGHT_BLUE}████████████████${AnsiColor.BLACK}██████████████████████████████${AnsiColor.BRIGHT_BLUE}████████████████
4 | ${AnsiColor.RED}████████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██████████████
5 | ${AnsiColor.BRIGHT_RED}████${AnsiColor.RED}██████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.MAGENTA}██████████████████████${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████████████
6 | ${AnsiColor.BRIGHT_RED}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}████${AnsiColor.MAGENTA}██████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██${AnsiColor.BLACK}████${AnsiColor.BRIGHT_BLUE}██████
7 | ${AnsiColor.BRIGHT_RED}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.MAGENTA}██████${AnsiColor.WHITE}██${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████
8 | ${AnsiColor.BRIGHT_YELLOW}██████████████████${AnsiColor.BRIGHT_RED}████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.MAGENTA}██████${AnsiColor.WHITE}██${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████
9 | ${AnsiColor.BRIGHT_YELLOW}██████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_YELLOW}██████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}████████${AnsiColor.WHITE}████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████
10 | ${AnsiColor.BRIGHT_YELLOW}████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}██${AnsiColor.BRIGHT_YELLOW}████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████
11 | ${AnsiColor.BRIGHT_GREEN}██████████████████${AnsiColor.BRIGHT_YELLOW}██${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}████████${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██
12 | ${AnsiColor.BRIGHT_GREEN}██████████████████████${AnsiColor.WHITE}████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BRIGHT_YELLOW}██${AnsiColor.WHITE}██████████${AnsiColor.BRIGHT_YELLOW}██${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██
13 | ${AnsiColor.BRIGHT_GREEN}██████████████████████${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██
14 | ${AnsiColor.BLUE}██████████████████${AnsiColor.BRIGHT_GREEN}████████${AnsiColor.BLACK}██████${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████${AnsiColor.WHITE}████████████████${AnsiColor.MAGENTA}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██
15 | ${AnsiColor.BLUE}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}████████████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████
16 | ${AnsiColor.BRIGHT_BLUE}██████████████████${AnsiColor.BLUE}████${AnsiColor.BLUE}██████${AnsiColor.BLACK}████${AnsiColor.WHITE}██████${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██████
17 | ${AnsiColor.BRIGHT_BLUE}██████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}████${AnsiColor.WHITE}████████████████████${AnsiColor.BLACK}██████████████████${AnsiColor.BRIGHT_BLUE}████████
18 | ${AnsiColor.BRIGHT_BLUE}████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}████████████████████████████████${AnsiColor.WHITE}██${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████████████
19 | ${AnsiColor.BRIGHT_BLUE}████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BRIGHT_BLUE}████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████████████
20 | ${AnsiColor.BRIGHT_BLUE}████████████████████████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████████████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████████████
21 | ████████████████████████████████████████████████████████████████████████████████
22 | ${AnsiColor.BRIGHT_BLUE}:: Meow :: Running Spring Boot ${spring-boot.version} :: \ö/${AnsiColor.BLACK}
--------------------------------------------------------------------------------
/code/reservation-service/src/main/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | spring.cloud.config.uri=http://localhost:8888
2 | spring.application.name=reservation-service
3 |
--------------------------------------------------------------------------------
/code/reservation-service/src/test/java/com/example/ReservationServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 | import org.springframework.test.context.web.WebAppConfiguration;
8 |
9 | @RunWith(SpringJUnit4ClassRunner.class)
10 | @SpringApplicationConfiguration(classes = ReservationServiceApplication.class)
11 | @WebAppConfiguration
12 | public class ReservationServiceApplicationTests {
13 |
14 | @Test
15 | public void contextLoads() {
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/code/zipkin-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | zipkin-service
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | zipkin-service
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.3.3.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 | org.springframework.cloud
29 | spring-cloud-starter-config
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-eureka
34 |
35 |
36 | io.zipkin.java
37 | zipkin-server
38 |
39 |
40 |
41 | io.zipkin
42 | zipkin-ui
43 | runtime
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-test
48 | test
49 |
50 |
51 |
52 |
53 |
54 |
55 | org.springframework.cloud
56 | spring-cloud-dependencies
57 | Brixton.BUILD-SNAPSHOT
58 | pom
59 | import
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | org.springframework.boot
68 | spring-boot-maven-plugin
69 |
70 |
71 |
72 |
73 |
74 |
75 | spring-snapshots
76 | Spring Snapshots
77 | https://repo.spring.io/snapshot
78 |
79 | true
80 |
81 |
82 |
83 | spring-milestones
84 | Spring Milestones
85 | https://repo.spring.io/milestone
86 |
87 | false
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/code/zipkin-service/src/main/java/com/example/ZipkinServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import zipkin.server.EnableZipkinServer;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 |
8 | @EnableZipkinServer
9 | @EnableDiscoveryClient
10 | @SpringBootApplication
11 | public class ZipkinServiceApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(ZipkinServiceApplication.class, args);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/code/zipkin-service/src/main/resources/bootstrap.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=zipkin-service
2 | spring.cloud.config.uri=http://localhost:8888
3 |
--------------------------------------------------------------------------------
/code/zipkin-service/src/test/java/com/example/ZipkinServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 |
8 | @RunWith(SpringJUnit4ClassRunner.class)
9 | @SpringApplicationConfiguration(classes = ZipkinServiceApplication.class)
10 | public class ZipkinServiceApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/images/git-config-repo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshlong-attic/microservices-dzrc/b90d75329d9f93282cb9de3e1be0da051b0680d4/images/git-config-repo.png
--------------------------------------------------------------------------------
/images/graphite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshlong-attic/microservices-dzrc/b90d75329d9f93282cb9de3e1be0da051b0680d4/images/graphite.png
--------------------------------------------------------------------------------
/images/hystrix-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshlong-attic/microservices-dzrc/b90d75329d9f93282cb9de3e1be0da051b0680d4/images/hystrix-dashboard.png
--------------------------------------------------------------------------------
/images/spring-cloud-netflix-eureka.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshlong-attic/microservices-dzrc/b90d75329d9f93282cb9de3e1be0da051b0680d4/images/spring-cloud-netflix-eureka.png
--------------------------------------------------------------------------------
/images/zipkin-traces.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshlong-attic/microservices-dzrc/b90d75329d9f93282cb9de3e1be0da051b0680d4/images/zipkin-traces.png
--------------------------------------------------------------------------------