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

Tomcat中Spring+Hibernate应用集成测试:如何访问独立应用的Bean?

解决方案:访问运行中Tomcat应用的Spring上下文

针对你遇到的「测试需要访问已启动Tomcat应用的Spring上下文、避免重复启动应用」的问题,这里有两种实用的方案,都能让测试直接连接到运行中的应用,获取已初始化的Bean和EntityManager:

方案一:通过HTTP远程调用暴露Spring上下文

这个方法通过Spring的HTTP Invoker将应用的ApplicationContext暴露为远程服务,测试代码可以通过HTTP请求获取上下文实例。

1. 在应用中配置远程服务

首先在你的Spring配置文件(比如http-invoker-servlet.xml)中添加暴露ApplicationContext的Bean:

<!-- 暴露ApplicationContext作为远程服务 -->
<bean name="/ApplicationContextExporter" class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter">
    <property name="service" ref="applicationContext"/>
    <property name="serviceInterface" value="org.springframework.context.ApplicationContext"/>
</bean>

然后在web.xml中配置对应的DispatcherServlet来处理远程请求:

<servlet>
    <servlet-name>httpInvoker</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/http-invoker-servlet.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>httpInvoker</servlet-name>
    <url-pattern>/remoting/*</url-pattern>
</servlet-mapping>

2. 在测试中获取远程上下文

测试类中通过HttpInvokerProxyFactoryBean连接到远程服务,获取ApplicationContext:

import org.springframework.context.ApplicationContext;
import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
import org.junit.BeforeClass;
import org.junit.Test;

public class MyRepositoryIntegrationTest {
    private static ApplicationContext context;

    @BeforeClass
    public static void setupRemoteContext() {
        HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
        // 替换为你的应用访问地址
        factoryBean.setServiceUrl("http://localhost:8080/your-app-name/remoting/ApplicationContextExporter");
        factoryBean.setServiceInterface(ApplicationContext.class);
        factoryBean.afterPropertiesSet();
        context = (ApplicationContext) factoryBean.getObject();
    }

    @Test
    void testMyRepository() {
        // 获取已在Tomcat中初始化的MyRepository Bean
        MyRepository repository = context.getBean(MyRepository.class);
        
        // 创建测试实体
        Item item = new Item();
        // 设置实体属性...
        
        // 调用Bean的业务方法(事务在服务器端执行)
        repository.myMethod(item);
        
        // 获取EntityManager验证数据库状态
        EntityManager em = context.getBean(EntityManager.class);
        Item savedItem = em.find(Item.class, item.getId());
        
        // 断言验证
        assertNotNull(savedItem);
        // 其他业务逻辑断言...
    }
}

方案二:通过JMX暴露Spring上下文

如果你的测试环境允许启用JMX,可以通过JMX连接到运行中的Tomcat,直接获取ApplicationContext。

1. 配置Tomcat启用JMX

启动Tomcat时添加以下JVM参数,开启JMX远程访问:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

2. 在应用中配置JMX暴露上下文

在applicationContext.xml中添加JMX相关配置,让Spring暴露ApplicationContext:

<!-- 启用MBean服务器 -->
<context:mbean-server/>
<!-- 自动暴露Spring Bean为MBean -->
<context:mbean-export/>
<!-- 暴露ApplicationContext本身 -->
<bean id="contextExporter" class="org.springframework.context.support.ContextExporter"/>

3. 在测试中通过JMX获取上下文

测试类中连接到Tomcat的JMX服务器,获取ApplicationContext:

import org.springframework.context.ApplicationContext;
import javax.management.JMXConnector;
import javax.management.JMXConnectorFactory;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXServiceURL;
import org.junit.BeforeClass;
import org.junit.Test;

public class MyRepositoryJmxTest {
    private static ApplicationContext context;

    @BeforeClass
    public static void setupJmxContext() throws Exception {
        // 连接到Tomcat的JMX服务
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
        JMXConnector connector = JMXConnectorFactory.connect(url);
        MBeanServerConnection connection = connector.getMBeanServerConnection();
        
        // 获取ApplicationContext的MBean实例
        ObjectName contextName = new ObjectName("org.springframework.context:name=ApplicationContext,type=org.springframework.context.support.ClassPathXmlApplicationContext");
        context = (ApplicationContext) connection.getAttribute(contextName, "ApplicationContext");
    }

    @Test
    void testMyRepository() {
        // 后续测试逻辑和方案一完全一致
        MyRepository repository = context.getBean(MyRepository.class);
        // ... 测试代码
    }
}

关键注意事项

  • 事务处理:因为MyRepository的方法标注了@Transactional,远程调用时事务会在Tomcat服务器端执行,不需要在测试中额外处理事务。
  • 安全性:上述配置仅适合测试环境,生产环境不要暴露ApplicationContext或开启无认证的JMX访问,避免安全风险。
  • 热部署支持:两种方案都不需要在测试中启动应用,Tomcat可以保持运行状态,你可以使用Tomcat自带的热部署或JRebel等工具修改代码后即时生效,测试直接运行即可。

内容的提问来源于stack exchange,提问作者Vojtěch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:14:37