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

基于Tomcat10的JSF2.3+CDI+Spring Bean整合问题咨询

Jakarta JSF 2.3 与 Spring JDBC 整合问题

环境配置

  • Tomcat 10.x,搭载JBoss Weld(weld-servlet-shaded 5.0.0)以支持CDI
  • GlassFish 4.0.0 提供的 Jakarta Faces(jakarta.faces)
  • Spring Core、Context、JDBC 6.0.2,不使用spring-web(以JSF作为Web框架),未使用Spring Boot

代码示例

JSF Bean (UserProfile)

@Named
@RequestScoped
public class UserProfile {

    @Inject
    private UserService userService;

    public String getMessage() {
        return userService.getMessage();
    }
}

Spring Service (UserService)

@Service
public class UserService {

    @Inject
    private UserDao userDao;

    public String getMessage() {
        return userDao.getMessage();
    }
}

Spring DAO (UserDao)

@Repository
public class UserDao extends JdbcDaoSupport{
    
    @Autowired
    private DataSource dataSource;
    
    
    @PostConstruct
    public void init() {
        setDataSource(dataSource);
    }
    
    public String getMessage(){
        Integer empCount =  getJdbcTemplate().queryForObject("SELECT COUNT(*) FROM EMPLOYEE", Integer.class) ;
        return empCount.toString();
    }
}

问题描述

数据源、Hikari配置及JdbcTemplate定义在applicationContext.xml中,但数据源未初始化,传统JSF与Spring整合方式无效,现提出以下疑问:

  1. 是否需要spring-web?已用JSF,不想增加复杂度。
  2. 是否需要JBoss Weld?Tomcat10支持CDI2.0,能否省略?
  3. 如何让Spring Bean在Tomcat启动时初始化,供JSF调用?

解答

1. 是否需要spring-web?

不需要。spring-web核心作用是支持Spring MVC的Web层整合,你以JSF作为Web框架,完全可以仅依赖Spring Core、Context、JDBC模块。但要注意:没有spring-web的情况下,Spring不会自动在Web容器启动时加载上下文,需要手动处理初始化逻辑。

2. 是否需要JBoss Weld?

不能省略。Tomcat 10.x本身不内置CDI容器,它仅支持Servlet 5.0(Jakarta EE 9)规范,CDI功能需要单独引入实现。而JSF 2.3依赖CDI管理@Named注解的Bean,以及处理@Inject依赖注入,没有CDI容器的话,JSF的核心依赖注入逻辑会失效。

3. 如何让Spring Bean在Tomcat启动时初始化并供JSF调用?

需要实现Spring上下文与CDI的桥接,具体步骤如下:

步骤1:通过监听器初始化Spring上下文

编写ServletContextListener,在Tomcat启动时加载Spring的ApplicationContext:

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@WebListener
public class SpringContextInitializer implements ServletContextListener {

    private static ApplicationContext springContext;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 加载applicationContext.xml配置文件
        springContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 将上下文存入ServletContext,方便后续获取
        sce.getServletContext().setAttribute("springContext", springContext);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        if (springContext instanceof ClassPathXmlApplicationContext) {
            ((ClassPathXmlApplicationContext) springContext).close();
        }
    }

    public static ApplicationContext getSpringContext() {
        return springContext;
    }
}

步骤2:实现CDI生产者暴露Spring Bean

CDI无法直接识别Spring的@Service/@Repository Bean,需要通过@Producer方法将Spring Bean转换为CDI可注入的实例:

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import org.springframework.context.ApplicationContext;

@ApplicationScoped
public class SpringBeanProducer {

    @Produces
    public UserService produceUserService() {
        ApplicationContext context = SpringContextInitializer.getSpringContext();
        return context.getBean(UserService.class);
    }

    @Produces
    public UserDao produceUserDao() {
        ApplicationContext context = SpringContextInitializer.getSpringContext();
        return context.getBean(UserDao.class);
    }

    // 其他需要暴露给CDI的Spring Bean,添加对应Producer方法即可
}

步骤3:修复数据源初始化问题

检查applicationContext.xml的配置,确保HikariCP依赖已正确引入,示例配置如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 启用组件扫描,识别@Service/@Repository注解 -->
    <context:component-scan base-package="你的服务包路径, 你的DAO包路径"/>

    <!-- Hikari数据源配置 -->
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/你的数据库名"/>
        <property name="username" value="数据库用户名"/>
        <property name="password" value="数据库密码"/>
        <property name="maximumPoolSize" value="10"/>
    </bean>

    <!-- 可选:显式定义JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg ref="dataSource"/>
    </bean>
</beans>

确保项目中已添加HikariCP依赖(如com.zaxxer:HikariCP:5.0.1),Spring会自动初始化数据源并注入到UserDao的dataSource字段。

步骤4:验证整合效果

完成上述配置后,JSF的UserProfile Bean通过@Inject注入的UserService,会由CDI生产者提供对应的Spring Bean实例,Spring上下文会在Tomcat启动时完成初始化,数据源及DAO层逻辑即可正常工作。


内容的提问来源于stack exchange,提问作者Vandan Hatkar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:15:37