Demystifying Microservices For Java EE Developers by Payara
Demystifying Microservices For Java EE Developers by Payara
Microservices for
Java EE Developers
by David Heffelfinger
© Payara Services Ltd
Contents
1
© Payara Services Ltd
2
© Payara Services Ltd
each instance of the application server, and, in some cases, the “tables are
turned” by having the application server be just a library that the application
uses as a dependency. With these modern application servers, several instances
of the application server are often deployed to a server, making modern Java EE
very suitable for microservices development. Many modern, lightweight Java EE
application servers are embeddable, allowing the creation of an “Uber JAR”,
which includes both the application code and the application server libraries.
This “Uber JAR” is then transferred to the server and run as a standalone
application. Payara Micro is an example of a lightweight application server that
offers this functionality.
In addition to “Uber JARs”, modern
application servers can be added to a Can Java EE be used to
container image (such as Docker), develop microservices
then? The answer is a
allowing an application to be deployed as a
resounding ‘yes’!
thin WAR, typically only a few kilobytes
in size. This approach has the advantage Java EE developers can
of very fast deployments, usually under 2 leverage their expertise
seconds. and deploy their code to
one of the lightweight
By deploying to a contemporary Java EE application servers
Web Profile compliant application server suitable for microservices
(or, as explained in the previous development, such as
Payara Micro.
paragraph, creating an “Uber JAR”), Java
EE developers can certainly leverage their
existing expertise to develop microservices compliant applications.
Now that we've established that Java EE is very much suitable for a microservice
architecture, let's explore some of the advantages and disadvantages of the
microservices approach.
Microservices Advantages
3
© Payara Services Ltd
Microservices Disadvantages
4
© Payara Services Ltd
5
© Payara Services Ltd
MIGRATING TO MICROSERVICES
If we have an existing, traditionally designed application, migrating to
microservices may or may not make sense. In this case, not only do we need to
consider the benefits vs. the disadvantages of a microservice architecture, we
also need to consider the fact that a migration to microservices may not provide
much value to our end users. As much as we software developers like to
modernize existing applications, the fact of the matter is that redesigning
existing applications does not bring direct value to end users. If there are
pressing new business requirements or defects to fix, then users may be better
served by keeping the existing architecture.
If we decide that migrating to a microservice architecture makes sense, existing
legacy systems typically cannot be changed overnight. There are a few
approaches we can follow to migrate existing applications to a microservice
architecture.
Iterative refactoring
Partial refactoring
6
© Payara Services Ltd
7
© Payara Services Ltd
We will be using Payara Micro to deploy our example code. Our application will
be developed as three modules, first a microservices client, followed by a
microservice implementation of a controller in the MVC design pattern, then an
implementation of the DAO design pattern implemented as a microservice.
Before delving into developing our services, we will first develop a microservices
client in the form of an HTML5 page using the popular Twitter Bootstrap CSS
library, as well as the ubiquitous jQuery JavaScript library. The JavaScript code in
the front end service will invoke the controller microservice, passing a JSON
representation of user entered data. The controller service will then invoke the
persistence service and save data to a database. Each microservice will return an
HTTP code indicating success or error condition.
The most relevant parts of our client code are the HTML form and the jQuery
code to submit the form to our Controller microservice.
We will only show small snippets of code here, the complete code for the
sample application can be found at
http://info.payara.fish/hubfs/payara_microprofile_example.zip
8
© Payara Services Ltd
<form id="customerForm">
<div class="form-group">
<label for="salutation">Salutation</label><br/>
<option value="Mr">Mr</option>
<option value="Mrs">Mrs</option>
<option value="Miss">Miss</option>
<option value="Ms">Ms</option>
<option value="Dr">Dr</option>
</select>
</div>
<div class="form-group">
</div>
<div class="form-group">
</div>
<div class="form-group">
</div>
<div class="form-group">
</div>
</form>
9
© Payara Services Ltd
As we can see, this is a standard HTML form using Twitter Bootstrap CSS classes.
Our page also has a script to send form data to the controller microservice.
<script>
$(document).ready(function () {
$("#submitBtn").on('click', function () {
$.ajax({
headers: {
'Content-Type': 'application/json'
},
crossDomain: true,
dataType: "json",
type: "POST",
url: "http://localhost:8180/CrudController/webresources/customercontroller/",
data: JSON.stringify(customerData)
$("#msg").removeClass();
$("#msg").toggleClass("alert alert-success");
} else {
$("#msg").removeClass();
$("#msg").toggleClass("alert alert-danger");
});
});
});
</script>
10
© Payara Services Ltd
The script is invoked when the Submit button on the page is clicked. It uses
jQuery's serializeArray() function to collect user-entered form data and
create a JSON formatted array with it. The serializeArray() function
creates an array of JSON objects, each element on the array has a name property
matching the name attribute on the HTML markup, and a value property
matching the user-entered value.
For example, if a user selected “Mr” in the salutation drop down, entered “John”
in the first name field, left the middle name blank, and entered “Doe” as the last
name, the generated JSON array would look like this:
[{"name":"salutation","value":"Mr"},{"name":"firstName","value":"John
"},{"name":"middleName","value":""},{"name":"lastName","value":"Doe"}
]
Notice that the value of each “name” property in the JSON array above matches
the “name” attributes in the HTML form and the corresponding “value” attributes
match the user entered values.
Since the generated HTTP request will be sent to a different Payara Micro
instance, we need to set the crossDomain property of the Ajax settings object
to true, even though we are deploying all of our microservices to the same
server (or, in our case, to our local workstation).
Notice that the url property value of the Ajax setting objects has a port of 8180,
as we need to make sure our Controller microservice is listening to this port
when we deploy it.
We can deploy our View microservice from the command line as follows:
11
© Payara Services Ltd
Payara Micro is distributed as an executable JAR file; therefore, we can start it via
the java -jar command. The exact name of the jar file will depend on the
version of Payara Micro you are using.
By default, Payara Micro instances running on the same server form a cluster
automatically, for our simple example we don't need this functionality, therefore
we used the --noCluster command line argument.
The --deploy command line argument is used to specify the artifact we want
to deploy, in our case it is a war file containing the HTML5 page serving as the
user interface of our example application.
We can examine Payara Micro output to make sure our application was deployed
successfully.
[2017-01-18T20:35:54.211-0500] [Payara Micro 4.1] [INFO] [AS-WEB-
GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=1
_ThreadName=main] [timeMillis: 1484789754211] [levelValue: 800]
Loading application [CrudView] at [/CrudView]
12
© Payara Services Ltd
When the user clicks on the Submit button, the client passes a JSON
representation of user-entered data to the controller service.
13
© Payara Services Ltd
@Path("/customercontroller")
public CustomerControllerService() {
@OPTIONS
return Response.ok("")
.header("Access-Control-Allow-Origin",
"http://localhost:8080")
.header("Access-Control-Allow-Headers", "origin,” +
“content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.build();
@POST
@Consumes(MediaType.APPLICATION_JSON)
Response response;
Response persistenceServiceResponse;
CustomerPersistenceClient client =
new CustomerPersistenceClient();
14
© Payara Services Ltd
persistenceServiceResponse = client.create(customer);
client.close();
if (persistenceServiceResponse.getStatus() == 201) {
response = Response.ok("{}").
header("Access-Control-Allow-Origin",
"http://localhost:8080").build();
} else {
response = Response.serverError().
header("Access-Control-Allow-Origin",
"http://localhost:8080").build();
return response;
JsonArray jsonArray;
new StringReader(customerJson))) {
jsonArray = jsonReader.readArray();
switch (propertyName) {
case "salutation":
customer.setSalutation(propertyValue);
break;
case "firstName":
customer.setFirstName(propertyValue);
15
© Payara Services Ltd
break;
case "middleName":
customer.setMiddleName(propertyValue);
break;
case "lastName":
customer.setLastName(propertyValue);
break;
default:
LOG.log(Level.WARNING, String.format(
"Unknown property name found: %s",
propertyName));
break;
return customer;
The main logic of our controller service is in the addCustomer() method. This
method receives the JSON string sent by the client as a parameter. In this
16
© Payara Services Ltd
17
© Payara Services Ltd
Let's now take a look at the implementation of our JAX-RS client code.
public class CustomerPersistenceClient {
public CustomerPersistenceClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget =
client.target(BASE_URI).path("customerpersistence");
return webTarget.request(
javax.ws.rs.core.MediaType.APPLICATION_JSON).
post(javax.ws.rs.client.Entity.entity(customer,
javax.ws.rs.core.MediaType.APPLICATION_JSON),
Response.class);
client.close();
As we can see, our client code is a fairly simple class making use of the JAX-RS
client API: We declare a constant containing the base URI of the service we are
invoking (our persistence service), and then create a new instance of
javax.ws.rs.client.ClientBuilder in the class constructor and set its
18
© Payara Services Ltd
base URI and path to match the appropriate values for our persistence service.
Our client class has a single method, which submits an HTTP POST request to the
persistence service, then returns the response sent back from it.
Our controller service only uses two Java EE APIs, JAX-RS and JSON-P. Both APIs
are supported by the MicroProfile initiative, therefore we can deploy it to the
scaled-down version of Payara Micro,
By examining Payara Micro's output we can see that our code deployed
successfully.
Now that we have successfully deployed our controller service, we are ready to
go through the final component of our application - the persistence service.
19
© Payara Services Ltd
Our persistence service is a JAX-RS RESTful web service; it is a thin wrapper over
a class implementing the DAO design pattern.
package fish.payara.crudpersistence.service;
@ApplicationScoped
@Path("customerpersistence")
@Context
@Inject
@POST
@Consumes(MediaType.APPLICATION_JSON)
try {
customerDao.create(customer);
} catch (Exception e) {
return Response.serverError().build();
return Response.created(uriInfo.getAbsolutePath()).build();
In this case, since the client code invoking our service is developed in Java, there
is no need to convert the JSON string we receive to Java code, this is done
automatically under the covers. Our create() method is invoked when the
20
© Payara Services Ltd
@ApplicationScoped
@Transactional
@PersistenceContext(unitName = "CustomerPersistenceUnit")
em.persist(customer);
Our DAO couldn't be much simpler, it implements a single method that invokes
the persist() method on an injected instance of EntityManager.
21
© Payara Services Ltd
Examining Payara Micro's output we can see that our persistence service was
deployed successfully.
Now that we have deployed all three components of our application, we are
ready to see it in action.
Once the user enters some data and clicks the submit button, we should see a
“success” message at the top of our page.
22
© Payara Services Ltd
If we take a look at the database, we should see that the user-entered data was
persisted successfully.
23
© Payara Services Ltd
Java EE 8
One welcome addition to Java EE 8 will be the inclusion of a brand new Java API
for JSON Binding (JSON-B), which will provide a standard way of populating Java
objects from JSON, and vice versa. Currently we need to rely on manually writing
code to populate Java from JSON, or use a non-standard APIs to populate Java
objects from JSON (i.e. Jackson, GSON, MOxy, etc).
Java EE 8 will include a new version of JAX-RS, namely JAX-RS 2.1, which will
introduce support for the aforementioned JSON-B API, as well as Server Sent
Events (SSE), improved CDI integration, non-blocking interceptors via the NIO
API, and declarative security, among other new features.
Java EE 8 will include a new version of the Servlet API, namely Servlet 4.0, which
will include support for the HTTP/2 protocol. HTTP/2 reduces network latency
and allows server push (that is, data can be sent from the server to the client
without having to wait for a client request).
New versions of CDI, Bean Validation will also be included with Java EE 8, which
may come in handy regardless of if we are developing microservices or a
traditionally designed application.
Java EE 9 will add even more new features and APIs that may be useful when
developing microservices.
Java EE 9
24
© Payara Services Ltd
The Java language has been around for 21 years, but technologies that were
popular when Java was first released are not so popular today (CORBA, for
instance). For backward compatibility purposes, modern versions of Java need to
support these legacy technologies.
Project Jigsaw will allow Java application developers to pick and choose what
technologies they need in their applications, eliminating the need to carry all this
legacy baggage from 21 years ago.
Once project Jigsaw is released, Java EE library dependencies may be declared as
project Jigsaw modules, and included only if the application being developed
requires it. This will eliminate the need for the concept of Java EE profiles, as
application developers will be able to freely include only necessary Java EE API's
in their applications.
There are plans to modify JAX-RS in Java EE 9 to include first class support for
the Circuit Breaker design pattern. This pattern allows an application to stop
invoking a service after a predetermine number of attempts, returning instead a
cached response or an error.
Other Java EE 9 features suitable for microservices include a new Event API ,
support for NoSQL databases and a new State Management API.
MicroProfile
25
© Payara Services Ltd
Our example controller service uses the scaled down version of Payara
Micro, which - as previously mentioned - is an implementation of the
MicroProfile initiative.
26
© Payara Services Ltd
CONCLUSION
As we can see, Java EE is very suitable for microservices development. Java EE
developers can leverage their existing knowledge to develop a microservice
architecture and deploy them to modern, lightweight application servers such as
Payara Micro. Additionally, it isn't necessary to “throw the baby out with the
bath water” so to speak, when migrating to microservices. Traditional Java EE
applications can interact with microservices quite well, and can be refactored
iteratively into a microservices architecture when it makes sense. Whether
developing new applications following a microservice architecture, refactoring
an existing application to microservices, or modifying existing applications to
interact with microservices, Java EE developers can leverage their existing skills
for the task at hand.
27
© Payara Services Ltd
It is small, <70 MB in size, and incredibly simple to use. With its automatic and
elastic clustering, Payara Micro is designed for running Java EE applications in a
modern containerized / virtualized infrastructure, using automated provisioning
tools like Chef, Ansible or Puppet.
That’s not all! Using the Hazelcast integration, each Payara Micro process will
automagically cluster with other Payara Micro processes on the network, giving
web session resilience and a fully distributed data cache using Payara’s JCache
support.
28