关于java:嵌入式Redis的Spring Boot

Embedded Redis for Spring Boot

我在机器上的本地Redis服务器的帮助下,使用Spring Boot运行了集成测试用例。

但是我想要一个嵌入式Redis服务器,它不依赖于任何服务器,并且可以在任何环境下运行,例如H2内存数据库。我该怎么办?

1
2
3
4
5
6
7
8
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@IntegrationTest("server.port:0")
@SpringApplicationConfiguration(classes = Application.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MasterIntegrationTest {

}


您可以使用嵌入式Redis,例如https://github.com/kstyrc/embedded-redis

  • 将依赖项添加到您的pom.xml
  • 调整集成测试的属性,使其指向嵌入式Redis,例如:

    1
    2
    3
    4
    spring:
      redis:
        host: localhost
        port: 6379
  • 仅在测试中定义的组件中实例化嵌入式redis服务器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @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();
        }
    }

  • 您可以将ozimov / embedded-redis用作Maven(-test)依赖项(这是kstyrc / embedded-redis的后继者)。

  • 将依赖项添加到pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    <dependencies>
      ...
      <dependency>
        <groupId>it.ozimov</groupId>
        embedded-redis</artifactId>
        <version>0.7.1</version>
        <scope>test</scope>
      </dependency>
  • 为集成测试调整应用程序属性

    1
    2
    spring.redis.host=localhost
    spring.redis.port=6379
  • 在测试配置中使用嵌入式Redis服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @TestConfiguration
    public static class EmbededRedisTestConfiguration {

      private final redis.embedded.RedisServer redisServer;

      public EmbededRedisTestConfiguration(@Value("${spring.redis.port}") final int redisPort) throws IOException {
        this.redisServer = new redis.embedded.RedisServer(redisPort);
      }

      @PostConstruct
      public void startRedis() {
        this.redisServer.start();
      }

      @PreDestroy
      public void stopRedis() {
        this.redisServer.stop();
      }
    }

  • 另一种简洁的方法是使用testcontainers库,该库可以运行可以在Docker容器中运行的任何类型的应用程序,Redis也不例外。我最喜欢的一点是它与Spring Test生态系统紧密结合。

    行家的依存关系:

    1
    2
    3
    4
    5
    <dependency>
        <groupId>org.testcontainers</groupId>
        testcontainers</artifactId>
        <version>${testcontainers.version}</version>
    </dependency>

    简单集成测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
    @ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
    @DirtiesContext
    public abstract class AbstractIntegrationTest {

        private static int REDIS_PORT = 6379;

        @ClassRule
        public static GenericContainer redis = new GenericContainer("redis:5-alpine").withExposedPorts(REDIS_PORT);

        public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
            @Override
            public void initialize(ConfigurableApplicationContext ctx) {
                // Spring Boot 1.5.x
                TestPropertySourceUtils.addInlinedPropertiesToEnvironment(ctx,
                   "spring.redis.host=" + redis.getContainerIpAddress(),
                   "spring.redis.port=" + redis.getMappedPort(REDIS_PORT));

                // Spring Boot 2.x.
                TestPropertyValues.of(
                   "spring.redis.host:" + redis.getContainerIpAddress(),
                   "spring.redis.port:" + redis.getMappedPort(REDIS_PORT))
                    .applyTo(ctx);
            }
        }
    }

    自Spring Framework 5.2.5(Spring Boot 2.3.x)起,您可以使用功能强大的DynamicPropertySource批注。
    这是一个示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @ExtendWith(SpringExtension.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
    public abstract class AbstractIT {

        static GenericContainer redisContainer = new GenericContainer("redis:5-alpine").withExposedPorts(6379);

        @DynamicPropertySource
        static void properties(DynamicPropertyRegistry r) throws IOException {
            r.add("spring.redis.host", redisContainer::getContainerIpAddress);
            r.add("spring.redis.port", redisContainer::getFirstMappedPort);
        }
    }


    您可以看到此存储库:https://github.com/caryyu/spring-embedded-redis-server,与Spring和Spring Boot完全集成

    Maven依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.github.caryyu</groupId>
    spring-embedded-redis-server</artifactId>
    <version>1.1</version>
    </dependency>

    Spring靴子注释

    1
    2
    3
    4
    @Bean
    public RedisServerConfiguration redisServerConfiguration() {
    return new RedisServerConfiguration();
    }

    application.yml的用法

    1
    2
    3
    4
    spring:
        redis:
            port: 6379
            embedded: true