Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Programming Styles Compared: Spring Framework vis-a-vis Eclipse MicroProfile, Part 2

DZone's Guide to

Programming Styles Compared: Spring Framework vis-a-vis Eclipse MicroProfile, Part 2

In the final part of this quick series, we run and test all the code we wrote last time. Let's get to it!

· Microservices Zone ·
Free Resource

Record growth in microservices is disrupting the operational landscape. Read the Global Microservices Trends report to learn more.

Welcome back! If you missed Part 1, you can check it out here. Now, let's learn how to run and test those apps!

Running the Applications

Starting the Database

We will start the Derby network server with authentication. If Derby is installed in derby_install_dir then change directory to <derby_install_dir>/bin and first execute:

export "DERBY_OPTS=-Dderby.connection.requireAuthentication=true \
-Dderby.authentication.provider=BUILTIN -Dderby.user.demo=demopwd"

Then, start Derby:

./startNetworkServer &

We need to create the database and the table to store data. That needs to be done only once. In the same console where Derby was started, execute the ij command under <derby_install_dir>/bin:

./ij

Then, on the ij prompt, execute ( ij> indicates the prompt) the following:

ij> connect 'jdbc:derby://localhost:1527/CarDB;create=true;user=demo;password=demopwd';

The above command will create a database instance called CarDB (notice the database user and password, as referenced by inventory-application.yaml for Spring and server.xml for Eclipse MicroProfile application). Next, create the car table as:

ij> CREATE TABLE car (brand VARCHAR(25) PRIMARY KEY, inventory INT);

Now, you can check the existence of the table by running show tables, e.g. see the bottom of the list below:

ij> show tables;
TABLE_SCHEM         |TABLE_NAME                    |REMARKS             
------------------------------------------------------------------------
SYS                 |SYSALIASES                    |                    
SYS                 |SYSCHECKS                     |                    
SYS                 |SYSCOLPERMS                   |                    
...       
DEMO                |CAR                           |            

Note that the table shows under the demo schema, which is the value associated with the user parameter in the connect string.

Stopping the Database

Once all the testing is done the database can be stopped. Change the directory to <derby_install_dir>/bin and, first, execute:

export "DERBY_OPTS=-Dderby.connection.requireAuthentication=true \
-Dderby.authentication.provider=BUILTIN -Dderby.user.demo=demopwd"

Then, stop Derby with the following command:

./stopNetworkServer -user demo -password demopwd

Running the Spring Application

Running as an Executable Jar

Change the directory to the root folder, i.e. where pom.xml resides, and execute the following to build the application:

mvn clean install

After the build is done, we can start the application by first exporting the environment variables, as discussed previously, and then invoking the Java executable:

export DB_HOST=localhost
export DB_PORT=1527
export SERVER_PORT=9080
java -jar target/inventories-1.0-SNAPSHOT.jar

You can view the log on the console as application runs. To stop the application simply execute [CTRL-C].

Running as a Docker Image

Make sure that you have logged in to your Docker repository in your console. Change the directory to the root folder, i.e. where pom.xml resides, and execute the following to build the application:

mvn install dockerfile:build -DpushImageTag

After the build is done, run the application as follows:

docker run -d -e "DB_HOST=host.docker.internal" \
-e "DB_PORT=1527" -e "SERVER_PORT=9081" \
    --name inventory-service_spring_app -p 9080:9081 \
    konuratdocker/spark-examples:inventory-service_spring

Comments:

  • We pass the environment variables to the Docker engine via the -e option.

  • We set the server port to 9081 inside the container and map it to the external 9080 port via the -p option.

  • The value of DB_HOST environment variable is set to host.docker.internal for MacOS environment only. For other environments, you could use localhost (see Networking features in Docker Desktop for Mac).

  • To understand how the image reference konuratdocker/spark-example:inventory-service_spring is defined, please consider the pom.xml file discussed previously: under Docker Maven Plugin from Spotify we had defined repository to be konuratdocker/spark-example and  imageTag to be inventory-service_spring. 

  • The name of the running Docker container is defined via the --name option; I've named it inventory-service_spring_app.

Once the Docker image starts running, you can see the logs via:

docker logs --details -f inventory-service_spring_app

To stop the application, execute:

docker container stop <container_id>

where container_id is the ID of the container created when the  docker run command was executed (that ID was printed out as the response to the docker run command above). 

Testing the Spring Application

We assume that the application is running either as an executable or as a Docker image.

Viewing Existing Inventory Records

Open a browser and send an HTTP GET request:

http://localhost:9080/CarInventories/cars/inventories

If there are no records in the database, you will get an empty JSON array.

Creating a New Inventory Record

Populate the car table by sending a few records as HTTP POST to the following URL (set body content type as application/json):

http://localhost:9080/CarInventories/cars/setInventory 

A sample record could be: {"brand":"BMW","inventory":"15"}

Try another one: {"brand":"Chevrolet","inventory":"25"}

Now, if you view existing inventory records you should get something like this:

[
  {
    "brand": "BMW",
    "inventory": 15
  },
  {
    "brand": "Chevrolet",
    "inventory": 25
  }
]

Updating an Existing Inventory Record

The URL to update an existing brand's inventory is the same as the one to create an inventory. The data structure is also the same.

Try updating an existing record by sending, e.g.  {"brand":"BMW","inventory":"35"} to the URL below as HTTP POST (again set body content type as application/json):

http://localhost:9080/CarInventories/cars/setInventory

Now, if you view existing inventory records you will see that the inventory has been updated.

Running the Eclipse MicroProfile Application

Running via Maven

Change the directory to the root folder, i.e. where pom.xml resides, and execute the following to build the application:

mvn clean install

After the build is done, we can start the application by first exporting the environment variables, as discussed previously, and then invoking the mvn executable:

export DB_HOST=localhost
export DB_PORT=1527
export SERVER_PORT=9080
mvn liberty:start-server

The log files will be available under the target/liberty/wlp/usr/servers/defaultServer/logs folder.  To stop the application, execute mvn liberty:stop-server.

Running as a Docker Image

Make sure that you have logged in to your Docker repository in your console. Change the directory to the root folder, i.e. where pom.xml resides, and execute the following to build the application:

mvn install dockerfile:build -DpushImageTag

Let PROJECT_ROOT be the root folder in your development machine where pom.xml resides for Eclipse MicroProfile application. After the build is done, run the application as:

docker run -d -e "DB_HOST=host.docker.internal" \
-e "DB_PORT=1527" -e "SERVER_PORT=9081" \
    --name inventory-service_ol_app -p 9080:9081 \
    -v <PROJECT_ROOT>/target/liberty/wlp/usr/servers:/servers  \
    -v <PROJECT_ROOT>/target/liberty/wlp/usr/shared/resources:/resources  \
    konuratdocker/spark-examples:inventory-service_ol

Comments:

  • For -e and -p options, as well as the value of the DB_HOST environment variable, the same comments as in Spring application apply (previous section). 

  • To understand how the image reference konuratdocker/spark-example:inventory-service_ol is defined, please consider the pom.xml file discussed previously: under the Docker Maven Plugin from Spotify we had defined repository to be konuratdocker/spark-example and  imageTag to be inventory-service_ol. 

  • The name of the running Docker container is defined via the --name option; I've named it inventory-service_ol_app.

  • The local folder <PROJECT_ROOT>/target/liberty/wlp/usr/servers is mapped to the symbolic link 'servers' in the Docker container previously created via RUN ln -s /opt/ol/wlp/usr/servers /servers in the Dockerfile. Similarly, the local folder <PROJECT_ROOT>/target/liberty/wlp/usr/shared/resources is mapped to the symbolic link 'resources' in Docker container previously created via  RUN ln -s /opt/ol/wlp/usr/shared/resources /resources in the Dockerfile.

Once the Docker image starts running, you can see the logs via:

docker logs --details -f inventory-service_ol_app

To stop the application execute

docker container stop <container_id>

where container_id is ID of the container created when the docker run command was executed (that ID was printed out as the response to the docker run command above).

Testing Eclipse MicroProfile Application

This is identical to testing the Spring application.

URI Path Construction

Recall that for both applications the root context is CarInventories. The web resource URIs are defined as:

  • cars/inventories: view existing car inventory

  • cars/setInventory: create/update car inventory

In the Spring application, the root context is established in inventory-application.yaml via the server.servlet.context-path attribute. In the Eclipse MicroProfile application, the root context is established in server.xml, the webApplication element via the contextRoot attribute. The value of contextRoot is populated from pom.xml, app.context.root variable, copied from the warContext (and, hence, the app.name) property. 

For both applications, the web resource URIs cars/inventories and cars/setInventory are established in the controller class, InventoryResource. In the case of Spring, 'cars' is passed to the 'value' attribute in org.springframework.web.bind.annotation.RequestMapping annotation that decorates the class declaration. In the case of Eclipse MicroProfile, 'cars' is passed to the javax.ws.rs.Path annotation that decorates the class declaration. In the case of Spring, 'inventories' and 'setInventory' are passed to the 'value' attribute of the org.springframework.web.bind.annotation.RequestMapping annotation decorating the getInventoriesand setInventory methods, respectively. In the case of Eclipse MicroProfile, 'inventories' and 'setInventory' are passed to the javax.ws.rs.Path annotation that decorates the getInventories  and setInventory methods, respectively.

Conclusions

In this article series, we implemented a simple microservice application twice, once via the Spring framework and once via the Eclipse MicroProfile with Open Liberty runtime, using the same baseline design. The purpose of the exercise was to compare the two frameworks for the core application components that comprise the Model and Controller in a Model-View-Controller architecture. 

We observed that the code bases for the two frameworks are quite similar. A notable difference is the data access layer where the Spring framework required less coding. This was due to the fact that the Spring Data JPA plugin did most of the work behind the scenes. 

For generating the executable Docker images of each application, we used Maven with the Dockerfile Maven Plugin from Spotify. Aside from obvious differences due to different library dependencies, we observed that the pom.xml files for each application had similar structures. 

By and large, for the relatively simple core microservice considered in this article, no substantial differences were observed between the two approaches. However, to compare more involved features, e.g. service registries, load balancing, health monitoring etc., additional prototyping would be needed.

Learn why microservices are breaking traditional APM tools that were built for monoliths.

Topics:
microservices ,spring tutorial ,eclipse microprofile ,microservices tutorial java ,microservices architecture java

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}