Spring issue with @PostConstruct and @PreDestroy

huangapple go评论68阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2020年8月19日 18:09:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/63484705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定