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
相关产品推荐
相关产品推荐

