- Java EE supports reactive applications through asynchronous APIs, non-blocking IO, and managed executors. CompletableFuture in Java 8 improves asynchronous programming.
- Payara Micro enables reactive microservices through automatic clustering, distributed caching, and a lightweight event bus using CDI events.
- While fully reactive approaches have high costs, Java EE leaves the door open for gradual improvements to reactivity through standards like JCache and by leveraging asynchronous capabilities.
How to bake reactive behavior into your Java EE applications
1. How to bake reactive
behavior into your Java EE
applications
Ondrej Mihályi
@OMihalyi
2. @OMihalyi
AgendaAgenda
➢
What is a reactive app
➢
Support in Java EE 7
➢
Java 8 joins the game
➢
Payara Micro additions
➢
Live demo
➢
Common pitfalls
5. @OMihalyi
Possible in Enterprise?Possible in Enterprise?
New tools and frameworks
➔
High risks and costs
Fully reactive approach
➔
High cost of development
➔
Harder to avoid and track bugs
Advice → reactive where it’s worth
→ leave the door open for future
6. @OMihalyi
Java EE leaves the door openJava EE leaves the door open
Established and wide-spread
– Built with resilience in mind (Transactions)
– Messaging is first-class citizen (JMS)
Continuous improvements
– Asynchronous API, thread-management
– Scalability improvements (JCache)
– Portable CDI extensions
12. @OMihalyi
Spawn a separate threadSpawn a separate thread
Idea:
– Blocking call in a new thread
– Do something while waiting
– Join the thread and retrieve results
– Fail after timeout vs. block infinitely
13. @OMihalyi
java.util.concurrent.Futurejava.util.concurrent.Future
Solution in Java world (since Java 5)
@Asynchronous methods since Java EE 6
– Solves the problem for fire-and-forget
– Still drawbacks when result needed
●
Complexity – keep asking “Are you ready?”
●
Requires one more thread
– blocked when nothing to do while waiting
14. @OMihalyi
@Asynchronous@Asynchronous
Any EJB method or all methods of an EJB
Executes in another thread in pool
Fire-and-forget with void result
Return result as a Future
– Future not efficient enough, we’ll improve later
16. @OMihalyi
Non-blocking API in Java EE 7Non-blocking API in Java EE 7
AsyncContext in Servlet (since 3.0, Java EE 6)
// get context for another thread
AsyncContext ctx =
req.startAsync();
AsyncContext
.getResponse()
.getOutputStream()…
ctx.complete();
17. @OMihalyi
Non-blocking API in Java EE 7Non-blocking API in Java EE 7
AsyncContext in Servlet
AsyncContext ctx =
req.startAsync();
AsyncContext // build response (in any thread)
.getResponse()
.getOutputStream()…
// finish (in new thread)
ctx.complete();
18. @OMihalyi
Non-blocking API in Java EE 7Non-blocking API in Java EE 7
AsyncContext in Servlet
– Requires to turn on async support
●
Using @WebServlet annotation
●
In web.xml descriptor
@WebServlet
(asyncSupported=true)
19. @OMihalyi
Non-blocking API in Java EE 7Non-blocking API in Java EE 7
Async IO in Servlet 3.1 (Java EE 7)
– Non-blocking reading of multi-part form
– Non-blocking writing of response body
Non-blocking IO in Java (NIO)
– to read HTML from files
26. @OMihalyi
Summary of approachesSummary of approaches
Traditional blocking API
– Easy to use, halts execution until finished
Asynchronous call with Future
– not blocking, +1 thread
Asynchronous call with callback
– Not blocking, 1 thread at a time, callback hell
27. @OMihalyi
Java 8Java 8
CompletableFuture (CompletionStage)
– Chain callbacks (like promises)
– Execute in the same or another thread
● thenRun(), thenRunAsync(), …
● thenCompose(),…
– Complete execution in any thread at any time
● completableFuture.complete()
thenComposeAsync()
30. @OMihalyi
Java EE + Java 8Java EE + Java 8
Future → CompletableFuture ?
– No, not compatible
Callbacks → CompletableFuture
– callback triggers cf.complete()
Pass CF as additional parameter
31. @OMihalyi
Pass CF as additional parameterPass CF as additional parameter
void asyncCall(CompletableFuture cf) {
… cf.complete(result);
}
… cf = new CompletableFuture<String>();
asyncCall(cf);
cf.thenComposeAsync(
result -> … , executor);
32. @OMihalyi
Use managed executorsUse managed executors
CF async methods use ForkJoinPool
– Not managed by Java EE
Always use a managed executor
@Resource
ManagedExecutorService
executor;
33. @OMihalyi
Other parts of being ReactiveOther parts of being Reactive
We’ve shown responsive API
The other 3 reactive concepts:
– Resilience
– Messaging
– Elasticity
34. @OMihalyi
ResilienceResilience
Responsive in the face of failures
Server clusters and transaction isolation
Load balancer in front
Microservices (embedded server)
… reduce single points of failure
35. @OMihalyi
Payara MicroPayara Micro
Application server as executable JAR
Runs WAR apps from command line
automatic and elastic clustering
→ spawn many micro services dynamically
→ replication using distributed cache
→ shared 60MB runtime, 40MB in heap
www.payara.fish
→ → V
36. @OMihalyi
Messaging in Java EEMessaging in Java EE
JMS – traditional solution
– Topics, Queues, Persistence,
Transactional, Repeated delivery
– Simplified API in Java EE 7
●
some bioler-plate still necessary
37. @OMihalyi
Why not make it even simpler?
@Inject @Outbound
Event<MyMsg> ev;
// handle in different JVM
void handle(@Observes
@Inbound MyMsg ev) {
… }
38. @OMihalyi
Payara Micro event busPayara Micro event bus
events handled by any distributed node
– Asynchronous (reactive) micro services
– No need for service registry
On top of CDI events, just 2 qualifiers
– @Outbound event, @Inbound observer
Uses Hazelcast distributed executor
39. @OMihalyi
Elasticity in Java EEElasticity in Java EE
Weakest point of Java EE specs
– Clusters do not scale dynamically
Many provider-specific solutions
JCache JSR – targets Java EE 8
40. @OMihalyi
JCacheJCache
Standard Java API for caching
Distributed
API and CDI binding
Supported by many cache providers
Built in to Payara Server and Payara Micro
43. @OMihalyi
Dynamic scalingDynamic scaling
Just run repeatedly
– binds to a free port to avoid port collisions
All instances autoconnect to a cluster
– Even across network (multicast)
java -jar payara-micro.java
--deploy app.war
--autoBindHttp
44. @OMihalyi
Payara Micro examplePayara Micro example
web service on single node, computation
service scaled to multiple nodes
– Web service fires an @Outbound event
– Computation started on a computation node
●
Synchronisation using Jcache API
– An event with result fired
– Observed by web service and returned
45. @OMihalyi
Fully reactive comes at a greater cost
– Dealing with threads, hard to track origin,
communication overhead
Don’t over-engineer, but leave doors open
Java EE enables gradual improvement
General adviceGeneral advice
Why apps are not inherently like this?
- because of traditionally blocking API and monolithic architectures
- because it is hard (for programmers)
Solutions
- Completely new frameworks (Vert.x)
- learn everything from scratch
- not easy to reuse knowledge
- Improve existing approaches
- add non-blocking API
- continuous improvements where it adds most value
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0 simplified API, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
Established → small costs of upgrade or redesign
Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)