CXF and spring boot actuator, actuator end points not available

Viewed 1700

I have a project setup with spring boot 1.4.2 and CXF JAXRS. I want to add spring boot actuator to the project. This is the configuration which I added to the project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
</dependency>

I create a WAR file after this and then deploy it in external tomcat server. But when I access the health URL localhost:8080/management/health it is giving 404 HTTP code. The server starts properly and I can see the logs with following details:

Health configuration log

[localhost-startStop-1] INFO org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping - Mapped "{[/management/health || /management/health.json],produces=[application/json]}" onto public java.lang.Object

Servlet(s) configuration log

[localhost-startStop-1] INFO org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean - Mapping filter: 'springSecurityFilterChain' to: [/*]

[localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean - Mapping filter: 'webRequestLoggingFilter' to: [/*]

[localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean - Mapping filter: 'applicationContextIdFilter' to: [/*]

[localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean - Mapping servlet: 'dispatcherServletRegistration' to []

[localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean - Mapping servlet: 'dispatcherServlet' to [/]

[localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean - Mapping servlet: 'CXFServlet' to [/services/*]

2 Answers

In my case i have Spring 1.5.X , i cannot use two different base paths for CXF and Spring Actuator. I need to keep "/" for root application path and add a RestEnpoint for returning actuator Health result.

So i use another approach when CXF returns a string result from Health Info generated on Service layer using @Autowired + ObjectMapper.

Note: you should enable the annotation context support for apply this solutions.

These following workaround works for me :

keep your CXF Servlet on "/"

In my case i'm using Camel + CXF, however all you need to do is creating the following component for build the Health object:

@Component
public class InfoHealthEndpoint extends HealthEndpoint {

    @Autowired
    private InfoEndpoint infoEndpoint;

    public InfoHealthEndpoint(HealthAggregator healthAggregator, Map<String, HealthIndicator> healthIndicators) {
        super(healthAggregator, healthIndicators);
    }

    @Override
    public Health invoke() {
        Health health = super.invoke();
        return new Health.Builder(health.getStatus(), health.getDetails())
                .withDetail("info", infoEndpoint.invoke())
                .build();
    }

}

And create a service that returns the String result for CXF response controller.

@Service public class HealthService {

@Autowired
private InfoHealthEndpoint infoHealthEndpoint;

@Autowired
private ObjectMapper mapper;

private static final String HEALTH_UP = "UP";

public void health(Exchange exchange) throws JsonProcessingException {

    Health health = infoHealthEndpoint.invoke();
    String healthReponse = mapper.writeValueAsString(infoHealthEndpoint.invoke());

    if(!HEALTH_UP.equals(health.getStatus().getCode())){
        Response response = Response.status(503).entity(healthReponse).build();
        exchange.getOut().setBody(response);
        exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE);
    }else{
        exchange.getIn().setBody(healthReponse);
    }

}

}

NOTE: in my case, im using Apache Camel (Exchange) for set response on route, however this solution could applyable for another situation by using a simple String return.

Credits for @Danny on this answer: Combine Spring Boot Actuator /health and /info into one

Related