How to add Spring Boot Actuator 2.X Support to Spring MVC / REST Application without Spring Boot

In the previous article, we have secured the REST API with Spring Security and JSON Web Token (JWT) without using Spring Boot. Now we are gonna add Spring Boot actuator 2.X support to a non Spring Boot application. So we are gonna use the same Spring REST application that we have created earlier and add actuator support to it.

Spring Boot Actuator 2.x defines its model, pluggable and extensible without relying on MVC for this. So we just need to add the spring-boot-starter-actuator dependency only.

Project Dependencies

pom.xml

We are gonna add the Spring Boot Starter Actuator dependency to the existing pom.xml file.

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
			<version>2.2.4.RELEASE</version>
		</dependency>

Spring Configuration

WebConfig.java

We are gonna add @EnableAutoConfiguration and @PropertySource annotations to our existing configuration class. You can put these annotations to any of the Spring configuration classes annotated with @Configuration

@EnableAutoConfiguration is used to enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually applied based on your classpath and what beans you have defined.

I’ve excluded the DataSourceAutoConfiguration.class since we have already configured the database using the JpaConfig class and persistence.xml

@PropertySource annotation is used to add the property source (application.properties) to the Spring’s Environment

package com.javachinna.config;

import java.util.List;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableWebMvc
@Configuration
@ComponentScan("com.javachinna")
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@PropertySource(value = { "classpath:application.properties" })
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.add(new MappingJackson2HttpMessageConverter());
	}
}

Actuator Endpoints Security

Since we are using JWT authentication, actuator endpoints are also secured. So we need to pass the JWT token in the request. In case if you don’t want to secure the /actuator endpoints then you can configure the same in WebSecurityConfig.configure(HttpSecurity httpSecurity) method as shown below

http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
            requests.anyRequest().permitAll());

Or if you want to enable role-based authentication, then you need to define user roles and then you can configure the authentication as shown below

http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
                requests.anyRequest().hasRole("ENDPOINT_ADMIN"));

Application Properties

application.properties

By default, all endpoints except for shutdown are enabled. To configure the enablement of an endpoint, use its management.endpoint.<id>.enabled property. The following example enables the shutdown endpoint:

management.endpoint.shutdown.enabled=true

By default, only the info, health endpoints are exposed. To expose all the available endpoints, add the management.endpoints.web.exposure.include property as shown below

management.endpoints.web.exposure.include=*

Build and Deploy Application

Run mvn clean install command to clean and build the war file and deploy the generated war file in a server like tomcat.

Test Application

Request

GET /SpringRestJwt/actuator HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYXZhY2hpbm5hIiwiZXhwIjoxNTgxNTAxMDUwLCJpYXQiOjE1ODE0ODMwNTB9.hqCZCMIHtuKng8PCQkNeuqQQCMiP59VQ3_9YGgjCgRfBPk_LmzIZQEBcPu1kTTobBS1w_6sSS9c4jHjE1frXaw
Cache-Control: no-cache
Postman-Token: 52bf6a85-d034-9907-dc51-a3d80ddd1065

Response

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/SpringRestJwt/actuator",
            "templated": false
        },
        "beans": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/beans",
            "templated": false
        },
        "caches-cache": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/caches/{cache}",
            "templated": true
        },
        "caches": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/caches",
            "templated": false
        },
        "health": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/health",
            "templated": false
        },
        "health-path": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/health/{*path}",
            "templated": true
        },
        "info": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/info",
            "templated": false
        },
        "conditions": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/conditions",
            "templated": false
        },
        "shutdown": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/shutdown",
            "templated": false
        },
        "configprops": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/configprops",
            "templated": false
        },
        "env": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/env",
            "templated": false
        },
        "env-toMatch": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/env/{toMatch}",
            "templated": true
        },
        "heapdump": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/heapdump",
            "templated": false
        },
        "threaddump": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/threaddump",
            "templated": false
        },
        "metrics-requiredMetricName": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/metrics/{requiredMetricName}",
            "templated": true
        },
        "metrics": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/metrics",
            "templated": false
        },
        "scheduledtasks": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/scheduledtasks",
            "templated": false
        },
        "mappings": {
            "href": "http://localhost:8080/SpringRestJwt/actuator/mappings",
            "templated": false
        }
    }
}

Health Check

Request

GET /SpringRestJwt/actuator/health HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYXZhY2hpbm5hIiwiZXhwIjoxNTgxNTAxMDUwLCJpYXQiOjE1ODE0ODMwNTB9.hqCZCMIHtuKng8PCQkNeuqQQCMiP59VQ3_9YGgjCgRfBPk_LmzIZQEBcPu1kTTobBS1w_6sSS9c4jHjE1frXaw
Cache-Control: no-cache
Postman-Token: ec3cfac7-c30b-24e7-5cca-e6aeaa607f1b

Response

{
“status”: “UP”
}

If we want to get the complete details of the health of the application, we can add the following property in application.properties.

management.endpoint.health.show-details=always

The resulting response will be as shown below. If your application has a database like MongoDB, Redis, or MySQL, for instance, the health endpoint will show the status of those too. However, it will not be shown in our case since we have added the DataSourceAutoConfiguration.class to the exclusion list of @EnableAutoConfiguration

{
    "status": "UP",
    "components": {
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 356515835904,
                "free": 328041304064,
                "threshold": 10485760
            }
        },
        "ping": {
            "status": "UP"
        }
    }
}

Application Metrics

You can get the list of metrics available using /actuator/metrics endpoint.

Request

GET /SpringRestJwt/actuator/metrics HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYXZhY2hpbm5hIiwiZXhwIjoxNTgxNTAxMDUwLCJpYXQiOjE1ODE0ODMwNTB9.hqCZCMIHtuKng8PCQkNeuqQQCMiP59VQ3_9YGgjCgRfBPk_LmzIZQEBcPu1kTTobBS1w_6sSS9c4jHjE1frXaw
Cache-Control: no-cache
Postman-Token: 634c1dab-866c-54dc-af07-e61df20288e2

Response

{
    "names": [
        "jvm.threads.states",
        "jvm.memory.used",
        "jvm.gc.memory.promoted",
        "jvm.memory.max",
        "jvm.gc.max.data.size",
        "jvm.memory.committed",
        "system.cpu.count",
        "logback.events",
        "jvm.buffer.memory.used",
        "jvm.threads.daemon",
        "system.cpu.usage",
        "jvm.gc.memory.allocated",
        "jvm.threads.live",
        "jvm.threads.peak",
        "process.uptime",
        "process.cpu.usage",
        "jvm.classes.loaded",
        "jvm.classes.unloaded",
        "jvm.gc.live.data.size",
        "jvm.gc.pause",
        "jvm.buffer.count",
        "jvm.buffer.total.capacity",
        "process.start.time"
    ]
}

JVM Memory Used Metrics Request

GET /SpringRestJwt/actuator/metrics/jvm.memory.used HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYXZhY2hpbm5hIiwiZXhwIjoxNTgxNTAxMDUwLCJpYXQiOjE1ODE0ODMwNTB9.hqCZCMIHtuKng8PCQkNeuqQQCMiP59VQ3_9YGgjCgRfBPk_LmzIZQEBcPu1kTTobBS1w_6sSS9c4jHjE1frXaw
Cache-Control: no-cache
Postman-Token: 24dbef68-7daa-f520-a3f5-2e6efff90ff5

JVM Memory Used Metrics Response

{
    "name": "jvm.memory.used",
    "description": "The amount of used memory",
    "baseUnit": "bytes",
    "measurements": [
        {
            "statistic": "VALUE",
            "value": 1216768800
        }
    ],
    "availableTags": [
        {
            "tag": "area",
            "values": [
                "heap",
                "nonheap"
            ]
        },
        {
            "tag": "id",
            "values": [
                "CodeHeap 'profiled nmethods'",
                "G1 Old Gen",
                "CodeHeap 'non-profiled nmethods'",
                "G1 Survivor Space",
                "Compressed Class Space",
                "Metaspace",
                "G1 Eden Space",
                "CodeHeap 'non-nmethods'"
            ]
        }
    ]
}

Source code

https://github.com/JavaChinna/spring-rest-jwt-sample

Conclusion

That’s all folks. In this article, we have added Spring Boot Actuator support to the Spring REST API without using Spring Boot. Thank you for reading !!!

This Post Has 2 Comments

  1. Randy

    Greetings,

    I’m not the best speller but I see the word “Continous” is spelled incorrectly on your website. In the past I’ve used a service like SpellAlerts.com or SiteChecker.com to help keep mistakes off of my websites.

    -Randy

    1. Chinna

      Thanks for pointing that out and the tip. I’ve corrected that.

Leave a Reply