To explain the various aspects of the Speedment Framework, a simple Microservice will be used. This microservice will be a simple catalogue application which supports the basic CRUD (Create, Read, Update, Delete) actions.
This first tutorial of the series will explain the basic architecture of the microservice.
The paragraphs below wil briefly explain all the various components used in the example application. Later chapters in the series will then explain each component in more detail.
Architecture
When setting up a new application, one of the first things to consider is the main architecture of the application. When building microservices, or any kind of SOA for that matter, The one explained below has served me well for a lot of those types of applications. Aside from the main architecture, there are several types of supporting components.
Main Architecture
The main architecture consists of 3 layers and the data storage. This data storage usually comes in the form of a database, but can just as easily be an external secondary microservice.
Controller
The Controller is the main REST interface. This is where the microservice is connected to the outside world. It consists of a series of API methods other applications can call. The Controller handles input validation only. After validating the input, the request is passed on to the next layer.
Handler
The handler is the second layer of the application. Usually there is one handler per controller. The handler is responsible for mapping incoming objects to internal objects and vice versa. After mapping the incoming objects to internal objects, the handler passes the request to the next layer. The handler can split this among several different calls depending on the needed functionality.
Service
The service layer is the final layer in the application. This is the layer where the actual application logic is placed. In the case of the example application, this is where the actual Speedment calls are made.
Usually, services are grouped logically. In case of the example application, there is an ItemService which handles all item related tasks. This does not necessarily mean the service only retrieves item information. It could just as easily enrich the Item object with a Category, which might even be retrieved from an entirely different REST application.
Supporting Components
Application
The first thing needed to run a Spring Boot application is the executable class. Like all Java applications, this is the class containing the public static void main(String[] args) method. Since this class is very basic it is handled here instead if in its own tutorial. The example code below shows the application runner for the example application.
@SpringBootApplication( exclude = SecurityAutoConfiguration.class, scanBasePackages = {"com.ractoc.tutorials.speedment"}) public class MyCatalogueRunner { public static void main(String[] args) { SpringApplication.run(MyCatalogueRunner.class, args); } }
Here the @SpringBootApplication identifies the class as a Spring Boot Application class. This annotation tells Springboot a few things it needs to know when starting the application. In this annotation there are two settings present:
- exclude, this property tells spring which configuration classes to skip.
- scanBasePackages, this property tells spring where to look for component classes to load.
Inside the main method is the call to SpringApplication.run which tells springboot what class to actually use as the base runner class for the application.
The link to the main Spring Boot website can be found in the Links section at the end of this tutorial.
Application properties
Aside from the runner class, there also needs to be a properties file where all the environment dependent properties can be configured. This file should be placed in src/resources/config. This file always has the name application.properties although it is also possible to add different files based on an environment setting provided as a system parameter at the start of the application. The properties in the environment specific properties file overrule the ones in the default properties file. The Spring Boot website has some excellent documentation on how this can be done.
Configuration
Configuration objects are used to configure the application at startup. When building a Speedment enabled RESt microservice, there are several configuration objects that should be considered. Only one of which is required, but all are to be considered.
SpeedmentConfiguration
The SpeedmentConfiguration handles the setup of the actual Speedment framework. The database connection settings are environment dependent and as such should be placed in the application properties file. The can be injected by Spring with the use of annotations.
SwaggerConfiguration
While not required to build a working REST microservice, the SwaggerConfiguration should be considered a valuable addition. This configuration adds runtime generation of a Swagger file to the microservice. Through this interface descriptor, other applications can then generate their client code automatically, making sure it always maps to the API in the correct way.
EmbeddedDatabaseConfiguration
Once again, this configuration is not required for a working REST microservice. What this configuration does is add an embedded MariaDB database to the microservice. This way, the microservice is self-contained. While this is not really usefull in a production environment, it does come in handy in a local development environment. That is why this configuration should have some way to being enabled and disabled based on the environment the REST microservice is run on. Usually this is done via the applications.properties.
Filter
A REST Microservice can have one or more filters. These filters are triggered before the request is forwarded to the actual REST controller. When more then one Filter is implemented, adding the @Order annotation allows setting the order in which they are triggered.
The most common filter added is a CORS filter.
Mapper
Mapper classes map one value object to another. This is done in the Handler layer of the application to make sure no internal state leaves the application. Having a distinct boundary between internal and external objects is good practice because it makes it much easier to make internal changes to the application without running the risk of breaking the external interface.
In the example application, the mappers are generated by MapStruct based on the mapper interface and the classes indicated in the methods on that interface.
Model
This component consists of the value objects used to send and receive data from the client. To make these objects as simple as possible, they use the Lombok framework to generate as much of the code as possible. This means the getters, setters and constructors are all generated by Maven at compile time.
Response
This component consists of the REST response objects used by Spring Boot. These contain the Model components as well as all the relevant HTTP response attributes.
Validation
As much of the validation as possible is done via annotations. This way Spring Boot can handle most of the validation during the conversion between the JSON file and the Java Object. In case of a validation error, the API method in the controller will never actually be called. This means the actual controller component as little actual validation logic as possible. Only when a single model component is reused for more then one purpose will the controller component have any validation logic. For example, the Item model object is used both for the create and update of an item. In case of a create, the ID field MUST be empty. In case of an update, the ID field MUST contain a value. This cannot be validated automatically by Spring Boot bat has te be validated by the controller component. The NAME field MUST always contain a value though, so this can be validated by Spring Boot.
Development Approach
Now that the main architecture of our example application has been created, we can start building the actual application. When building a REST application, there are two possible approaches to take; inside-out and outside-in.
Inside-out
Inside-out means starting with the database and working towards the controller. The advantage of this option is that it’s data-centric. Since it places most of the focus on the actual data being stored in the application. This option is most suited for applications that have a strong data component and mainly need to expose basic data manipulation functionality.
Outside-in
Outside-out means starting from the external entrypoint, the controller, and working inwards towards the database. The advantage of this option is that it focusses on functionality over data. This option is most suited for aplication with a more complex functionality that goes beyond basic data manipulation functionality.
Since the example application is starts out with simple data manipulation, the inside-in approach is the bast fit.
Tutorial Setup
Now that the main architecture of the application has been decided and the approach has been selected it is time to start building the application. In the next few tutorials will explain the different aspects of the application. First the basic Maven setup will be explained, complete with the Speedment setup. After that there is a tutorial about setting up the application database. Since this will be an embedded database, it deserves its own tutorial. After these two tutorials, all the basic prerequisites are there to start building the actual application.
Links
The main Speedment website can be found at https://www.speedment.com
The main documentation for Speedment can be found at https://speedment.github.io/speedment-doc/index.html
The source code for the tutorial series examples can be found at https://github.com/ractoc-tutorials/speedment
This tutorial continuous in the next part of the series, speedment-basics