英文:
Spring issue with @PostConstruct and @PreDestroy
问题
我有一个Spring应用程序,我正尝试使用EmbededRedis进行测试。所以我创建了一个以下的组件来在测试之后初始化和关闭redis。
@Component
public class EmbededRedis {
@Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
@PostConstruct
public void startRedis() throws IOException {
redisServer = new RedisServer(redisPort);
redisServer.start();
}
@PreDestroy
public void stopRedis() {
redisServer.stop();
}
}
但是现在我面临一个奇怪的问题。因为Spring会缓存上下文,PreDestroy并不会在每次测试执行后都被调用,但由于某种原因,@PostConstruct会被调用,EmbededRedis会不断尝试启动正在运行的redis服务器,这在执行中造成问题。
有没有任何方法可以通过任何方式处理这种情况?
**更新**
这是我主要定义测试的方式。
@SpringBootTest(classes = {SpringApplication.class})
@ActiveProfiles("test")
public class RedisApplicationTest {
英文:
I have a Spring application that I am trying to test with EmbededRedis. So I created a component like below to Initialize and kill redis after test.
@Component
public class EmbededRedis {
@Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
@PostConstruct
public void startRedis() throws IOException {
redisServer = new RedisServer(redisPort);
redisServer.start();
}
@PreDestroy
public void stopRedis() {
redisServer.stop();
}
}
But now I am facing a weird issue. Because spring caches the context, PreDestroy doesnt get called everytime after my test is executed, but for some reason, @PostConstruct gets called, and EmbededRedis tries to start the running redis server again and again, which is creatimg issues in the execution.
Is there a way to handle this situation by any mean?
Update
This is how I am primarily defining my tests.
@SpringBootTest(classes = {SpringApplication.class})
@ActiveProfiles("test")
public class RedisApplicationTest {
答案1
得分: 2
放弃这个类,编写一个将 RedisServer
暴露为一个 bean 的 @Configuration
类。
@Configuration
public class EmbeddedRedisConfiguration {
@Bean(initMethod="start", destroyMethod="stop")
public RedisServer embeddedRedisServer(@Value("${spring.redis.port}") int port) {
return new RedisServer(port);
}
}
英文:
Ditch the class and write an @Configuration
class which exposed RedisServer
as a bean.
@Configuration
public void EmbeddedRedisConfiguration {
@Bean(initMethod="start", destroyMethod="stop")
public RedisServer embeddedRedisServer(@Value("${spring.redis.port}") int port) {
return new RedisServer(port);
}
}
答案2
得分: 0
所以我按照 @M. Deinum 的建议对 ContextInitialization 进行了调试。
对我来说,问题是,我们的应用程序在模拟不同的类,以便将模拟与 Spring 上下文混合在一起。
现在,当您使用模拟时,MockitoContextInitializer
也成为您的缓存键的一部分,这导致缓存未命中。原因是,模拟下的类在不同的测试类中显然是不同的。
看着这种情况,我更倾向于使用 @DirtiesContext
在测试完成后使上下文无效,这样我稍后可以为不同的测试重新初始化上下文。
注意 @DirtiesContext
从某种意义上来说,建议避免使用,因为它会减慢测试速度。
英文:
So I debuged the ContextInitialization as suggested by @M. Deinum.
For me, the porblem was, Our application was mocking different classes in order to mix mocking with Spring context.
Now, when you use mocks, MockitoContextInitializer
also becomes part of your cache key, which results in cache miss. Reason is, The classes under mock are obviously different for different test classes.
Looking at the situation, I preferred to go ahead with @DirtiesContext
to invalidate the contest after the test is done, so that I can reinitialize the context later on for different test.
Note @DirtiesContext
is in a way recommended to be avoided as it slows down your tests.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论