$30 off During Our Annual Pro Sale. View Details »

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.

Stéphane Nicoll

May 10, 2017
Tweet

More Decks by Stéphane Nicoll

Other Decks in Technology

Transcript

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

    View Slide

  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

    View Slide

  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

    View Slide

  4. @snicoll
    4
    JDK 9

    View Slide

  5. @snicoll
    5
    HTTP/2

    View Slide

  6. @snicoll
    6
    Reactive Spring

    View Slide

  7. 7



    View Slide

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

    View Slide

  9. Blocking + Thread pools
    9
    HTTP request
    HTTP response






    Thread

    View Slide

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


    ⚙ ⚙ ✍
    ✍ ⚙

    ✍ ✍ ⚙
    ⚙ ✍

    View Slide

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

    View Slide

  12. Imperative style
    12
    public interface PersonRepository {


    Person findById(String id);


    List findAll();


    void save(Person person);


    }
    try {

    Person p = personRepository.findById(id);

    // ...

    handle(p);

    }

    catch (IOException ex) {

    // ...

    }
    Blocking

    View Slide

  13. Functional style
    13
    personRepository.findById(id)

    .map(this::handle)

    .subscribe();
    public interface PersonRepository {


    Mono findById(String id);


    Flux findAll();


    Mono save(Person person);


    }
    Neutral to latency
    (event based)

    View Slide

  14. Reactive Streams
    14
    Publisher Subscriber
    subscribe
    request(n)
    Backpressure
    Error|Complete
    onNext(data)
    onNext(data)
    onNext(data)

    View Slide

  15. Reactive Streams API
    15
    public interface Publisher {
    void subscribe(Subscriber super T> s);
    }
    public interface Subscriber {
    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 extends Subscriber, Publisher {
    }

    View Slide

  16. Functional style
    16
    personRepository.findById(id)

    .map(this::handle)

    .subscribe();
    public interface PersonRepository {


    Mono findById(String id);


    findAll();


    Mono save(Person person);


    }
    Neutral to latency
    (event based)
    Flux

    View Slide

  17. 17
    is a Publisher for 0..n elements
    Flux

    View Slide

  18. 18
    Mono is a Publisher for 0..1 element

    View Slide

  19. @snicoll
    Demo

    View Slide

  20. 20

    View Slide

  21. Reactive Web Controller
    21
    @GetMapping("/users/{id}")

    Mono getById(@PathVariable String id) {

    return this.userRepository.findOne(id);

    }


    @GetMapping("/users")

    Flux all() {

    return this.userRepository.findAll();

    }


    @PostMapping("/users")

    Mono save(@RequestBody Mono user) {

    return this.userRepository.save(user).then();

    }

    View Slide

  22. New Web Client API
    22
    WebClient client = WebClient.create();
    Mono githubUser = client
    .get()
    .uri("https://api.github.com/users/{username}", username)
    .retrieve()
    .bodyToMono(GithubUser.class);
    Mono 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));

    View Slide

  23. 23
    @Controller, @RequestMapping
    Spring MVC
    Servlet API
    Servlet Container
    Spring WebFlux.fn
    Servlet 3.1, Netty, Undertow
    Spring WebFlux
    HTTP / Reactive Streams

    View Slide

  24. @snicoll
    24
    Functional APIs

    View Slide

  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();
    }

    View Slide

  26. Functional-style web routing
    26
    RouterFunction> route =

    route(GET("/users"),
    )

    .and(route(GET("/users/{id}"),
    )

    .and(route(POST("/users"),
    )));
    request -> {

    Flux people = repository.findAll();

    return ServerResponse.ok().body(people, User.class);

    }
    request -> {

    String personId = request.pathVariable("id");

    Mono person = repository.findById(personId);

    return ServerResponse.ok().body(person, User.class);

    }
    request -> {

    Mono user = request.bodyToMono(User.class);

    return ServerResponse.ok().build(repository.saveAll(user).then());

    }

    View Slide

  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

    View Slide

  28. @snicoll
    28
    Kotlin Support

    View Slide

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

    View Slide

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

    View Slide

  31. Extensions
    31
    fun findAll(request: ServerRequest): Mono {
    }
    inline fun ServerResponse.BodyBuilder
    .body(publisher: Publisher) = body(publisher, T::class.java)
    ServerResponseExtensions provided by spring-webflux
    return ok().body(repo.findAll(), User::class.java)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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)

    View Slide

  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)

    View Slide

  37. And many more…
    37
    https://goo.gl/gMnhxN

    View Slide

  38. @snicoll
    Demo

    View Slide

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

    View Slide

  40. 40
    Thank You!
    @snicoll

    View Slide