Spring Flow与JSF集成时HttpRequestHandlerAdapter Bean冲突问题
问题背景
我正在构建基于Spring Flow与JSF的项目,使用Gradle作为构建工具,build.gradle配置如下:
plugins { id 'java' id 'war' id 'org.springframework.boot' version '3.1.2' id 'io.spring.dependency-management' version '1.1.2' } group = 'test.pkg' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.joinfaces:mojarra-spring-boot-starter:5.1.2' compileOnly 'org.springframework.webflow:spring-webflow:3.0.0' implementation 'org.springframework.webflow:spring-webflow:3.0.0' implementation 'org.springframework.webflow:spring-faces:3.0.0' implementation 'jakarta.faces:jakarta.faces-api:4.0.1' runtimeOnly 'jakarta.faces:jakarta.faces-api:4.0.1' runtimeOnly 'org.springframework.webflow:spring-faces:3.0.0' runtimeOnly 'org.springframework.webflow:spring-webflow:3.0.0' runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() }
尝试用纯Java方式完成所有配置,编写了如下@Configuration类:
@Configuration public class WebFlowConfig extends AbstractFacesFlowConfiguration { @Bean public FlowDefinitionRegistry flowDefinitionRegistry(FlowBuilderServices flowBuilderServices) { return getFlowDefinitionRegistryBuilder() .setBasePath("/WEB-INF") .addFlowLocation("/flows/**/*.xml") .setFlowBuilderServices(flowBuilderServices) // 11.5 view resolution .build(); } @Bean public FlowExecutor flowExecutor(FlowDefinitionRegistry flowDefinitionRegistry) { return getFlowExecutorBuilder(flowDefinitionRegistry) .addFlowExecutionListener(new FlowFacesContextLifecycleListener()) // 13.3 .build(); } @Bean public FlowBuilderServices flowBuilderServices(MvcViewFactoryCreator mvcViewFactoryCreator) { return getFlowBuilderServicesBuilder() .setDevelopmentMode(true) .setViewFactoryCreator(mvcViewFactoryCreator) .build(); } @Bean public MvcViewFactoryCreator mvcViewFactoryCreator() { MvcViewFactoryCreator mvcViewFactoryCreator = new MvcViewFactoryCreator(); return mvcViewFactoryCreator; } //13.2 @Bean public ServletRegistrationBean jsfServletBean() { ServletRegistrationBean<jakarta.faces.webapp.FacesServlet> servletRegistrationBean = new ServletRegistrationBean(new FacesServlet(), "*.xhtml"); servletRegistrationBean.setLoadOnStartup(1); return servletRegistrationBean; } //auch 13.2 @Bean public ServletContextInitializer initializer() { return new ServletContextInitializer() { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml"); } }; } //13.3 public JsfFlowHandlerAdapter jsfFlowHandlerAdapter(FlowExecutor flowExecutor) { JsfFlowHandlerAdapter jsfFlowHandlerAdapter = new JsfFlowHandlerAdapter(); jsfFlowHandlerAdapter.setFlowExecutor(flowExecutor); return jsfFlowHandlerAdapter; } @Bean public ServletRegistrationBean webFlowServletBean() { ServletRegistrationBean<DispatcherServlet> bean = new ServletRegistrationBean(new DispatcherServlet(), "/flows/*"); bean.addInitParameter("contextConfigLocation", "/WEB-INF/web-application-config.xml"); bean.setLoadOnStartup(1); bean.setOrder(1); return bean; } @Bean public FlowHandlerMapping flowHandlerMapping(FlowDefinitionRegistry flowDefinitionRegistry) { FlowHandlerMapping flowHandlerMapping = new FlowHandlerMapping(); flowHandlerMapping.setFlowRegistry(flowDefinitionRegistry); flowHandlerMapping.setOrder(0); return flowHandlerMapping; } }
运行项目时出现以下错误:
The bean 'httpRequestHandlerAdapter', defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [test/pkg/testflow/config/WebFlowConfig.class] and overriding is disabled.
我不想开启Bean覆盖,希望使用自定义Bean,求纯Java配置的Spring Flow+JSF项目解决方案。
问题分析与解决方案
1. 冲突根源
AbstractFacesFlowConfiguration已自动注册httpRequestHandlerAdapter Bean,而Spring Boot的WebMvc自动配置也会注册同名Bean,导致冲突。此外配置存在冗余和错误:
- 重复依赖:同时声明
compileOnly和implementation的spring-webflow,属于冗余 - 手动注册FacesServlet:JoinFaces Starter已自动配置FacesServlet,无需手动注册
- 多余的DispatcherServlet注册:Spring Boot已有默认DispatcherServlet,无需单独为WebFlow注册新实例
JsfFlowHandlerAdapter未加@Bean注解,无法被Spring容器识别
2. 优化后的Gradle依赖
精简build.gradle,移除冗余依赖:
plugins { id 'java' id 'war' id 'org.springframework.boot' version '3.1.2' id 'io.spring.dependency-management' version '1.1.2' } group = 'test.pkg' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } repositories { mavenCentral() } dependencies { // Spring Boot Web基础 implementation 'org.springframework.boot:spring-boot-starter-web' // JoinFaces整合JSF(自动配置FacesServlet等) implementation 'org.joinfaces:mojarra-spring-boot-starter:5.1.2' // Spring WebFlow核心依赖 implementation 'org.springframework.webflow:spring-webflow:3.0.0' implementation 'org.springframework.webflow:spring-faces:3.0.0' // 数据库驱动 runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' // 测试依赖 testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() }
3. 修正后的WebFlow配置类
移除冗余配置,解决Bean冲突,确保JsfFlowHandlerAdapter被正确注册:
@Configuration public class WebFlowConfig extends AbstractFacesFlowConfiguration { // 定义Flow注册表,扫描WEB-INF下的flow配置文件 @Bean public FlowDefinitionRegistry flowDefinitionRegistry(FlowBuilderServices flowBuilderServices) { return getFlowDefinitionRegistryBuilder() .setBasePath("/WEB-INF") .addFlowLocationPattern("/flows/**/*.xml") .setFlowBuilderServices(flowBuilderServices) .build(); } // 定义Flow执行器,添加JSF生命周期监听器 @Bean public FlowExecutor flowExecutor(FlowDefinitionRegistry flowDefinitionRegistry) { return getFlowExecutorBuilder(flowDefinitionRegistry) .addFlowExecutionListener(new FlowFacesContextLifecycleListener()) .build(); } // 配置Flow构建服务,启用开发模式,关联视图工厂 @Bean public FlowBuilderServices flowBuilderServices(MvcViewFactoryCreator mvcViewFactoryCreator) { return getFlowBuilderServicesBuilder() .setDevelopmentMode(true) .setViewFactoryCreator(mvcViewFactoryCreator) .build(); } // MVC视图工厂创建器,适配JSF视图解析 @Bean public MvcViewFactoryCreator mvcViewFactoryCreator() { MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator(); // 设置JSF视图后缀,与JoinFaces保持一致 factoryCreator.setViewSuffix(".xhtml"); return factoryCreator; } // 注册JSF Flow处理器适配器,必须加@Bean注解 @Bean public JsfFlowHandlerAdapter jsfFlowHandlerAdapter(FlowExecutor flowExecutor) { JsfFlowHandlerAdapter adapter = new JsfFlowHandlerAdapter(); adapter.setFlowExecutor(flowExecutor); return adapter; } // Flow处理器映射,设置优先级高于默认MVC映射 @Bean public FlowHandlerMapping flowHandlerMapping(FlowDefinitionRegistry flowDefinitionRegistry) { FlowHandlerMapping mapping = new FlowHandlerMapping(); mapping.setFlowRegistry(flowDefinitionRegistry); mapping.setOrder(0); return mapping; } // 配置JSF初始化参数,替代手动ServletContextInitializer @Bean public ServletContextInitializer jsfInitializer() { return servletContext -> { servletContext.setInitParameter("jakarta.faces.DEFAULT_SUFFIX", ".xhtml"); // 可添加其他JSF配置参数,比如开发模式 servletContext.setInitParameter("jakarta.faces.DEVELOPMENT", "true"); }; } }
4. 关键说明
- 移除手动注册的
FacesServlet和额外的DispatcherServlet,由JoinFaces和Spring Boot自动配置处理,避免冲突 - 修正
JsfFlowHandlerAdapter的@Bean注解,确保Spring能识别并管理该Bean - 使用
addFlowLocationPattern替代addFlowLocation,支持批量扫描Flow配置文件 - 替换
javax.faces前缀为jakarta.faces,符合Jakarta EE 9+规范(Spring Boot 3.x基于Jakarta EE)
内容的提问来源于stack exchange,提问作者daskai0815
相关产品推荐
相关产品推荐

