当 运行 spring 引导测试得到 hazelcast.core.DuplicateInstanceNameException
When run spring boot tests got hazelcast.core.DuplicateInstanceNameException
如何使用 Hazelcast 执行 spring 启动应用程序的集成测试,因为当 运行 所有测试都得到 hazelcast.core.DuplicateInstanceNameException 时?
我使用 Spring Boot 2.0.0.RC1 和 Hazelcast 3.9.2
为 hazelcast 使用 java 配置:
@Bean
public Config getHazelCastServerConfig() {
final Config config = new Config();
config.setInstanceName(hzInstance);
config.getGroupConfig().setName(hzGroupName).setPassword(hzGroupPassword);
final ManagementCenterConfig managementCenterConfig = config.getManagementCenterConfig();
managementCenterConfig.setEnabled(true);
managementCenterConfig.setUrl(mancenter);
final MapConfig mapConfig = new MapConfig();
mapConfig.setName(mapName);
mapConfig.setEvictionPolicy(EvictionPolicy.NONE);
mapConfig.setTimeToLiveSeconds(0);
mapConfig.setMaxIdleSeconds(0);
config.getScheduledExecutorConfig(scheduler)
.setPoolSize(16)
.setCapacity(100)
.setDurability(1);
final NetworkConfig networkConfig = config.getNetworkConfig();
networkConfig.setPort(5701);
networkConfig.setPortAutoIncrement(true).setPortCount(30);
final JoinConfig joinConfig = networkConfig.getJoin();
joinConfig.getMulticastConfig().setEnabled(false);
joinConfig.getAwsConfig().setEnabled(false);
final TcpIpConfig tcpIpConfig = joinConfig.getTcpIpConfig();
tcpIpConfig.addMember(memberOne)
.addMember(memberTwo);
tcpIpConfig.setEnabled(true);
return config;
}
@Bean
public HazelcastInstance getHazelCastServerInstance() {
final HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(getHazelCastServerConfig());
hazelcastInstance.getClientService().addClientListener(new ClientListener() {
@Override
public void clientConnected(Client client) {
System.out.println(String.format("Connected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
log.info(String.format("Connected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
}
@Override
public void clientDisconnected(Client client) {
System.out.println(String.format("Disconnected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
log.info(String.format("Disconnected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
}
});
return hazelcastInstance;
}
我有简单的测试:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = UpaSdcApplication.class)
@ActiveProfiles("test")
public class CheckEndpoints {
@Autowired
private ApplicationContext context;
private static final String HEALTH_ENDPOINT = "/actuator/health";
private static WebTestClient testClient;
@Before
public void init() {
testClient = org.springframework.test.web.reactive.server.WebTestClient
.bindToApplicationContext(context)
.configureClient()
.filter(basicAuthentication())
.build();
}
@Test
public void testHealth(){
testClient.get().uri(HEALTH_ENDPOINT).accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.json("{\"status\": \"UP\"}");
}
}
如果 运行 测试 class 与其他测试分开 - 它执行良好并通过。
如果 运行 与其他测试 - 得到异常:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.hazelcast.core.HazelcastInstance]: Factory method 'getHazelCastServerInstance' threw exception; nested exception is com.hazelcast.core.DuplicateInstanceNameException: HazelcastInstance with name 'counter-instance' already exists!
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:579)
... 91 more
Caused by: com.hazelcast.core.DuplicateInstanceNameException: HazelcastInstance with name 'counter-instance' already exists!
at com.hazelcast.instance.HazelcastInstanceFactory.newHazelcastInstance(HazelcastInstanceFactory.java:170)
at com.hazelcast.instance.HazelcastInstanceFactory.newHazelcastInstance(HazelcastInstanceFactory.java:124)
at com.hazelcast.core.Hazelcast.newHazelcastInstance(Hazelcast.java:58)
at net.kyivstar.upa.sdc.config.HazelcastConfiguration.getHazelCastServerInstance(HazelcastConfiguration.java:84)
at net.kyivstar.upa.sdc.config.HazelcastConfiguration$$EnhancerBySpringCGLIB$$c7da65f3.CGLIB$getHazelCastServerInstance[=15=](<generated>)
at net.kyivstar.upa.sdc.config.HazelcastConfiguration$$EnhancerBySpringCGLIB$$c7da65f3$$FastClassBySpringCGLIB$$b920d5ef.invoke(<generated>)
你是怎么解决这个问题的?你如何 运行 集成测试?
instanceName
配置元素用于创建命名的 Hazelcast 成员,并且对于 JVM 中的每个 Hazelcast 实例应该是唯一的。在您的情况下,您应该为同一 JVM 中的每个 HazelcastInstance
bean 创建设置一个不同的实例名称,或者如果您不使用实例名称召回实例,则可以完全删除 instanceName
配置。
在 运行 我的测试中遇到了同样的问题。在我的例子中,原因是 spring 测试框架试图启动新的上下文,同时保持旧的缓存 - 因此试图创建另一个具有相同名称的 hazelcast 实例,而一个已经在缓存的上下文中。
Once the TestContext framework loads an ApplicationContext (or
WebApplicationContext) for a test, that context is cached and reused
for all subsequent tests that declare the same unique context
configuration within the same test suite.
阅读 here 以了解有关 spring 测试框架如何管理测试上下文的更多信息。
我目前正在研究解决方案,稍后会post。我看到的一种可能的解决方案是在每次使用 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
进行测试后删除测试上下文,但这在性能方面非常昂贵。
我遇到了同样的问题,我通过检查实例是否已经存在解决了这个问题:
@Bean
public CacheManager cacheManager() {
HazelcastInstance existingInstance = Hazelcast.getHazelcastInstanceByName(CACHE_INSTANCE_NAME);
HazelcastInstance hazelcastInstance = null != existingInstance
? existingInstance
: Hazelcast.newHazelcastInstance(hazelCastConfig());
return new HazelcastCacheManager(hazelcastInstance);
}
你可以看到剩下的代码here。
如何使用 Hazelcast 执行 spring 启动应用程序的集成测试,因为当 运行 所有测试都得到 hazelcast.core.DuplicateInstanceNameException 时?
我使用 Spring Boot 2.0.0.RC1 和 Hazelcast 3.9.2
为 hazelcast 使用 java 配置:
@Bean
public Config getHazelCastServerConfig() {
final Config config = new Config();
config.setInstanceName(hzInstance);
config.getGroupConfig().setName(hzGroupName).setPassword(hzGroupPassword);
final ManagementCenterConfig managementCenterConfig = config.getManagementCenterConfig();
managementCenterConfig.setEnabled(true);
managementCenterConfig.setUrl(mancenter);
final MapConfig mapConfig = new MapConfig();
mapConfig.setName(mapName);
mapConfig.setEvictionPolicy(EvictionPolicy.NONE);
mapConfig.setTimeToLiveSeconds(0);
mapConfig.setMaxIdleSeconds(0);
config.getScheduledExecutorConfig(scheduler)
.setPoolSize(16)
.setCapacity(100)
.setDurability(1);
final NetworkConfig networkConfig = config.getNetworkConfig();
networkConfig.setPort(5701);
networkConfig.setPortAutoIncrement(true).setPortCount(30);
final JoinConfig joinConfig = networkConfig.getJoin();
joinConfig.getMulticastConfig().setEnabled(false);
joinConfig.getAwsConfig().setEnabled(false);
final TcpIpConfig tcpIpConfig = joinConfig.getTcpIpConfig();
tcpIpConfig.addMember(memberOne)
.addMember(memberTwo);
tcpIpConfig.setEnabled(true);
return config;
}
@Bean
public HazelcastInstance getHazelCastServerInstance() {
final HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(getHazelCastServerConfig());
hazelcastInstance.getClientService().addClientListener(new ClientListener() {
@Override
public void clientConnected(Client client) {
System.out.println(String.format("Connected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
log.info(String.format("Connected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
}
@Override
public void clientDisconnected(Client client) {
System.out.println(String.format("Disconnected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
log.info(String.format("Disconnected %s %s %s", client.getClientType(), client.getUuid(), client.getSocketAddress()));
}
});
return hazelcastInstance;
}
我有简单的测试:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = UpaSdcApplication.class)
@ActiveProfiles("test")
public class CheckEndpoints {
@Autowired
private ApplicationContext context;
private static final String HEALTH_ENDPOINT = "/actuator/health";
private static WebTestClient testClient;
@Before
public void init() {
testClient = org.springframework.test.web.reactive.server.WebTestClient
.bindToApplicationContext(context)
.configureClient()
.filter(basicAuthentication())
.build();
}
@Test
public void testHealth(){
testClient.get().uri(HEALTH_ENDPOINT).accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.json("{\"status\": \"UP\"}");
}
}
如果 运行 测试 class 与其他测试分开 - 它执行良好并通过。 如果 运行 与其他测试 - 得到异常:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.hazelcast.core.HazelcastInstance]: Factory method 'getHazelCastServerInstance' threw exception; nested exception is com.hazelcast.core.DuplicateInstanceNameException: HazelcastInstance with name 'counter-instance' already exists!
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:579)
... 91 more
Caused by: com.hazelcast.core.DuplicateInstanceNameException: HazelcastInstance with name 'counter-instance' already exists!
at com.hazelcast.instance.HazelcastInstanceFactory.newHazelcastInstance(HazelcastInstanceFactory.java:170)
at com.hazelcast.instance.HazelcastInstanceFactory.newHazelcastInstance(HazelcastInstanceFactory.java:124)
at com.hazelcast.core.Hazelcast.newHazelcastInstance(Hazelcast.java:58)
at net.kyivstar.upa.sdc.config.HazelcastConfiguration.getHazelCastServerInstance(HazelcastConfiguration.java:84)
at net.kyivstar.upa.sdc.config.HazelcastConfiguration$$EnhancerBySpringCGLIB$$c7da65f3.CGLIB$getHazelCastServerInstance[=15=](<generated>)
at net.kyivstar.upa.sdc.config.HazelcastConfiguration$$EnhancerBySpringCGLIB$$c7da65f3$$FastClassBySpringCGLIB$$b920d5ef.invoke(<generated>)
你是怎么解决这个问题的?你如何 运行 集成测试?
instanceName
配置元素用于创建命名的 Hazelcast 成员,并且对于 JVM 中的每个 Hazelcast 实例应该是唯一的。在您的情况下,您应该为同一 JVM 中的每个 HazelcastInstance
bean 创建设置一个不同的实例名称,或者如果您不使用实例名称召回实例,则可以完全删除 instanceName
配置。
在 运行 我的测试中遇到了同样的问题。在我的例子中,原因是 spring 测试框架试图启动新的上下文,同时保持旧的缓存 - 因此试图创建另一个具有相同名称的 hazelcast 实例,而一个已经在缓存的上下文中。
Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context is cached and reused for all subsequent tests that declare the same unique context configuration within the same test suite.
阅读 here 以了解有关 spring 测试框架如何管理测试上下文的更多信息。
我目前正在研究解决方案,稍后会post。我看到的一种可能的解决方案是在每次使用 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
进行测试后删除测试上下文,但这在性能方面非常昂贵。
我遇到了同样的问题,我通过检查实例是否已经存在解决了这个问题:
@Bean
public CacheManager cacheManager() {
HazelcastInstance existingInstance = Hazelcast.getHazelcastInstanceByName(CACHE_INSTANCE_NAME);
HazelcastInstance hazelcastInstance = null != existingInstance
? existingInstance
: Hazelcast.newHazelcastInstance(hazelCastConfig());
return new HazelcastCacheManager(hazelcastInstance);
}
你可以看到剩下的代码here。