I have some spring boot (using 2.7.18) autoconfiguration, which import this configuration, that creates an InternalResourceViewResolver
@Configuration
@ConditionalOnClass(javax.servlet.jsp.jstl.core.Config.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class ViewResolverConfiguration {
@Bean
public InternalResourceViewResolver internalResourceViewResolver(
@Value("${spring.mvc.view.prefix:/WEB-INF/jsp/}") String prefix,
@Value("${spring.mvc.view.suffix:.jsp}") String suffix) {
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix(prefix);
viewResolver.setSuffix(suffix);
viewResolver.setOrder(InternalResourceViewResolver.HIGHEST_PRECEDENCE);
return viewResolver;
}
}
I believe that to be normal conditional configuration. However, at runtime I had two InternalResourceViewResolvers, as seen from /actuator/beans:
"internalResourceViewResolver": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.web.servlet.view.InternalResourceViewResolver",
"resource": "class path resource [com/example/ViewResolverConfiguration.class]",
"dependencies": [
"com.example.ViewResolverConfiguration"
]
},
"defaultViewResolver": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.web.servlet.view.InternalResourceViewResolver",
"resource": "class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]",
"dependencies": [
"org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter"
]
},
As can be seen, it is the one from WebMvcAutoConfiguration, which for some reason ignores a @ConditionalOnMissingBean condition.
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
I can see the positive evaluation from /actuator/conditions, that it does configure it in on that condition:
"WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#defaultViewResolver": [
{
"condition": "OnBeanCondition",
"message": "@ConditionalOnMissingBean (types: org.springframework.web.servlet.view.InternalResourceViewResolver; SearchStrategy: all) did not find any beans"
}
],
Aside from the problem of them being mostly identical, it shouldn't configure the defaultViewResolver, or is there something I don't understand? Has onyone any clues how to investigate or resolve the situation
WebMvcAutoConfiguration autoconfigure in a different priority than the default one with @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
. Therefore when @ConditionalOnMissingBean
is evaluated, your bean is not yet created and therefore it creates the default one.
To fix it, you can either put @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
or (as you suggested) @AutoConfigureBefore(org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.class)
on your @Configuration
class.
If you want to see in which order bean are created, the only way I see is to put a breakpoint in this method (AutoConfigurationSorter), which seems responsible of the ordering. debug: true
configuration does not seems to print the evaluation report in the order which beans has been created.