Skip to content

Instantly share code, notes, and snippets.

@dsyer
Last active March 1, 2016 16:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsyer/c9d5ae6e91a299bf853a to your computer and use it in GitHub Desktop.
Save dsyer/c9d5ae6e91a299bf853a to your computer and use it in GitHub Desktop.

Modern Spring

Basic Spring Boot Features

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
  • 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

Create a Separate Service Backend

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 type RestTemplate
  • 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

Add Config Server

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
  • 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 to main.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)

Add Circuit Breaker

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
  • Create a Hystrix dashboard app and inspect the stream

    • Home page can return "forward:/hystrix/"
    • Shutdown the backend and open the circuit

Declarative REST Client

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)

Service Discovery

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

Gateway

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

Security

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

OAuth2

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

Custom Autoconfiguration

Goal: build a Spring Boot "plugin" to add new behaviour automatically

Distributed Tracing

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. in bootstrap.poperties
    • Starts on port 9411
    • /api/v1/services and /api/v1/trace/{id}
  • Run a Zipkin UI

    • launch the jar file with -zipkin.web.port=:7676 (for example)

Messaging Microservices

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 the Sink 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

Groovy CLI

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

Testing

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

Docker Images

Goal: build a docker image for a Spring Boot app with a small footprint.

Custom Initializr

Goal: build your own Initializr and configure it to serve custom dependency sets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment