Spring Framework 5.0 Themes and Trends

Spring Framework 5.0 Themes and Trends

Preparing for the challenges of 2017 and beyond, Spring Framework 5 focuses on several key themes:. In particular reactive web applications, comprehensive support for JDK 9, and a general focus on lambda-oriented programmatic setup This keynote introduces Spring Framework 5.0 towards the end of its milestone phase and presents selected feature highlights.

D3c309254575cdef66812b8970230d2c?s=128

Stéphane Nicoll

May 10, 2017
Tweet

Transcript

  1. Spring 5 Themes & Trends Stéphane Nicoll - @snicoll

  2. Last 4.x feature release: 4.3 2 • Released on June

    2016 • Extended support life until 2019 • on JDK 6, 7, 8 • on Tomcat 6, 7, 8.0, 8.5 • on WebSphere 7, 8.0, 8.5 and 9 • Programming model refinements brought forward to JDK 6+ • DI & MVC refinements • Composed annotations
  3. A new framework generation for 2017+ 3 • 5.0 GA

    available • Spring Boot 2.0 M5 next week! • Major baseline upgrade • JDK 8+ and JavaEE 7 (Servlet 3.1+, Bean Validation 1.1, JMS 2.0+, JPA 2.1+) • Support of JUnit 5 (next to JUnit 4.12) • Comprehensive integration with JavaEE 8 API level • Servlet 4.0, Bean Validation 2.0, JPA 2.2, JSON Binding API 1.0 • e.g. Tomcat 9.0, Hibernate Validator 6.0, Apache Johnzon 1.1
  4. @snicoll 4 JDK 9

  5. @snicoll 5 HTTP/2

  6. @snicoll 6 Reactive Spring

  7. 7 ∞

  8. 8 Going Reactive: More for scalability and stability than for

    speed
  9. Blocking + Thread pools 9 HTTP request HTTP response ⏳

    ⚙ ⏳ ✍ ⏳ Thread
  10. Non-blocking and event-loop 10 IO Selector Thread Worker Threads ⚙

    ⚙ ✍ ✍ ⚙ ⚙ ✍ ✍ ⚙ ⚙ ✍
  11. 11 From blocking to event-based Neutral to latency

  12. Imperative style 12 public interface PersonRepository {
 
 Person findById(String

    id);
 
 List<Person> findAll();
 
 void save(Person person);
 
 } try {
 Person p = personRepository.findById(id);
 // ...
 handle(p);
 }
 catch (IOException ex) {
 // ...
 } Blocking
  13. Functional style 13 personRepository.findById(id)
 .map(this::handle)
 .subscribe(); public interface PersonRepository {


    
 Mono<Person> findById(String id);
 
 Flux<Person> findAll();
 
 Mono<Void> save(Person person);
 
 } Neutral to latency (event based)
  14. Reactive Streams 14 Publisher Subscriber subscribe request(n) Backpressure Error|Complete onNext(data)

    onNext(data) onNext(data)
  15. Reactive Streams API 15 public interface Publisher<T> { void subscribe(Subscriber<?

    super T> s); } public interface Subscriber<T> { void onSubscribe(Subscription s); void onNext(T t); void onError(Throwable t); void onComplete(); } public interface Subscription { void request(long n); void cancel(); } public interface Processor<T, R> extends Subscriber<T>, Publisher<R> { }
  16. Functional style 16 personRepository.findById(id)
 .map(this::handle)
 .subscribe(); public interface PersonRepository {


    
 Mono<Person> findById(String id);
 
 <Person> findAll();
 
 Mono<Void> save(Person person);
 
 } Neutral to latency (event based) Flux
  17. 17 <T> is a Publisher<T> for 0..n elements Flux

  18. 18 Mono<T> is a Publisher<T> for 0..1 element

  19. @snicoll Demo

  20. 20

  21. Reactive Web Controller 21 @GetMapping("/users/{id}")
 Mono<User> getById(@PathVariable String id) {


    return this.userRepository.findOne(id);
 }
 
 @GetMapping("/users")
 Flux<User> all() {
 return this.userRepository.findAll();
 }
 
 @PostMapping("/users")
 Mono<Void> save(@RequestBody Mono<User> user) {
 return this.userRepository.save(user).then();
 }
  22. New Web Client API 22 WebClient client = WebClient.create(); Mono<GithubUser>

    githubUser = client .get() .uri("https://api.github.com/users/{username}", username) .retrieve() .bodyToMono(GithubUser.class); Mono<TwitterUser> twitterUser = client .get() .uri("https://api.twitter.com/1.1/users/show.json?screen_name={username}", username) .retrieve() .bodyToMono(TwitterUser.class); return githubUser.and(twitterUser, (github, twitter)-> new AppUser(github, twitter));
  23. 23 @Controller, @RequestMapping Spring MVC Servlet API Servlet Container Spring

    WebFlux.fn Servlet 3.1, Netty, Undertow Spring WebFlux HTTP / Reactive Streams
  24. @snicoll 24 Functional APIs

  25. Functional bean registration API (work in progress) 25 • Alternative

    mechanism to configure the ApplicationContext • Full control over beans registration public static void main(String[] args) { GenericApplicationContext ctx = new GenericApplicationContext(); ctx.registerBean(A.class); ctx.registerBean(B.class, () -> new B(ctx.getBean(A.class))); ctx.refresh(); }
  26. Functional-style web routing 26 RouterFunction<?> route =
 route(GET("/users"), )
 .and(route(GET("/users/{id}"),

    )
 .and(route(POST("/users"), ))); request -> {
 Flux<User> people = repository.findAll();
 return ServerResponse.ok().body(people, User.class);
 } request -> {
 String personId = request.pathVariable("id");
 Mono<User> person = repository.findById(personId);
 return ServerResponse.ok().body(person, User.class);
 } request -> {
 Mono<User> user = request.bodyToMono(User.class);
 return ServerResponse.ok().build(repository.saveAll(user).then());
 }
  27. Functional-style web routing 27 RouterFunction<?> route =
 route(GET(“/users"), )
 .and(route(GET(“/users/{id}”),

    )
 .and(route(POST(“/users”), ))); this::findAll this::findById this::save
  28. @snicoll 28 Kotlin Support

  29. Type inference 29 @RestController class UserController(val repo: UserRepository) { @GetMapping("/user/{id}")

    fun findOne(@PathVariable id: String): Mono<User> { } @GetMapping("/user") fun findAll() : Flux<User> { } } return repo.findOne(id) return repo.findAll()
  30. Type inference 30 @RestController class UserController(val repo: UserRepository) { @GetMapping("/user/{id}")

    fun findOne(@PathVariable id: String) = @GetMapping("/user") fun findAll() : Flux<User> = } repo.findOne(id) repo.findAll()
  31. Extensions 31 fun findAll(request: ServerRequest): Mono<ServerResponse> { } inline fun

    <reified T : Any> ServerResponse.BodyBuilder .body(publisher: Publisher<T>) = body(publisher, T::class.java) ServerResponseExtensions provided by spring-webflux return ok().body(repo.findAll(), User::class.java)
  32. Extensions 32 fun findAll(request: ServerRequest) = inline fun <reified T

    : Any> ServerResponse.BodyBuilder .body(publisher: Publisher<T>) = body(publisher, T::class.java) ServerResponseExtensions provided by spring-webflux ok().body(repo.findAll())
  33. Leverage Kotlin nullable information 33 @GetMapping("/foo") fun foo(@RequestParam( ) bar:

    String?) = … http://localhost:8080/foo required = false
  34. Leverage Kotlin nullable information 34 @GetMapping("/foo") fun foo(@RequestParam bar: String?)

    = … http://localhost:8080/foo
  35. Custom DSL 35 nest( ), route( . andRoute( ). andNest(

    ), . . ); path("/blog").and(accept(TEXT_HTML) GET("/"), blogHandler::findAllView) GET("/{slug}"), blogHandler::findOneView) path("/api/blog").and(accept(APPLICATION_JSON) route(GET("/"), blogHandler::findAll) andRoute(GET("/{id}"), blogHandler::findOne) andRoute(POST("/"), blogHandler::create)
  36. Custom DSL 36 router { ( ).nest { } (

    ).nest { } } "/blog" and accept(TEXT_HTML) GET("/", blogHandler::findAllView) GET("/{slug}", blogHandler::findOneView) "/api/blog" and accept(APPLICATION_JSON) GET("/", blogHandler::findAll) GET("/{id}", blogHandler::findOne) POST("/", blogHandler::create)
  37. And many more… 37 https://goo.gl/gMnhxN

  38. @snicoll Demo

  39. Try it today: start.spring.io 39

  40. 40 Thank You! @snicoll