You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 2.7.18中@ConditionalOnMissingBean未生效,生成两个InternalResourceViewResolver

问题:Spring Boot中出现两个InternalResourceViewResolver实例的排查与解决

问题场景

基于Spring Boot 2.7.18进行自动配置,自定义以下配置类创建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;
    }
}

运行后通过/actuator/beans发现存在两个InternalResourceViewResolver实例:

"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"
    ]
}

其中WebMvcAutoConfiguration中的defaultViewResolver带有@ConditionalOnMissingBean注解,但仍被创建:

@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix(this.mvcProperties.getView().getPrefix());
    resolver.setSuffix(this.mvcProperties.getView().getSuffix());
    return resolver;
}

通过/actuator/conditions查看条件判断结果为:

"WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#defaultViewResolver": [
    {
        "condition": "OnBeanCondition",
        "message": "@ConditionalOnMissingBean (types: org.springframework.web.servlet.view.InternalResourceViewResolver; SearchStrategy: all) did not find any beans"
    }
]

排查思路

1. 配置类加载顺序与条件触发时机

@ConditionalOnMissingBean的生效依赖于Bean的注册顺序。如果自定义配置类的加载时机晚于WebMvcAutoConfiguration,那么在自动配置类执行条件检查时,自定义的InternalResourceViewResolver还未被注册,条件判断会认为不存在该Bean,从而创建默认实例。

  • 检查自定义配置类的条件注解:@ConditionalOnClass(javax.servlet.jsp.jstl.core.Config.class)要求JSTL类存在才会加载配置类。如果JSTL依赖的加载时机晚于WebMvcAutoConfiguration的条件检查,会导致自定义配置类延迟加载。
  • 对比自动配置类的条件:WebMvcAutoConfiguration的触发条件是@ConditionalOnWebApplication(type = SERVLET) + @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }),这些类通常在启动初期就会被加载,所以自动配置类会优先触发。

2. 验证Bean注册顺序

可以通过以下方式确认两个Bean的注册顺序:

  • 在自定义配置类的internalResourceViewResolver()方法中添加日志,输出Bean创建的时间点;
  • 自定义BeanPostProcessor,在Bean初始化前打印Bean名称和时间,对比两个实例的注册顺序。

3. 检查@ConditionalOnMissingBean的搜索范围

虽然条件信息显示搜索策略为all,但如果自定义Bean所在的配置类未被加载(条件未满足),搜索时自然无法找到该Bean。需要确认JSTL的Config.class是否确实存在于类路径中,可通过打印类路径或检查依赖树验证。

解决方法

方法一:强制自定义配置类优先加载

给自定义配置类添加@AutoConfigureBefore(WebMvcAutoConfiguration.class)注解,确保自定义配置类在自动配置类之前加载。这样当自动配置类执行@ConditionalOnMissingBean检查时,自定义的InternalResourceViewResolver已经存在,就不会创建默认实例:

@Configuration
@ConditionalOnClass(javax.servlet.jsp.jstl.core.Config.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
public class ViewResolverConfiguration {
    // 原有代码不变
}

方法二:设置自定义Bean为优先实例(仅解决优先级,不消除重复Bean)

给自定义的InternalResourceViewResolver添加@Primary注解,确保Spring在注入时优先选择自定义实例。但此方法不会阻止默认Bean的创建,仅解决注入优先级问题:

@Bean
@Primary
public InternalResourceViewResolver internalResourceViewResolver(...) {
    // 原有代码不变
}

方法三:排除自动配置类(不推荐)

通过spring.autoconfigure.exclude属性排除WebMvcAutoConfiguration,但这会影响其他MVC自动配置逻辑,仅在特殊场景下使用:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

内容的提问来源于stack exchange,提问作者Niels Bech Nielsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 06:05:54