Spring Boot Actuator requires #EnableWebMvc but that turns off other features - spring-boot

I got confused trying to integrate Actuator to a project using Spring Boot 1.5.11's static resource serving feature:
Spring Boot Actuator does not work without #EnableWebMvc, HTTP 406 is returned because the right Http media converter is not installed.
But if I add #EnableWebMvc, it turns off serving resources from the static folder and other Spring Boot features.
Is there a way to initialize Actuator without losing Boot features?

Found a bug in Spring Boot 2.0, it seems it was there in Boot 1.5 as well. Workaround: setting favorPathExtension to false turns off buggy code in ServletPathExtensionContentNegotiationStrategy and Actuator endpoints start working.
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}

Related

Spring boot actuator auditevents with custom ReactiveAuthenticationManager

I have setup my own ReactiveAuthenticationManager
public class CustomReactiveAuthenticationManager implements ReactiveAuthenticationManager
and then in SecurityWebFilterChain:
.authenticationManager(this.authenticationManager)
However after this setup im not getting anything in the actuator auditevents endpoint:
{"events":[]}
What do I need to change to have audit events even if I use a custom ReactiveAuthenticationManager?
This isn't a problem with your custom AuthenticationManager. It is a limitation of Spring Security. At the time of writing, events are not published when using reactive Spring Security. An enhancement that will remove the limitation is being tracked in this Spring Security issue.

Metrics are not supported for Spring Boot 1.x applications

I am using Spring Boot 2.x but in Spring Boot Admin-> Wallboard -> Metrics I am getting "Metrics are not supported for Spring Boot 1.x applications".
I had the same issue and the reason was, that my application always sent a fixed content-type in the response header.
Spring Boot Admin checks for the content-type application/vnd.spring-boot.actuator.v2. If this content-type is absent, your application is considered to be a Spring Boot 1 application.
In my case, the reason was a WebMvcConfigurer which hard-coded the defaultContentType to application/json. I had something like the following in my configurer:
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON)
.favorPathExtension(false).favorParameter(true).ignoreAcceptHeader(true).useRegisteredExtensionsOnly(true);
}
After changing it to
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.valueOf("application/vnd.spring-boot.actuator.v2+json"), MediaType.APPLICATION_JSON)
.favorPathExtension(false).favorParameter(true).ignoreAcceptHeader(true).useRegisteredExtensionsOnly(true);
}
, Spring Boot Admin showed me the metrics as it was supposed to.

What Is the Correct Way To Use AbstractReactiveWebInitializer

I've got a Spring WebFlux application running successfully as a standalone spring boot application.
I am attempting to run the same application in a Tomcat container, and following the documentation, I've created a class that extends AbstractReactiveWebInitializer. The class requires that I implement a method getConfigClasses that would return classes normally annotated with #Configuration. If the working spring boot app started with a class called ApplicationInitializer, then the resulting implementations would look like this:
#SpringBootApplication(scanBasePackages = "my.pkg")
#EnableDiscoveryClient
#EnableCaching
public class ApplicationInitializer {
public static void main(String... args) {
SpringApplication.run(ApplicationInitializer.class, args);
}
}
and
public class ServletInitializer extends AbstractReactiveWebInitializer {
#Override
protected Class<?>[] getConfigClasses() {
return new Class[] {ApplicationInitializer.class};
}
}
When deployed, the only thing that starts is ApplicationInitializer, none of the autoconfigured Spring Boot classes (Cloud Config, DataSource, etc) ever kick off.
The documenation states this is the class I need to implement, I just expected the remainder of the spring environment to "just work".
How should I be using this class to deploy a Reactive WebFlux Spring Boot application to a Tomcat container ?
Edit:
After some additional research, I've narrowed it down to likely just Cloud Config. During bean post processing on startup, the ConfigurationPropertiesBindingPostProcessor should be enriched with additional property sources (from cloud config), but it appears to be the default Spring properties instead, with no additional sources.
The misisng properties is causing downstream beans to fail.
Spring Boot does not support WAR packaging for Spring WebFlux applications.
The documentation you're referring to is the Spring Framework doc; Spring Framework does support that use case, but without Spring Boot.
you can extend SpringBootServletInitializer, add add reactive servlet on onStartup method

JerseyConfig and #Profile to hide a REST endpoint

I'm trying to hide a REST endpoint based on runtime configuration in Spring and Jersey. The most straightforward way is to throw the NotFoundException from the controller itself but maybe there's more kosher. The controller is registered in the constructor of the config class which extends org.glassfish.jersey.server.ResourceConfig.
I thought of using the #Profile annotation on the controller but I can still access the endpoint. When I hit that endpoint, I get the following error:
o.g.j.s.s.SpringComponentProvider - None or multiple beans found in Spring context
but then Jersey manages to access that controller, which I confirmed by attaching a debugger to the Spring process. So Jersey does not honor the #Profile setting.
On a separate note, I also have Swagger plugged into Jersey and when accessing the definition endpoint (.../swagger.json) I can see the endpoint provided by the #Profile-disabled controller.
Is there anything better I can do here is is throwing the NotFoundException the best option?
Note: Sorry, I thought I saw that you were using Spring Boot. The following answer is only relevant for Spring Boot.
#Profile is only good for Spring bean registration, but you are still registering the service with Jersey as a resource. What you can do is use a ResourceConfigCustomizer and add the #Profile to the customizer. This way it will only register the resource with Jersey ResourceConfig if the correct profile is active.
#Component
#Profile("..")
public class MyResourceConfigCustomizer implements ResourceConfigCustomizer {
#Override
public void customize(ResourceConfig config) {
config.register(MyResource.class);
}
}

JAX-RS - Spring Boot vs without Spring Boot

I want to use Spring boot with JAX-RS (Jersey Implementation). If we were not using Spring Boot, we could use the following code to register all the Rest service classes
#ApplicationPath("/myrest")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorld.class);
return s;
}
}
This works fine in a Servlet 3.0 supported container.
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
Because Spring Boot uses the ResourceConfig type as the as a service that it injects into its auto configurer, namely the JerseyAutoConfiguration. If you look at the source code, you will see
#Autowired
private ResourceConfig config;
From there, Sprig Boot configures the app with that instance. If a ResourceConfig bean is not available in the Spring context, then not auto-configuration happens.

Resources