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

Spring I/O 2017: Getting Thymeleaf Ready for Spring 5 and Reactive

Spring I/O 2017: Getting Thymeleaf Ready for Spring 5 and Reactive

Spring 5 is here and it brings a lot of awesomeness — but the star of the show is no doubt the new reactive web framework. Thymeleaf has been the server-side template engine of choice for a lot Spring users for a while now, so once the new Spring reactive infrastructure was sketched some time ago, we took up the challenge of adapting Thymeleaf to the needs of the new framework.

From adjusting code to the new APIs –that was easy– to actually making the engine respond to back-pressure requests from consumers –that definitely wasn't–, Thymeleaf had to undergo a good amount of refactoring and rethinking just before the release of Thymeleaf 3.0 last year. The result was a Java server-side template engine able to be as friendly to a reactive application environment as one would need: from normal, good-old templating operation to turning Thymeleaf into an on-the-fly generator of HTML for reactive streams/publishers of data.

This talk will offer a quite brief introduction to Thymeleaf and its features for those new to the technology, and then explain the challenges posed by the integration of Thymeleaf with Spring's reactive web framework and the approach of the project to the reactive world in general.

Daniel Fernández

May 19, 2017

More Decks by Daniel Fernández

Other Decks in Technology


  1. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org What is ? •

    Server-side template engine for Java – HTML, XML, JavaScript, CSS, text – View layer in SpringMVC, WebFlux, and others • First version 2011 — Currently 3.0.6 • 220,000+ downloads/month (core) April 2017 – Was 75,000+ a year ago!
  2. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org It looks like this…

    <table> <thead> <tr> <th th:text="#{msgs.headers.name}">Name</th> <th th:text="#{msgs.headers.price}">Price</th> </tr> </thead> <tbody> <tr th:each="prod : ${allProducts}"> <td th:text="${prod.name}">Oranges</td> <td th:text="${#numbers.formatDecimal(prod.price,1,2)}">0.99</td> </tr> </tbody> </table>
  3. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org …or this… <a data-th-href="@{/user/profile(id=${user.id})}">See

    Profile</a> <div data-th-if="${user.isAdmin()}"> <div data-th-insert="~{commonheaders :: adminheader(user)}"> ... </div> <span>[[${user.name}]]</span> </div>
  4. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org …or even this, too

    <script data-th-inline="javascript"> var sourceUrl = [[@{/streams/events}]]; var source = new EventSource(sourceUrl); ... </script> Dear [(${name})], here's a list of our current products: [# th:each="item : ${items}"] - [(${item})] [/] Regards.
  5. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Summary of features •

    Iteration, conditionals, layout, i18n… All the Basics • Non-intrusive for design Natural Templates • Non-intrusive for client-side code Coexist with JS • Extensibility Custom Dialects
  6. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Very little effort to

    adapt • Unaffected by most changes – Java 8 Thymeleaf still supporting Java 6 ¯\_(ϑ)_/¯ – Package refactoring, tech support cleanup • New integration module – thymeleaf-spring5 – 3.0.6.M4, will be .RELEASE when Spring 5 is too
  7. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org That's a different story

    • WebFlux APIs are equivalent to MVC's • Still, they are other APIs – RequestContext, BindStatus… – No Servlet-based Request/Response objects • Parameters, attributes, link building, output – View/ViewResolver
  8. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org The big one: WebFlux

    is reactive • Thymeleaf 3.0 is not a reactive technology – Being reactive needs being coded reactive • Evaluate: How much blocking do we have? – Template reading: do cache! Still, cache blocks :( – Blocking data retrieval Not Thymeleaf's fault – Output
  9. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org The issue with output

    • No HttpResponse.getWriter() – No "send to the browser as you render it" • Reactive output: Publisher<DataBuffer> – Mono<DataBuffer> with the whole output? • Formally valid, but what about memory usage? – Flux<DataBuffer>? • We are subject to backpressure • We need to stop the engine after each DataBuffer • Being a hot source is not an option for a template engine
  10. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Thymeleaf is input-driven •

    Thymeleaf 3 is (normally) input-driven – Parser/cache produce template model events – Events are processed in sequence, produce output S:table S:tr S:td T:"John" E:td ... <table> <tr> <td> John </td> ... process()
  11. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Engine throttling • Throttling

    allows it to stop and resume – Whenever it has written n bytes of output – Engine might need to hibernate after any event • Not in the middle of an event, so a tiny bit of buffering S:table S:tr S:td <table> <tr> <td> processThrottled() T:"John" E:td ... John </td> ... processThrottled() STOP OUTPUT
  12. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Reactive context variables •

    Publisher<T> variables in context (model) • WebFlux resolves them all – Before asking the View to render – In a non-blocking way – Transparent to Thymeleaf • What if we don't want them all resolved?
  13. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Data-driven execution • A

    Publisher<T> driving template execution – Special variable in context – Only one, and it has to be iterated (th:each) – HTML rendered as values are published • Thymeleaf = Processor<T,DataBuffer> – Subscriber<T> – Publisher<DataBuffer>
  14. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Server-Sent Events (SSE) •

    Data-driven execution, 1 iteration = 1 event – Thymeleaf's output channels must understand SSE event: head id: 0 data: <table> event: message id: 1 data: <tr> data: <td>John Apricot</td> data: </tr> event: message id: 2 data: <tr> data: <td>Josephine Watermelon</td> data: </tr> event: tail id: 3 data: </table>
  15. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Reactive-friendly operation modes Publisher<Data>

    Data Iterable<Data> CONTEXT "<!DOCTYPE>\n<html>\n<body>..." String Mono<DataBuffer> OUTPUT CHANNEL Publisher<Data> Data Iterable<Data> CONTEXT Flux<DataBuffer> OUTPUT CHANNEL Publisher<Data> CONTEXT Flux<DataBuffer> OUTPUT CHANNEL 1 DATA-DRIVEN CHUNKED FULL
  16. @spring_io #springio17 @danfenz · @thymeleaf http://thymeleaf.org Spring Boot 2.0 awesomeness

    • Uses Thymeleaf 3.0 by default • Main way to develop Spring WebFlux apps • Supports thymeleaf-spring5 • Autoconfigures Thymeleaf + WebFlux! <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>