Overview
Spring Boot provides the parent POM for easier creation of Spring Boot applications. However, not everyone likes inheriting from the spring-boot-starter-parent
POM.
In one of the projects I have worked earlier, we have used a custom Spring Boot Starter with all the Security Configurations and generic components required for creating microservices.
By using this starter, we were able to focus only on the buisness use case of the service rather than spending time on configuring the same thing again and again for new service implementation
Like this, You may have your own corporate standard parent that you need to use, or you may just prefer to explicitly declare all your Maven configuration.
In this tutorial, we’ll demonstrate how to build a custom Spring Boot Starter with multiple authentication profiles and default application.properties
.
So far, we have implemented the following things in our previous articles
- Spring Boot REST API
- Swagger 2 integration
- Basic Authentication and authorization
- JWT Authentication and authorization
- LDAP Authentication and authorization
- Disable Spring Security for
noauth
profile
In order to implement a new micorservice with all the above funtionalities, we don’t need to copy the code that we have developed so far here. If we do so, it will lead to redundant code and its very difficult to maintain as well.
We are gonna create a starter module and move all the Security configurations and application.properties
from the product REST API to the starter module. So that, new microservices can inherit all the common configurations/functionalities and application properties from the starter module.
To accomplish this, we are gonna create:
- microservice-spring-boot-starter module which uses the Spring Boot Starter Parent and defines the required dependencies in the
pom.xml
. Apart from that, it also contains all the security configurations and default application properties. - microservice-starter-parent module which has the parent POM. The packaging type of parent project should always be POM. Then only we will be able to use it as a parent in the actual applications. This parent module defines the starter module as a dependency in the
dependencyManagement
section inpom.xml
. - microservice which makes use of the starter module via the parent POM.
Naming Convention
Custom starter module should not start with Spring Boot. Use name-spring-boot-starter as a guideline. In our case, we named our starter as microservice-spring-boot-starter.
Lets Get Started
We are gonna create a Spring Boot multi module project as shown in the diagram below
Create Starter Module
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.javachinna</groupId>
<artifactId>microservice-spring-boot-starter</artifactId>
<version>1.0</version>
<name>microservice-spring-boot-starter</name>
<description>Microservice Spring Boot Starter</description>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
</dependency>
</dependencies>
</project>
We have excluded spring-beans
and spring-tx
dependencies from the spring-ldap-core
dependency to avoid version conflicts.
Note: If you don’t wanna inherit the spring-boot-starter-parent
at all, then you can still use the dependency management without inheriting it by removing the parent configuration and adding the spring-boot-dependencies
in the dependencyManagement
section of the pom.xml
as shown below
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Project Structure
All the files shown below are pulled from the product REST API project here. It has all the Security configurations, generic components. Any other generic funtionality like validation can be added in the starter and be used across all the microservices which makes use of this starter.
Install Starter with Maven
Run mvn clean install
command in the starter project to build the jar and install it in your local maven repository. So that, when you build the parent and child module, it will be pulled from the local repository.
Create Parent Module
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javachinna</groupId>
<artifactId>microservice-starter-parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>microservice-starter-parent</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.javachinna</groupId>
<artifactId>microservice-spring-boot-starter</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Install Parent with Maven
Run mvn clean install
command in the parent project to install it in your local maven repository. So that, when you build the child module, it will be pulled from the local repository.
Create Microservice
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.javachinna</groupId>
<artifactId>microservice-starter-parent</artifactId>
<version>1.0</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-boot-microservice</artifactId>
<name>spring-boot-microservice</name>
<description>Demo project for Spring Boot REST API CRUD Operations with Swagger Documentation</description>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.javachinna</groupId>
<artifactId>microservice-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.6.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
Since we are using a custom parent, we will not get the plugin mangement feature provided by spring-boot-starter-parent
. That is why we have added the spring-boot-maven-plugin
with version number.
We have added dependencies that are common to all the microservices in the starter module itself. Apart from that, if any service specific dependency is required, then those should be added in the microservice pom itself.
Project Structure
All the files shown below are pulled from the product REST API project here. It has only the Product specific classes leaving all the generic configurations in starter module
Inheriting application.properties
By default properties will be loaded from application.properties
and/or application.yml
files in the following locations:
- file:./config/
- file:./
- classpath:config/
- classpath:
The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).
Hence, we have moved the application.properties
to the resources folder in the starter module and overridden few default properties in our microservice by creating a application.properties
in the src\main\resources\config\
folder.
application.properties
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
logging.level.root=debug
Run with a Profile
You can run the application with any of the 4 available profiles. For example, run mvn spring-boot:run -Dspring-boot.run.profiles=basicauth
and hit the url http://localhost:8080/swagger-ui.html in the browser. You should be able to execute the services with basic authentication. Similarly, if you run the application with other profiles, then the respective security configuration will be enabled.
Source Code
As always, you can get the source code from the Github below
https://github.com/JavaChinna/microservice-spring-boot-starter
Conclusion
That’s all folks! In this article, you’ve learned how to build a custom Spring Boot Starter for developing microservices with multiple authentication profiles using the starter.
I hope you enjoyed this article. Thank you for reading.