The Most Popular Technologies for Java Microservices Right Now
This article describes the main technical challenges facing modern web applications and lists some frameworks, libraries, and practices used to solve these problems.
Join the DZone community and get the full member experience.Join For Free
My name is Viacheslav Aksenov, I am a backend developer and in recent years I have been writing web applications in Java/Kotlin. Throughout my practice, I have met with various systems both in production and in pet projects. Some systems had their own "bicycles," but most were based on very similar technical solutions.
The main idea of this article is to describe the main technical challenges facing modern web applications. And also list those frameworks and libraries that are most often used to solve these problems. We'll grab some infrastructure as a bonus.
Thus, beginners who do not know what to expect from corporate development or in which framework to improve their skills will be able to see the picture of the world a little wider and make the right choice.
What Are the Most Popular Technical Tasks that Should Be Solved by Almost Any Microservice?
These are the most popular tasks. The list can be different from project to project, of course.
- Complex business logic,
- HTTP requests routing,
- Database integration,
- Sync and async message transport,
Make Complex Logic Readable and Expandable
There are a lot of concepts and patterns like SOLID, KISS, DRY, etc. But in this article, I want to discuss a different one.
The industry standard for developing web applications in Java is Spring. This does not mean that you cannot meet the conditional Javalin or Ktor or something else, so let's consider the main thing that Spring loves a lot and implements in any other framework in one way or another. This approach is the dependency injection (DI) pattern.
In short, DI is about the fact that you wrote a separate code brick — a class and use it in those places where the logic of this brick is required instead of writing a new one.
If we go deeper, DI is the concept in which objects get other required objects from outside.
DI can be implemented in any programming language. The general concept behind dependency injection is called Inversion of Control.
In Java, class dependency is where a class is dependent on another class because it uses an instance of the other class. e.g., a class accessing a service would have a dependency on the service class.
So in any project in which you find yourself, there will be a certain context in which these code bricks will be stored, and the presence of this context does not depend on the framework chosen for development. Let me tell you a secret: even when one of the most progressive European banks abandons Spring and develops web services in pure Java, they still have a context in which all "services" are laid.
Route of the HTTP Requests and Responses
The tasks that are included in this layer are to direct each HTTP request to the method that will process it. This also includes a description of the data model that is passed as input, as well as the serialization of the request and the deserialization of the response.
At the moment, the most popular framework for building web services is Spring, namely Spring Boot, which immediately has a built-in tomcat or Netty servlet container, depending on which configuration set is selected.
So to describe the endpoints of your application, you will almost always, in 9 out of 10 cases, have to use the @GetMapping and @PostMapping annotations. In that single option out of 10, a library that was written in-house will be responsible for routing and will do the same thing as Spring Boot, only "in its own way."
Example of controller layer to handle the HTTP request.
Since Spring Boot is used almost everywhere, the de facto industry standard for serializing and deserializing HTTP requests and responses is the Jackson library. It is also included in the Spring Boot dependencies and is actively used internally.
To use it, you will need to create an ObjectMapper instance and configure it if necessary. Keep in mind that the Spring Context will already have an initialized instance configured the way Spring needs it, so use it with care.
Also, sometimes they use a library from Google — GSON, it does not fundamentally differ from Jackson.
No web application is complete without the use of a data store. Anything can be such storage — a text file, a redis cache. But most often, of course, a database is used, and again, the industry-standard now is:
- PostgreSQL (high performance, free).
- Oracle (high performance, slightly less convenient API, has a vendor distribution model).
- MongoDB (very convenient for start-up development due to its non-relational nature, it is extremely common in cloud solutions).
To access the database, you need to be able to open connections, monitor open streams, execute SQL queries, convert, and so on.
Currently, the ORM approach — Object-Relational Mapping — is widely used. To cover the whole range of tasks for storing database information, you need to solve 4 types of operations (the same as CRUD) — create, read, update, delete.
The most popular implementation of this approach is the Hibernate framework. It is able to generate SQL queries depending on the code and entities, but it does not always do it optimally.
We also did not forget that Spring Boot is the industry standard, and there is also an ORM implementation for working with the database — Spring Data JPA. It is a wrapper over Hibernate that can be used at a higher level of abstraction. It is conveniently configured and even allows you to write queries without SQL at all. But if there is a need to write raw SQL and execute it, that can also be done.
And finally, the most powerful tool that provides the best performance, but does not actually implement the ORM ideology — jdbcTemplate. Its essence is in the execution of raw SQL queries. But if you write your own conversion logic on top of it and use it to store entities in the database according to the ORM logic, you will get a very fast and customizable tool.
Sync and Async Message Transport
As a means of transport for messages, synchronous methods such as HTTP GET/POST requests are used. They use either RestTemplate, which is included in the list of Spring Boot dependencies or a newer one and WebClient.
Message brokers are used for asynchronous communications, the most popular of which are rabbitmq and kafka. In this article, I will not dive into their difference from each other. I will dwell on the method of integrating with them from the code — Spring Boot modules are used for this, or a self-written "bike", if we are talking about a large company. The most popular extensions for a Spring Boot project are spring-kafka and spring-boot-starter-amqp.
Testing is an integral part of any self-respecting development. In our realities, if development is not carried out immediately in the TDD (Test Driven Development) paradigm, then a code threshold is set within the team, which must be covered by tests.
There are the following the most popular types of tests:
- Unit tests — a separate class, or even its method, is taken for testing.
- Integration tests — a separate section of the system is tested along with integration with other elements. For example, integration testing of a process in a service and its work with a database.
Third-party libraries in tests are needed to solve problems of direct testing, as well as mocking (emulation of the response of some service or integration).
For testing, junit 5, TestNG, kotest (kotlin) are most often used. For mocking, the Java development standard is mockito, for kotlin it is mockk. To test Spring Boot applications, the spring-boot-starter-test starter is used, which already includes all the necessary dependencies and knows how to build a Spring Context for each test.
Unit test diagram.
Example of unit test in Kotest with MockK.
It is extremely rare that processes are so complex and ornate that testing one scenario requires calling many endpoints of one service. In this case, you need to be prepared for the fact that you will encounter self-written "bicycles" such as a separate Spring Boot application that deals with calling endpoints and testing the main application under test.
Also, there are a lot of different practices that can help to improve the whole process of developing your services.
Static Code Analysis
The essence of static code analysis is checking the code for compliance with the conditions — the absence of duplicate code, test coverage, compliance with the code style, etc.
As a rule, things such as "Linters" are used to check if the style code matches. By their nature, these are the same plugins for gradle, maven. Usually, they are launched automatically during the configured pipeline. Sometimes you need to be prepared to call a command that will format your code according to the rules configured in the linter.
For Java, the most popular linters are Checkstyle and SonarLint. For Kotlin — ktlint.
For static analysis, with hints and other useful things, the vast majority of projects use a customized sonarqube. For small projects — codacy or codeclimate. I would recommend using them even for pet projects.
However, not all projects have built-in processes to keep the code clean. This can happen for various reasons — a rapidly changing project, and insufficient time for the team to build processes.
CI/CD — Continuous Integration and Continuous Deployment are processes without which it is impossible to imagine modern development. You can pack jar files by hand and manually deploy them to servers, but this increases the likelihood of errors caused by human factors. So that basic infrastructure actions do not cause a big headache, scripts for assembly and deployment are usually used.
As a rule, ordinary developers have to do this quite rarely. Usually, it is in the DevOps area of engineers. As a rule, scripts are executed in the Jenkins environment, or Gitlab CI.
The scripts themselves are a set of actions that must be performed to achieve a particular goal. The most difficult thing can be to understand how the code inside the application and with the deployment is associated. Build systems are used for this. At the moment, there are two most popular ones for the backend — Maven and Gradle. 9 times out of 10 it's Maven, it's pretty crude but functional and has a lot of plugins. Gradle is also occasionally found, which in turn is more recent, but less widespread. In terms of functionality, it is in no way inferior to maven in most moments.
In this article, we looked at the main technical issues that a backend developer has to deal with at the present time. As well as the main ways of solving problems for each of these technical areas. I would be glad for information in the comments about what tool you use in your project to solve the problem and whether you are completely satisfied with this tool.
Opinions expressed by DZone contributors are their own.