Custom Endpoints in Spring boot Actuator
Custom Endpoints in Spring Boot Actuator extends the default functionality provided by the Actuator. It involves defining a custom endpoint class annotated with @Endpoint, which contains methods annotated with @ReadOperation, @WriteOperation, and @DeleteOperation to handle GET, POST, and DELETE requests. Spring Boot Actuator allows you to expose these custom endpoints through HTTP by configuring the necessary security settings. Using the SecurityFilterChain, we can secure these endpoints to ensure that only authorized users can access them.
Key Annotations:
- @Endpoint: It marks a class as the endpoint to be exposed by the Spring Boot Actuator. This annotation can be used on the class level to define the Custom Actuator endpoint.
- @ReadOperation: It indicates that the annotated method should handle the GET requests for the custom endpoint. This annotation can be used on methods within the @Endpoint class to define the read (GET) operations.
- @WriteOperation: It indicates that the annotated method should handle the POST requests for the custom endpoint. This annotation can be used on methods within the @Endpoint class to define the write (POST) operations.
- @DeleteOperation: It indicates that the annotated method should handle the DELETE requests for the custom endpoint. This annotation can be used on methods within the @Endpoint class to define the delete(DELETE) operations.
Implementation of Custom Endpoints in Spring Boot Actuator
Below are the steps to implement Custom Endpoints in Spring boot Actuator.
Step 1: Create the Spring Project
Create a new Spring Boot project using Spring Initializr and add below dependencies,
- Spring Web
- Spring Security
- Spring Boot Actuator
- Lombok
- Spring DevTools
After this step, the project structure will be like below.
Step 2: Configure the Application properties
Open the application.properties file and add the properties.
spring.application.name=custom-endpoints-actuators
management.endpoints.web.exposure.include=*
management.endpoint.customEndpoint.enabled=true
# Enable security for actuator endpoints
management.endpoint.customEndpoint.roles=ACTUATOR
Step 3: Configure Web Security
We will create the security configuration class to secure the custom endpoints and other actuator endpoints of the application.
Go to src > main > java > org.example.customendpointsacuators > SecurityConfig and put the below code.
package org.example.customendpointsactuators;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/actuator/**").hasRole("ACTUATOR")
.anyRequest().authenticated()
)
.httpBasic(withDefaults())
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password("{noop}password")
.roles("ACTUATOR")
.build();
return new InMemoryUserDetailsManager(user);
}
}
Step 4: Create Custom Endpoints
We will create the custom endpoints class with the methods for the different operations of the application.
Go to src > main > java > org.example.customendpointsacuators > CustomEndpoints and put the below code.
package org.example.customendpointsactuators;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.stereotype.Component;
@Component
@Endpoint(id = "customEndpoint")
public class CustomEndpoint {
@ReadOperation
public String customEndpoint() {
return "Hello from custom endpoint!";
}
@WriteOperation
public String writeOperation(String name) {
return "Hello, " + name;
}
@DeleteOperation
public String deleteOperation() {
return "Delete operation performed";
}
}
Step 5: Main Class
No changes are required in the main class.
package org.example.customendpointsactuators;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomEndpointsActuatorsApplication {
public static void main(String[] args) {
SpringApplication.run(CustomEndpointsActuatorsApplication.class, args);
}
}
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>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>custom-endpoints-actuators</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>custom-endpoints-actuators</name>
<description>custom-endpoints-actuators</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 6: Run the application
Now, we will run the application as a spring then it will be start port at 8080.
Step 7: Testing the Custom Endpoints
Authorization: Set the Basic Auth and provide the username and password.
Testing the Read Operation (GET):
GET http://localhost:8080/actuator/customEndpoint
Output:
Testing the Write Operation (POST):
POST http://localhost:8080/actuator/customEndpoint
Output:
Testing the Delete Operation (DELETE):
DELETE http://localhost:8080/actuator/customEndpoint
Contact Us