- Why was this project created?
- Elements included in this project
- Previous steps
- Security services
- Rest API documentation
- gRPC communication
- JMS communication
- Native images
- Docker
Basically to know how to create a project using the microservices approach with 6th version of Spring framework. Due to there are several options we can use for different features included in a microservice architecture, the main purpose of this project is explore the most widely used creating a good base we will be able to use in a real one.
The current project is based on previous the one Spring5Microservices.
Below is shown a brief introduction to the subprojects included in this one:
Server used to register all microservices included in this project. In this case, using Netflix Eureka
each client can simultaneously act as a server, to replicate its status to a connected peer. In other words, a client retrieves a list of all connected
peers of a service registry and makes all further requests to any other services through a load-balancing algorithm (Ribbon by default).
Configuration server used by the included microservices to get their required initial values like database configuration, for example. Those configuration values have been added into the project:
As you can see, there is a specific folder for every microservice and the important information is encoded (the next code is part of security-custom-service-dev.yml file):
spring:
datasource:
url: jdbc:postgresql://localhost:5432/spring6
username: spring6
# Using environment variable ENCRYPT_KEY=ENCRYPT_KEY
# Raw password: spring6
password: "{cipher}c8e1f3a8e0f5d7246a0dcbe620b97de51b580a1ef16f80ffafd3989920287278"
To increase the security level, in the config-server microservice I have deactivated the decryption in application.yml:
spring:
cloud:
config:
server:
encrypt:
# We will send encrypted properties
enabled: false
Sending the information encrypted and delegating in every microservice the labour of decrypt it. That is the reason to include in their pom.xml files, the dependency:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-rsa</artifactId>
<version>${spring-security-rsa.version}</version>
</dependency>
Using Spring Gateway Server WebFlux, this is the gateway
implementation used by the other microservices included in this proof of concept. This module contains a filter to registry every web service invoked, helping
to debug each request.
Full integration with Oauth 2.0 + Jwt functionality provided by Spring Authorization Server, used to be able to manage authentication/authorization functionalities through access and refresh tokens. With this microservice working as Oauth 2.0 Server, we will be able to configure the details of every allowed application using the database table: security.oauth2_registered_client.
On the other hand, several customizations have been included to manage the creation of access JWT token and how to append additional information too.
The technologies used are the following ones:
- Spring Data JDBC to speed up data access, persistence, and management between Java objects and database queries.
- Flyway as version control of database changes.
- Lombok to reduce the code development in entities and DTOs.
- Hazelcast as cache to reduce the invocations to the database.
- SpringDoc-OpenApi to document the endpoints provided by the microservice using Swagger.
In this microservice, the layer's division is:
- repository layer used to access to the database.
- service containing the business logic.
On the other hand, there are other important folders:
- configuration with several classes used to manage several areas such: security, documentation, database or cache.
- model to store the entities.
Regarding Flyway, using application.yml the project has been configured to avoid invoking it when this microservice is launched or packaged:
spring:
flyway:
enabled: false
So, if you want to manage it manually, you can create a new maven configuration. The next picture displays how to do it using IntelliJ IDEA:
All the managed SQL files are located in the folder changelog.
Based on JWT token, this module was created to centralize the management of authentication/authorization functionalities. Its main purpose is provided a completely multi-application platform to generate/manage their own access and refresh tokens (including additional information), choosing between the options defined in TokenType:
- JWS
- JWE
- ENCRYPTED_JWS
- ENCRYPTED_JWE
The provided algorithms to sign the JWT tokens, that is, to generate JWS or the internal one inside ENCRYPTED_JWS are located in TokenSignatureAlgorithm.
On the other hand, the available algorithms selecting JWE or ENCRYPTED_JWE are defined in TokenEncryptionAlgorithm
Every application will be able to manage its own token configuration/generation adding a new row in the database table: security.application_client_details and including/developing a new value in SecurityHandler.
The technologies used are the following ones:
- Hibernate as ORM to deal with the PostgreSQL database.
- JPA for accessing, persisting, and managing data between Java objects and database.
- Spring Data JDBC to speed up data access, persistence, and management between Java objects and database for some queries.
- Flyway as version control of database changes.
- Lombok to reduce the code development in entities and DTOs.
- Hazelcast as cache to reduce the invocations to the database.
- NimbusJoseJwt to work with JWS/JWE tokens.
- SpringDoc-OpenApi to document the endpoints provided by the microservice using Swagger.
- Webflux creating a reactive REST Api to manage the authentication/authorization requests.
In this microservice, the layer's division is:
- application parent folder of the microservice groups whose authentication/authorization is managed by this one.
- repository layer used to access to the database.
- service containing the business logic.
- controller REST Api using Spring Webflux.
On the other hand, there are other important folders:
- configuration with several classes used to manage several areas such: security, documentation, database, cache, exception handlers, etc.
- model to store the entities.
- dto custom objects to contain specific data.
- util to manage the JWS/JWE functionality.
Regarding Flyway, using application.yml the project has been configured to avoid invoking it when this microservice is launched or packaged:
spring:
flyway:
enabled: false
So, if you want to manage it manually, you can create a new maven configuration. The next picture displays how to do it using IntelliJ IDEA:
All the managed SQL files are located in the folder changelog.
One order has several order lines and one order line mainly contains: concept, amount and cost. The main purpose of this microservice is the creation of a small one on which I am using the following technologies:
- MyBatis replacing the traditional pair Hibernate/JPA by adding more code to deal with the database but improving the performance.
- Flyway as version control of database changes.
- Lombok to reduce the code development in models and DTOs.
- MapStruct used to easily convert between models and DTOs and vice versa.
- SpringDoc-OpenApi to document the endpoints provided by the microservice using Swagger.
- Spring OAuth 2.0 Resource Server to handle the security through the microservice security-oauth-service.
- MVC a traditional Spring MVC Rest API to manage the included requests.
- gRPC server, more information in gRPC communication.
- Kafka producer, more information in JMS communication.
In this microservice, the layer's division is:
- mapper layer used to access to the database.
- service containing the business logic.
- controller REST Api using Spring MVC.
On the other hand, there are other important folders:
- configuration with several classes used to manage several areas such: security, documentation, database, exception handlers, etc.
- model to store the entities.
- dto custom objects to contain specific data.
- util/converter to translate from models to DTOs and vice versa.
Regarding Flyway, using application.yml the project has been configured to avoid invoking it when this microservice is launched or packaged:
spring:
flyway:
enabled: false
So, if you want to manage it manually, you can create a new maven configuration. The next picture displays how to do it using IntelliJ IDEA:
All the managed SQL files are located in the folder changelog.
Microservice used to manage invoices and related customers. The main purpose of this microservice is the creation of a small one on which I am using the following technologies:
- Hibernate as ORM to deal with the PostgreSQL database.
- JPA for accessing, persisting, and managing data between Java objects and database.
- Flyway as version control of database changes.
- Lombok to reduce the code development in entities and DTOs.
- SpringDoc-OpenApi to document the endpoints provided by the microservice using Swagger.
- Webflux creating a reactive REST Api to manage the authentication/authorization requests.
- gRPC client, more information in gRPC communication.
- Kafka consumer, more information in JMS communication.
In this microservice, the layer's division is:
- repository layer used to access to the database.
- service containing the business logic.
- controller REST Api using Spring Webflux.
On the other hand, there are other important folders:
- configuration with several classes used to manage several areas such: security, documentation, database, exception handlers, etc.
- model to store the entities.
- dto custom objects to contain specific data.
- util/converter to translate from models to DTOs and vice versa.
Regarding Flyway, using application.yml the project has been configured to avoid invoking it when this microservice is launched or packaged:
spring:
flyway:
enabled: false
So, if you want to manage it manually, you can create a new maven configuration. The next picture displays how to do it using IntelliJ IDEA:
All the managed SQL files are located in the folder changelog.
Maven project that includes common code used in several microservices, with different useful helper classes like:
- ArrayUtil
- AssertUtil
- CollectionUtil
- CollectorsUtil
- ComparatorUtil
- DateTimeUtil
- EnumUtil
- ExceptionUtil
- FunctionUtil
- MapUtil
- NumberUtil
- ObjectUtil
- PredicateUtil
- StringUtil
Generic Cloneable interface improving provided one. New generic interfaces used to provide common conversion functionality using MapStruct:
And functional programming structures and useful classes like:
- Either as an alternative to Optional for dealing with possibly missing values.
- Function improvements.
- Lazy to manage a lazy evaluated value.
- PartialFunction unary function where the domain does not necessarily include all values of the type used.
- Predicate improvements.
- Try representing a computation that may either result in an exception, or return a successfully computed value.
- Tuple immutable objects that contains a fixed number of elements (by now up to 9).
- Validation to validate the given instance.
Maven project that includes common code specifically related with Spring framework, used in several microservices. It contains different useful helper classes like:
Improvements to the functionality provided by default for managing the database:
Wrapper to manage a cache, regardless of the selected implementation:
New validators:
- EnumHasInternalStringValue: using Enums to map database values in Hibernate POJOs, allowing to verify internal properties.
- ContainsAnyProvidedString: to verify if the given string matches with one of the provided ones inside the defined array.
Common DTOs to send/receive authentication, authorization data and/or handle errors invoking endpoints:
Common functionality used by developed gRPC server and client. This one contains:
-
order.proto with the contract which includes defining the gRPC service and the method request and response types using protocol buffers specification.
-
BasicCredential which carries the Basic Authentication that will be propagated from gRPC client to the server in the request metadata with the
Authorizationkey. -
GrpcErrorHandlerUtil helper class with several methods to manage errors both on gRPC client and server side.
More information about how gRPC server and client uses it in gRPC communication.
With SQL files included in the database, just to expose the initial steps to start working with these microservices.
- changelog contains all the SQL archives required by the microservices that
use Flyway to manage their changes in database.
In the next picture, you will see a communication diagram of all microservices described above:
Due to every microservice has to decrypt the information sent by config-server, some steps are required:
In this project a symmetric encryption key has been used. The symmetric encryption key is nothing more than a shared secret that's used by the encrypter to encrypt a value and the decrypter to decrypt a value. With the Spring Cloud configuration server developed in config-server, the symmetric encryption key is a string of characters you select that is passed to the service via an operating system environment variable called ENCRYPT_KEY. For those microservices, I have used:
ENCRYPT_KEY=ENCRYPT_KEY
If you are using Oracle JDK instead of OpenJDK, you need to download and install Oracle's Unlimited Strength Java Cryptography Extension (JCE). This isn't available through Maven and must be downloaded from Oracle Corporation. Once you've downloaded the zip files containing the JCE jars, you must do the following:
-
Locate your
$JAVA_HOME/jre/lib/securitydirectory -
Back up the
local_policy.jarandUS_export_policy.jarfiles in the$JAVA_HOME/jre/lib/securitydirectory to a different location. -
Unzip the JCE zip file you downloaded from Oracle
-
Copy the
local_policy.jarandUS_export_policy.jarto your$JAVA_HOME/jre/lib/securitydirectory.
If you receive some errors related to encryption like:
IllegalStateException: Cannot decrypt: ...
Please, take a look to the previous steps in this section, maybe one of them is missing. If you still see same error messages, the best way to solve it is changing the cipher values added in the microservices configuration files included in:
Like:
spring:
datasource:
# Raw password: spring6
password: "{cipher}c8e1f3a8e0f5d7246a0dcbe620b97de51b580a1ef16f80ffafd3989920287278"
And something similar in the database table security.application_client_details,
in the columns: signature_secret and encryption_secret.
To do it:
-
Run registry-server and config-server
-
Encrypt required values using the provided endpoint for that purpose, as follows:
- Overwrite current values by the provided ones.
As you read previously, there are two different microservices you can use to manage the authentication/authorization functionality: security-oauth-service and security-custom-service.
Regarding every microservice, in this section I will explain the web services provided by everyone and how to use them, starting by security-oauth-service.
Before entering in details about this security service, it is important to know that, for every request we have to include the Basic Auth Oauth 2.0 credentials, based on the application configured in the database table: security.oauth2_registered_client.
In the next pictures I will use the predefined one: Spring6Microservices
So, the list of web services is the following one:
1. Get the authorization code using PKCE (Proof of Key Code Exchange) approach (1st request), pasting in a browser a request similar to:
http://localhost:8181/security/oauth/authorize?response_type=code&client_id=Spring6Microservices&scope=openid&redirect_uri=http://localhost:8181/security/oauth/authorized&code_challenge=jZae727K08KaOmKSgOaGzww_XVqGr_PKEgIMkjrcbJI&code_challenge_method=S256
Providing:
response_type=codeto specify to the authorization server that the client wants to use the authorization code grant type.client_id=Spring6Microservicesthe client's identifier added in security.oauth2_registered_client.scope=openidindicates which scope the client wants to be granted with this authentication attempt.redirect_uri=http://localhost:8181/security/oauth/authorizedspecifies the URI to which the authorization server will redirect after a successful authentication. This URI must be one of those previously configured for the current client.code_challenge=jZae727K08KaOmKSgOaGzww_XVqGr_PKEgIMkjrcbJIif using the authorization code enhanced with PKCE (Proof of Key Code Exchange), the hash value of the verifier that must be provided in the second request.code_challenge_method=S256hashing method has been used to create the challenge from the verifier. In this case, S256 means SHA-256.
The browser will redirect you to the login page:
In the previous image I used admin/admin however there is another option: user/user, included in the SQL file security.spring6microservice_user.
We configured a no existing page as redirect_uri for that reason we receive a 404 as response after the successful login however, the
Spring Authorization Server returns a valid authorization code we will be able to use
in the second request of PKCE (Proof of Key Code Exchange):
2. Get the authentication information using PKCE (Proof of Key Code Exchange) approach (2nd request), using above authorization code:
Providing:
client_id=Spring6Microservicesthe client's identifier added in security.oauth2_registered_client.redirect_uri=http://localhost:8181/security/oauth/authorizedspecifies the URI to which the authorization server will redirect after a successful authentication. This URI must be one of those previously configured for the current client.grant_type=authorization_codeshows which flow the client uses to request the access token.code=...the value of the authorization code the authorization server provided to the client (returned ascodequery parameter in the previous request).code_verifier=123456the verifier based on which the challenge that the client sent at authorization was created (code_challenge&code_challenge_methodparameters).
3. Once the access token has expired, return new authentication information using refresh token:
4. Get authorization information using access token:
5. Revoke the token using the access one:
So, if we try to get again its internal information, this is the new response:
Before entering in details about this security service, it is important to know that, for every request we have to include the Basic Auth credentials, based on the application configured in the database table: security.application_client_details.
In the next pictures I will use the predefined one: Spring6Microservices
This microservice provides 2 different authentication flows:
- Traditional: the request contains the user's credentials and returns the full authentication response.
- PKCE (Proof of Key Code Exchange) with 2 requests:
- The first one to send challenge data and receive the authorization code.
- The second one to send user's credentials, authorization code and verifier and returns the full authentication response.
So, the list of web services is the following one:
1. Get the authentication information using traditional approach:
In the previous image I used admin/admin however there is another option: user/user, included in the SQL file security.spring6microservice_user.
2. Get the authorization code using PKCE (Proof of Key Code Exchange) approach (1st request):
3. Get the authentication information using PKCE (Proof of Key Code Exchange) approach (2nd request):
4. Once the access token has expired, return new authentication information using refresh token:
5. Get authorization information using access token:
6. Logs out a user related with an application:
So, if we try to get again its internal information, this is the new response:
The user must complete any of the provided login flows to resubmit new requests.
The following microservices have a well-documented Rest API:
Swagger has been used in all cases, however for a better an easier integration with Spring Framework, the library used is:
- Springdoc-OpenApi both in every documented microservice and the gateway-server.
To facilitate access to this documentation, we can use the gateway-server URL. On that way, using the upper selector: Select a definition, we will be able to choose between all existing microservices.
Using dev profile, the url to access them is http://localhost:5555/swagger-ui/index.html
Configured to use the application Bruno, several collections were created to use the provided endpoints. You can them here.
Besides the REST API developed in:
In this project has been added a gRPC communication channel between:
- gRPC server: in order-service
- gRPC client: in invoice-service
Both use the same approach to run server and client instances:
- The instance definition:
- The Spring functionality used to run it:
The internal communication between a microservice and its related security server, that is:
Uses Basic Authentication to include the required credentials:
- order-service in the class CustomAuthoritiesOpaqueTokenIntrospector
- invoice-service in the class CustomAuthenticationManager
In the current gRPC development I have followed the same approach:
-
In the gRPC client creating a new BasicCredential instance and adding it in the
Authorizationheader sent to the server, using the methodbuildCallCredentialsof the class GrpcClient. -
In the gRPC server, the interceptor AuthenticationInterceptor manages required verifications.
This project uses Spring tracing through Micrometer tracing for distributed tracing, to simulate the same behaviour two interceptors have been defined:
- At gRPC server with RequestIdInterceptor
- At gRPC client with RequestIdInterceptor
Everytime invoice-service returns an invoice details searched by its identifier or code, will send a request to order-service using a gRPC communication channel to get its order and order lines data.
The communication diagram including also the invocation of security-custom-service is the following:
So, as I explained you in security-custom-service endpoints, once you have obtained the required JWT access token, you can use it to invoke the web service that uses the developed gRPC channel:
Besides the REST API and the gRPC communication, the project works with JMS to send data from
order-service to invoice-service. Using Kafka, everytime a new order is created in order-service through
its REST API, a new message is sent to invoice-service to insert a new invoice based on the order's information.
The JMS communication channel uses Basic access authentication with a similar approach to gRPC. In this case,
- order-service (Producer) adds it in JmsService (in the method
toEventDto). - invoice-service (Consumer) verifies it in JmsService (in the method
verifyBasicAuthRequest).
As I mentioned, everytime a new order is created in order-service through its REST API, a new message is sent to invoice-service to insert a new invoice based on the order's information.
The communication diagram including also the invocation of security-oauth-service is the following:
So, as I explained you in security-oauth-service endpoints, once you have obtained the required JWT access token, you can use it to invoke the web service that uses the developed JMS communication channel:
If there was no error, you should see 3 new entities in database:
Native Image is a technology to compile Java code ahead-of-time to a binary – a native executable. A native executable includes only the code required at run time, that is the application classes, standard-library classes, the language runtime, and statically-linked native code from the JDK.
An executable file produced by Native Image has several important advantages, in that it:
- Uses a fraction of the resources required by the Java Virtual Machine, so is cheaper to run.
- Starts in milliseconds
- Delivers peak performance immediately, with no warmup.
- Can be packaged into a lightweight container image for fast and efficient deployment.
Download the required GraalVM JDK from here, in this project I use Java 21. Although there are several options to manage different JDKs such as SDKMAN, I have followed the instructions included in the webpage to install and configure GraalVM JDK in Ubuntu.
In summary, the steps are:
1. Unpack the JDK in /usr/lib/jvm/java-21-graalvm-jdk-amd64 and navigate to /usr/lib/jvm/ to work on the next points.
2. Create a symbolic link that points to the GraalVM JDK 21 directory:
ln -s java-21-graalvm-jdk-amd64 /usr/lib/jvm/java-1.21.0-graalvm-jdk-amd64
3. Prepare a descriptor file providing the information about binaries to the update-alternative utilities, creating the new file
.java-1.21.0-openjdk-amd64.jinfo with:
name=java-21-graalvm-amd64
alias=java-1.21.0-graalvm-amd64
priority=2102
section=main
hl java /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/java
hl jpackage /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jpackage
hl keytool /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/keytool
hl rmiregistry /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/rmiregistry
hl jexec /usr/lib/jvm/java-21-graalvm-jdk-amd64/lib/jexec
jdkhl jar /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jar
jdkhl jarsigner /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jarsigner
jdkhl javac /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/javac
jdkhl javadoc /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/javadoc
jdkhl javap /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/javap
jdkhl jcmd /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jcmd
jdkhl jdb /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jdb
jdkhl jdeprscan /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jdeprscan
jdkhl jdeps /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jdeps
jdkhl jfr /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jfr
jdkhl jimage /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jimage
jdkhl jinfo /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jinfo
jdkhl jlink /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jlink
jdkhl jmap /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jmap
jdkhl jmod /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jmod
jdkhl jps /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jps
jdkhl jrunscript /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jrunscript
jdkhl jshell /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jshell
jdkhl jstack /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jstack
jdkhl jstat /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jstat
jdkhl jstatd /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jstatd
jdkhl jwebserver /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jwebserver
jdkhl serialver /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/serialver
jdkhl jhsdb /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jhsdb
jdk jconsole /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/jconsole
jdk native-image /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/native-image
jdk native-image-configure /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/native-image-configure
jdk native-image-inspect /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/native-image-inspect
4. Configure update-alternative to use executables from the GraalVM JDK, creating the new file
java-21-graalvm-jdk-amd64_alternatives-install with:
for path in /usr/lib/jvm/java-21-graalvm-jdk-amd64/bin/*; do
name=$(basename $path)
update-alternatives --install /usr/bin/$name $name $path 2102 \
--slave /usr/share/man/man1/$name.1.gz $name.1.gz /usr/lib/jvm/java-21-graalvm-jdk-amd64/man/man1/$name.1
done
update-alternatives --install /usr/bin/jexec jexec /usr/lib/jvm/java-21-graalvm-jdk-amd64/lib/jexec 2102
5. Invoke the new file:
./java-21-graalvm-jdk-amd64_alternatives-install
6. Switch to the brand new GraalVM JDK using the update-java-alternatives:
update-java-alternatives -s java-1.21.0-graalvm-jdk-amd64
If everything went well, then we should watch something like:
java --version
java 21.0.6 2025-01-21 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 21.0.6+8.1 (build 21.0.6+8-LTS-jvmci-23.1-b55)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21.0.6+8.1 (build 21.0.6+8-LTS-jvmci-23.1-b55, mixed mode, sharing)
Once we have configured the GraalVM JDK, the required changes/considerations in security-custom-service are:
1. Create the new application-native.yml
file to include the specific configuration for native images.
2. Add the configuration files based on the project's functionality.
To know how to generate all the configuration archives in this microservice, package the project with maven using native profile and invoke:
java -Dspring.aot.enabled=true -agentlib:native-image-agent=config-output-dir=./native-config -jar target/security-custom-service-1.0.0.jar
You can use all the new files located in native-config folder, to include in the project only the required ones.
3. Update pom.xml to add, at least, the native profile. Not all the dependencies are available
to work with native images, you can check the list here.
4. Create a new maven configuration to compile the project and generate the native image as executable file:
5. Invoke the generated executable archive:
./target/security-custom-service --spring.profiles.active=native
If everything went well, then the application will run smoothly and the endpoints will respond to the request normally. Comparing both options: local and native you will be able to notice an important improvement in the performance:
- local: more than 6 seconds.
- native: less than 3 seconds.
In addition to launching all the microservices included in this project as normal Java applications locally, all of them have been dockerized. Every one
includes a Dockerfile inside with the required configuration and instructions to generate both Docker image and container. On the other hand, new application files with docker
profile have been added to Spring6Microservices_ConfigServerData.
There are 2 main types of Dockerfile based on the option to invoke maven install inside the Docker container, this is because some projects contain internal dependencies that
have not been uploaded to a public repository like:
Projects with maven install in their DockerFile and do not need to create the jar file previously:
Projects that must create the jar file before building the Docker image:
Once you have created all the Docker images on your local, you should see something similar to:
To manage the Docker containers in an easier way, a Docker compose file: compose.yml has been added. It includes the required commands to up and down the project's containers.
The file kafka-compose.yml adds only the required containers to work with the microservices in local, specially:
allowing you to debug and work locally without problems. More information in the section JMS communication.
In this project, the PostgreSQL database has not been dockerized, feel free to do it if you prefer such option instead of using the local one. In this section, I will describe the required steps to allow the connections from Docker to the PostgreSQL database installed in a local computer, in my case, PostgreSQL 16 over Ubuntu (other database versions and/or OS should need similar ones).
- Go to the PostgreSQL's folder with configuration files (in my case
/etc/postgresql/16/main) - Edit
postgresql.confto listen connections outsidelocalhost:
listen_addresses = '*'
- Edit
pg_hba.confto allow connections from Docker containers
# # IPv4 local connections:
host all all 172.18.0.0/16 md5 # Docker
host all all 172.21.0.0/16 md5 # Docker compose
- Restart PostgreSQL service (in my case
service postgresql restart).




































