1、问题:
在run as Maven test出现以上Exception。
项目集成了spring+atomikos jta
主要原因是所有的单元测试类都继承了BaseTest,本来是为了方便每次单元测试前都可以获取ApplicationContext,其部分源码如下:
public class BaseTest {
...
private static ApplicationContext context;
@BeforeClass
public static void initContext() {
context = new FileSystemXmlApplicationContext("src/main/webapp/WEB-INF/spring-config.xml");
}
protected ApplicationContext getContext() {
return context;
}
...
}
如果没有用atomikos jta是没问题的,但事与愿违,出现了此Exception
2、原因:
从atomikos找到了明白了原因:
This happens if you accidentally instantiate two connectors with the same value for uniqueResourceName. A common example is if you include spring config files multiple times within the same VM: Spring will then create all the beans more than once - and this is problematic for recovery. An example of this problem is here: javax.naming.NamingException: Another resource already exists...
附链接:http://www.atomikos.com/Documentation/KnownProblems#JNDI_Error_Another_resource_alre
意思是多次加载了spring配置文件时spring在上下文中多次创建了beans,即在同一个VM中创建了多个dataSource,就违背了每个dataSource必须uniqueResourceName的规定,
so异常就出现啦。
3、解决方案:
只要在没个单元测试类运行结束之后关闭连接就OK啦,附上修改后的BaseTest部分源码:
public class BaseTest {
...
private static ApplicationContext context;
@BeforeClass
public static void initContext() {
context = new FileSystemXmlApplicationContext("src/main/webapp/WEB-INF/spring-config.xml");
}
/**
* 必须在每个单元测试类运行结束之后关闭连接,
* 要不会出现Another resource already exists with name xxx一次
*/
@AfterClass
public static void destroyTransaction() {
AtomikosDataSourceBean webds = (AtomikosDataSourceBean)context.getBean("webDataSource");
AtomikosDataSourceBean ds = (AtomikosDataSourceBean)context.getBean("dataSource");
webds.close();
ds.close();
}
public ApplicationContext getContext() {
return context;
}
...
}
希望能帮到遇到同一个问题的朋友啦。最后附上部分spring配置文件:
...
<bean id="webDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<description>web mysql xa datasource</description>
<property name="uniqueResourceName">
<value>web_ds</value>
</property>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="user">${database.user}</prop>
<prop key="password">${database.password}</prop>
<prop key="URL">${database.jdbcUrl}</prop>
</props>
</property>
<property name="poolSize" value="${database.maxPoolSize}"/>
</bean>
<bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<description>admin mysql xa datasource</description>
<property name="uniqueResourceName">
<value>admin_ds</value>
</property>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="user">${admin.database.user}</prop>
<prop key="password">${admin.database.password}</prop>
<prop key="URL">${admin.database.jdbcUrl}</prop>
</props>
</property>
<property name="poolSize" value="${database.maxPoolSize}"/>
</bean>
...