How to bake reactive
behavior into your Java EE
applications
Ondrej Mihályi
@OMihalyi
@OMihalyi
AgendaAgenda
➢
What is a reactive app
➢
Support in Java EE 7
➢
Java 8 joins the game
➢
Payara Micro additions
➢
Live demo
➢
Common pitfalls
@OMihalyi
Ondrej
Mihályi
Web:
itblog.inginea.eu
Twitter:
Ondrej
Mihályi
Web:
itblog.inginea.eu
Twitter:
Payara suppor
engineer
Java EE developer
Java EE lecturer
Java blogger
Scrummaster
@OMihalyi
Reactive applicationReactive application
@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
@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
@OMihalyi
Traditional approachTraditional approach
Request started
→ external resource required (DB, WS, files)
→ request external resource
→ external resource is slow
→ what do we do?
We SIMPLY wait…
@OMihalyi
Traditional approachTraditional approach
We SIMPLY wait…
Simple
Thread-safe
Sufficient when waiting time is
negligible
@OMihalyi
Traditional approachTraditional approach
Blocking calls:
JDBC:
ResultSet rs =
stmt.executeQuery(q);
@OMihalyi
Traditional approachTraditional approach
Blocking calls:
JPA:
List r =
query.getResultList();
Servlet:
response.getWriter()
.print(s);
@OMihalyi
Traditional approachTraditional approach
Blocking design:
– Servlet filters
– Interceptors
– JSF lifecycle
@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
@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
@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
@OMihalyi
@Asynchronous - Fire-and-
forget
@Asynchronous - Fire-and-
forget
@Asynchronous
void fireAndForget
(String message)
{
… // long-running task
}
@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();
@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();
@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)
@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
@OMihalyi
Non-blocking APINon-blocking API
JAX-RS AsyncResponse
@Suspended@GET
void get(@Suspended
AsyncResponse r)
…
// in another thread
response.resume("OK");
@OMihalyi
Non-blocking APINon-blocking API
JAX-RS AsyncResponse
@Suspendedvoid get(@Suspended
AsyncResponse response)
…
// in another thread
response
.resume("OK");
@OMihalyi
Non-blocking APINon-blocking API
JAX-RS async client
resourceTarget
.request(MediaType.TEXT_PLAIN)
.async()
.get(new
InvocationCallback
() { … });
@OMihalyi
CDI events + @AsynchronousCDI events + @Asynchronous
CDI events decouple components
– one-way communication
– handlers triggered in the same thread
→ emitter is blocked
Handlers are asynchronous EJB methods
– triggered in anyther thread
→ emitter not blocked
@OMihalyi
@Inject
Event<MyEvent> ev;
…
ev.fire(new MyEvent());
…
@Asynchronous
void handle(@Observes
MyEvent ev) { … }
@OMihalyi
Summary of approachesSummary of approaches
Traditional blocking API
– Easy to use, halts execution until finished
→→
@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
@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()
@OMihalyi
thenComposeAsync()thenComposeAsync()
CompletableFuture<String>
cf = new
CompletableFuture<>();
…
cf.thenComposeAsync( r ->
return callThatReturnsCF(r);
), executor)
…
cf.complete(awaitResult())
@OMihalyi
thenComposeAsync()thenComposeAsync()
…
cf.thenComposeAsync(
r -> returnsCF(r)
), executor)
.thenComposeAsync(…
…
cf.complete(r);
@OMihalyi
Java EE + Java 8Java EE + Java 8
Future → CompletableFuture ?
– No, not compatible
Callbacks → CompletableFuture
– callback triggers cf.complete()
Pass CF as additional parameter
@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);
@OMihalyi
Use managed executorsUse managed executors
CF async methods use ForkJoinPool
– Not managed by Java EE
Always use a managed executor
@Resource
ManagedExecutorService
executor;
@OMihalyi
Other parts of being ReactiveOther parts of being Reactive
We’ve shown responsive API
The other 3 reactive concepts:
– Resilience
– Messaging
– Elasticity
@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
@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
@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
@OMihalyi
Why not make it even simpler?
@Inject @Outbound
Event<MyMsg> ev;
// handle in different JVM
void handle(@Observes
@Inbound MyMsg ev) {
… }
@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
@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
@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
@OMihalyi
@Inject MyCache cache;
…
value = cache.get(key);
…
@CacheResult
Object get(
@CacheKey Object key)
JCache CDI bindingJCache CDI binding
@OMihalyi
mycache.put(key, value);
…
@CachePut
void put(
@CacheKey Object key,
@CacheValue Object v)
{ // body can be empty }
JCache CDI bindingJCache CDI binding
@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
@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
@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
@OMihalyi
Questions?Questions?
Thank you

How to bake reactive behavior into your Java EE applications

Editor's Notes

  • #4 dfds
  • #5 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
  • #7 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0 simplified API, managed executor)
  • #8 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #9 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #10 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #11 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #12 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #13 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #14 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #15 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #16 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #17 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #18 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #19 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #20 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #21 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #22 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #23 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #24 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #25 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #26 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #27 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #28 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #29 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #30 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #31 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #32 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #33 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #34 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #35 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #36 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #37 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #38 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #39 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #40 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #41 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #42 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #43 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #44 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #45 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)
  • #46 Established → small costs of upgrade or redesign Improvements → simplifications (EJB3, CDI, JMS 2.0, managed executor)