Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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. 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
  2. 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
  3. 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
  4. 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)
  5. 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> { }
  6. 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
  7. 20

  8. 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();
 }
  9. 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));
  10. 23 @Controller, @RequestMapping Spring MVC Servlet API Servlet Container Spring

    WebFlux.fn Servlet 3.1, Netty, Undertow Spring WebFlux HTTP / Reactive Streams
  11. 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(); }
  12. 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());
 }
  13. 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
  14. 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()
  15. 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()
  16. 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)
  17. 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())
  18. Leverage Kotlin nullable information 33 @GetMapping("/foo") fun foo(@RequestParam( ) bar:

    String?) = … http://localhost:8080/foo required = false
  19. 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)
  20. 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)