Spring Boot's Actuator library with production information endpoints is really useful for any server application. But the problem is I could not find a way to integrate into a traditional Spring Application (which is not a Spring BOOT application).
There must be some way to use the endpoints of actuator but I could not wire them up.
I have a JavaConfig class like below
@Configuration
@ComponentScan(basePackages = { "com.company.helper", "org.springframework.boot" })
@EnableWebMvc
@Import({ DbConfig.class })
public class AppConfig extends WebMvcConfigurerAdapter {
}
But this configuration throws an error during deployment.
Can this wiring be done without the Spring Boot application?
First let's clarify that you cannot use Spring Boot Actuator without using Spring Boot. I was wrong about not being able to it without Spring Boot. See @stefaan-neyts answer for an example of how to do it.
In order to access the actuator endpoints using HTTP, we need to both enable and expose them. By default, all endpoints but /shutdown are enabled.
To enable Spring Boot actuator endpoints to your Spring Boot application, we need to add the Spring Boot Starter actuator dependency in our build configuration file. Maven users can add the below dependency in your pom. xml file. Gradle users can add the below dependency in your build.
The application can also be called as Spring Boot Standalone application. To develop a non web application, your Application needs to implement CommandLineRunner interface along with its run method. This run method acts like a main of your application.
I have added information on how to add spring boot actuator in a non boot application in this blog post
http://givenwhenthen.blogspot.com/2015/09/adding-spring-boot-actuator-to-non.html
In the application's build.gradle, I added the following dependency
compile('org.springframework.boot:spring-boot-actuator:1.2.5.RELEASE'){
exclude group: 'org.springframework.boot', module:'spring-boot-starter-logging'}
In the application's Spring Config class, I added the following things:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.BeansEndpoint;
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
@Configuration
@Import(EndpointAutoConfiguration.class)
public class MyAppSpringConfig {
@Bean
@Autowired
//Define the HandlerMapping similar to RequestHandlerMapping to expose the endpoint
public EndpointHandlerMapping endpointHandlerMapping(
Collection<? extends MvcEndpoint> endpoints
){
return new EndpointHandlerMapping(endpoints);
}
@Bean
@Autowired
//define the HealthPoint endpoint
public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate){
return new HealthMvcEndpoint(delegate, false);
}
@Bean
@Autowired
//define the Info endpoint
public EndpointMvcAdapter infoMvcEndPoint(InfoEndpoint delegate){
return new EndpointMvcAdapter(delegate);
}
@Bean
@Autowired
//define the beans endpoint
public EndpointMvcAdapter beansEndPoint(BeansEndpoint delegate){
return new EndpointMvcAdapter(delegate);
}
@Bean
@Autowired
//define the mappings endpoint
public EndpointMvcAdapter requestMappingEndPoint(
RequestMappingEndpoint delegate
){
return new EndpointMvcAdapter(delegate);
}
}
If you want to get rid of one additional dependency then please refer to the blogpost.
UPDATE
Also you need to make sure you have a bean defined for RequestMappingHandlerAdapter, if you do not have it the ServletDispatcher will not be able to fetch the adapter for the handler of your HealthMvcEndpoint.
if you dont have it just add it to your bean configuration file
xml configurations:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter"/>
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
<property name="prettyPrint" value="true" />
</bean>
The project I'm working on uses Spring, but neither Spring-boot nor Spring-MVC. The following solution may not be as automagic as the actuator with boot, but it exposes the endpoints in a pretty succinct way.
Basically, all actuator endpoints are just beans, so you can create a new component and autowire in the endpoints however you see fit.
The only additional dependencies in my pom are spring-boot-actuator and spring-webmvc:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
Then all you need to do is create a single component class (maybe register it if you need to). Make sure to annotate with @EnableAutoConfiguration:
@Component
@EnableAutoConfiguration
@Path("/actuator/")
public class ActuatorResource {
private ObjectMapper mapper = new ObjectMapper();
@Autowired
private DumpEndpoint dumpEndpoint;
@GET
@Produces("application/json")
@Path("/dump")
@Transactional(readOnly = true)
public String getDump() throws JsonProcessingException {
return mapper.writeValueAsString(dumpEndpoint.invoke());
}
@Autowired
private EnvironmentEndpoint envEndpoint;
@GET
@Produces("application/json")
@Path("/environment")
@Transactional(readOnly = true)
public String getEnvironment() throws JsonProcessingException {
return mapper.writeValueAsString(envEndpoint.invoke());
}
}
In our project we used a little hack, that worked for us. To enable actuator we used dependencies from spring-boot in POM.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<version>1.2.3.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.2.Final</version>
</dependency>
and just used additional config class as follows:
@EnableConfigurationProperties
@Configuration
@EnableAutoConfiguration
@Import(EndpointAutoConfiguration.class)
public class SpringBootActuatorConfig {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With