I've noticed the actuator endpoints throwing a 404 error. The following are the Spring Framework versions used:
Spring Boot Starter 3.2.5 Spring Boot Jersey Starter 3.2.5 Tomcat embedded container
The actuator endpoints worked with Spring boot 2.7.* and Jersey was configured as "Filter".
Additional info: (In the working code)
ServletContainer.class throws Status.NOT_FOUND The call reaches the Tomcat Embedded core (ApplicationFilterChain, WSFilter) The call hits the Spring boot actuator
In the not-working code, the flow never reaches the spring boot actuator.
Please share your thoughts.
Comment From: philwebb
Please share a sample project that replicates the issue.
Comment From: RameshVE123
Attached is the demo code.
Comment From: nosan
Thank you for your demo, @RameshVE123
I checked it, and indeed, it does not work. I also downgraded the Spring Boot version to 2.7.18, and it does not work
either.
Three things should be changed in your demo code to make it work:
- In your demo, you have added dependency on
org.springframework.boot:spring-boot-starter-webthat back-offsJerseyWebEndpointManagementContextConfigurationasDispatcherServletwas registered.
JerseyWebEndpointManagementContextConfiguration:
Did not match:
- @ConditionalOnMissingBean (types: org.springframework.web.servlet.DispatcherServlet; SearchStrategy: all) found beans of type 'org.springframework.web.servlet.DispatcherServlet' dispatcherServlet (OnBeanCondition)
Matched:
- @ConditionalOnClass found required class 'org.glassfish.jersey.server.ResourceConfig' (OnClassCondition)
- found 'session' scope (OnWebApplicationCondition)
You need to either comment out this dependency or remove it entirely from your pom.xml
- A property
server.servlet.context.path=/msapiis incorrect and should be changed toserver.servlet.context-path=/msapi
- Since, you set
spring.jersey.type=filter, the JerseyServletContainerwill be registered asFilterand filters are invoked on either the request to a resource (a servlet or static content), or on the response from a resource, or both, and in your application, there are no such resources. You can modify your configuration with the following changes:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
ServletRegistrationBean<NoOpServlet> noOpServlet() {
return new ServletRegistrationBean<>(new NoOpServlet(), "/*");
}
public static class NoOpServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
Once you have made all these changes, the actuator endpoint will be available on:
```http request GET http://localhost:8080/msapi/actuator/health
Could you please provide more information about your application, which uses Jersey as a `Filter`, as the provided demo does not show that it worked in `2.7.x`.
**Comment From: nosan**
> The actuator endpoints worked with Spring boot 2.7.* and Jersey was configured as "Filter".
> Additional info: (In the working code)
> ServletContainer.class throws Status.NOT_FOUND
> The call reaches the Tomcat Embedded core (ApplicationFilterChain, WSFilter)
> The call hits the Spring boot actuator
> In the not-working code, the flow never reaches the spring boot actuator.
The actuator endpoints are not accessible because the `ServletContainer` (Jersey Filter) is not configured with the actuator resources. This occurs because a `DispatcherServlet` bean was registered, which back-off `JerseyWebEndpointManagementContextConfiguration` and the latter one is responsible for configuring `ServletContainer`.
You can adjust `JerseyConfiguration` with the following changes:
```java
@Component
@ApplicationPath("/jersey") //change path from '/' to something else
public class JerseyConfiguration extends ResourceConfig {
// Demo code, no resources are registered
}
The actuator endpoint will also be accessible (handled by the MVC infrastructure) since the Jersey filter will use the /jersey/ URL pattern and will not interfere with /actuator/health but in that case, you need to have org.springframework.boot:spring-boot-starter-web dependency in your pom.xml*
Comment From: philwebb
Thanks for the detailed analysis @nosan. It doesn't look like this is a bug so I'm going to close the issue.
Comment From: RameshVE123
Thank you for your suggestion.
Comment From: rdlf0
- Since, you set
spring.jersey.type=filter, the JerseyServletContainerwill be registered asFilterand filters are invoked on either the request to a resource (a servlet or static content), or on the response from a resource, or both, and in your application, there are no such resources. You can modify your configuration with the following changes:```java @SpringBootApplication public class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }
@Bean ServletRegistrationBean
noOpServlet() { return new ServletRegistrationBean<>(new NoOpServlet(), "/*"); } public static class NoOpServlet extends GenericServlet {
@Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) { throw new UnsupportedOperationException("Not supported yet."); }}
} ```
Once you have made all these changes, the actuator endpoint will be available on:
httpspec GET http://localhost:8080/msapi/actuator/health
A simpler way to achieve this is to just set server.servlet.register-default-servlet=true. This way you won't need to register a NoOpServlet.
Comment From: RameshVE123
Thank you for the response.
I have a follow up question on the @ApplicationPath annotation,
Does it support regex pattern like the below to register multiple url mappings or any alternate ways to do this.
@ApplicationPath(“/jersey/{ver: v[0-9]+}”)
Comment From: wilkinsona
@ApplicationPath is part of JAX-RS. As such, questions about what it supports don't belong in Spring Boot's issue tracker. I'd recommend checking the Javadoc for the annotation's value attribute and the JAX-RS spec. If that doesn't help, Stack Overflow may be a good place to ask.