Goal: show how it is easy to create web UI and modify its behaviour according to the environment.
-
Use start.spring.io to create an application with a simple
@RestController
-
Use STS to do the same thing (and mention the other IDEs)
-
Create vanilla webapp and add static home page
- Add webjars to pom and show that they get loaded
- Demonstrate that changes are visible immediately
-
Add angular app and home controller with static greeting.
- Double handlebars for binding angular model.
-
Use
$http
to load a greeting from the backend using a simple@RestController
.$http.get(...).then(function(response) { .. })
-respone.data
is the body
-
Parameterize the greeting with
@Value
-
Use
@ConfigurationProperties
instead- Add the configuration processor and get the IDE auto-completion
-
Build a jar file and run it
- Remember to
chmod +x mvnw
- Change the greeting on the command line with an argument
- With a System property
- With an env var
- Change the greeting in
./application.properties
- Remember to
-
Make a different greeting in a "dev" profile and activate the profile
-
Build an executable jar file and run it
- Show that it can be installed as a service
Goal: exract the greeting data management to a separate service
-
Use JPA and Spring Data REST to serve up greeting resources
-
Convert the front end to delegate to the backend to get a greeting
- Walk the JSON manually, e.g. "_embedded.greetings[0]"
- Add Spring HATEOAS
- Use
PagedResources<Greeting>
to get the greetings - remember to create a@Bean
of typeRestTemplate
-
Extract the service URL into a configuration property
app.url
-
Quick tour of Actuator endpoints
-
Add HAL browser
-
Add Actuator docs and look at /actuator endpoint
-
Expose Actuator endpoints on a separate port
Goal: keep the service URL in a config server and explore basic Spring Cloud features
-
Create a config server with
@EnableConfigServer
- Launch it with
spring.config.name=configserver
(e.g. via `bootstrap.properties) so it runs on port 8888 - Show that the config repo URL is a local git repository
- Launch it with
-
Add config client to front end and give it a
spring.application.name=main
-
Show that it picked up config from the config server, but the
app.url
is missing -
Add
app.url
tomain.properties
in the config repo and POST to /refresh to get the app working -
Temporary change via POST to /env (e.g. enable DEBUG logging)
Goal: show how to protect the front end from back end failures
-
Add
@EnableCircuitBreaker
and@HystrixCommand
on the@RequestMapping
- add
spring-cloud-starter-hystrix
- extract the
@RestController
to a separate class - add a fallback method with the same signature
logging.level.com.netflix.hystrix.AbstractCommand: DEBUG
- add
-
Create a Hystrix dashboard app and inspect the stream
- Home page can return "forward:/hystrix/"
- Shutdown the backend and open the circuit
Goal: show how to replace RestTemplate
with @FeignClient
- Add Feign dependency and a
@FeignClient
to read the remote greeting- Remove devtools at this point (it doesn't work with Ribbon still)
- Don't use
PagedResources<Greeting>
(the converter isn't installed in Feign by default) - just get a greeting by ID. - Use a hard-coded URL and then a service id with
greetings.ribbon.listOfServers=
. - Remember
ribbon.eureka.enabled=false
(it's not needed until you put Eureka on the classpath, but useful to know when it is and the server list is not getting configured)
Goal: allow service population to change dynamically
-
Create a Eureka server and run it
-
Add eureka dependency to main and service apps
- Also add
@EnableDiscoveryClient
- Remove the hard-coded ribbon server list
- Also add
Goal: manage traffic to back end servers through a dynamic router
-
Add
@EnableZuulProxy
to the main UI app -
Show that it proxies the backend service
- curl the /routes
- Configure the route not to drop the prefix
- Note the links to the proxy rendered in the proxied resources
- add a table of greetings in HTML -
ng-repeat="greeting in home.greetings"
-
Add a form and append to the list of greetings by POSTing to /greetings through the proxy
- Remember to use
@RequestBody
for the body
- Remember to use
Goal: secure the system and protect the resources
-
Add Spring Security to the proxy and set up a custom password
-
Set up a custom
AuthenticationManager
-
(TODO): Add a login screen
-
(TODO): Secure the UI separately from the Actuator endpoints
-
Secure the backend service and show that it is inaccessible
-
Add Spring Session to both apps with Redis.
- Remember
security.session: IF_REQUIRED
. - Remove devtools
$ curl -v user:password@localhost:8080/ > /dev/null
grab the cookie- Also use
management.security.sessions: IF_REQUIRED
if you want to use the cookie on the actuator endpoints
- Remember
Goal: (TODO) simple single sign on with an external social provider
-
Add
@EnableOAuth2Sso
and authenticate with Github -
Cloud Foundry SSO service
-
Token relay with Spring Cloud Security
Goal: build a Spring Boot "plugin" to add new behaviour automatically
Goal: correlate requests and messages throughout a distributed system.
-
Add sleuth starter to both apps and relaunch.
- Show correlation ids being logged.
- Remember to log something in the requests (e.g. add a log
statement in the controller and/or set
logging.level.org.springframework.web=DEBUG
)
-
Fire up ELK and pipe some app logs to logstash (
nc localhost 5000
)- Check the logstash config for the Sleuth pattern
- You can pipe to a fifo from Eclipse but the process will hang
until you start reading it (so
nc localhost 5000 < ~/tmp/outf
for instance) - Netcat dies if its input ends, so you have to keep relaunching it
-
Add Zipkin stream and relaunch.
spring.sleuth.sampler.percentage=1.0
-
Create a Zipkin server with
@EnableZipkinStreamServer
- Set
spring.config.name=zipkin-server
e.g. inbootstrap.poperties
- Starts on port 9411
/api/v1/services
and/api/v1/trace/{id}
- Set
-
Run a Zipkin UI
- launch the jar file with
-zipkin.web.port=:7676
(for example)
- launch the jar file with
Goal: separate producer and consumer of greetings, and show how easy it can be.
-
Add Spring Cloud Stream Rabbit to both applications
- Don't use Redis because of content and serialization issues (hopefully to be fixed in 1.0.0)
-
@EnableBinding(Source.class)
in the UI and replace the POST to /greetings with a message sent to the source channel -
@EnableBinding(Sink.class)
in the backend and wire theSink
in to save the new greeting- Remember to set
spring.cloud.stream.bindings.input.destination=output
so the consumer subscribes to the same queue as the producer. - Set the content type on producer to
application/json
- Set the content type on consumer to
application/x-java-object;type=com.example.Greeting
- Remember to set
Goal: show how quick it is to run up simple services and get them running locally and in production.
-
Simple "Hello World" rest controller
-
Static website with HTML
-
Add
@EnableDiscoveryClient
and see it register with Eureks- Don't use
--watch
until Boot 1.3.4
- Don't use
Goal: write integration tests for services.
Non-goal: write unit tests for javascript client
-
Look at the unit test provided by start.spring.io
-
Expand on it a bit and make some assertions
-
Use Mock MVC to test a controller
-
Add restdocs and generate some snippets
- Add the dependency (version is managed by Boot)
- Add document
Goal: build a docker image for a Spring Boot app with a small footprint.
Goal: build your own Initializr and configure it to serve custom dependency sets.