基于docker的test-containers环境百宝箱
笔者语录: 我开了个公众号【Java你我他】,欢迎大家关注。 在很多时候,程序猿们更关注代码本身,而不愿意把时间花费在环境搭建上,这也是Docker变得越来越受欢迎的原因之一。test-containe是Docker生态圈中的一颗新星,其 主要针对测试领域、背靠Docker实现环境百宝箱功能。 test-containers: 你要的环境,我都有~ 假设我们现在需要一个redis-clust
在很多时候,程序猿们更关注代码本身,而不愿意把时间花费在环境搭建上,这也是Docker变得越来越受欢迎的原因之一。test-containers
是Docker生态圈中的一颗新星,其 主要针对测试领域、背靠Docker实现环境百宝箱功能
。
test-containers: 你要的环境,我都有~
假设我们现在需要一个redis-cluster环境来学习reids pipeline相关的代码知识,那么就需要搭建一套redis集群:
环境支持方式 | 直接搭建 | docker搭建 | 使用test-container |
---|---|---|---|
工作量(简单预估) | 100个单位 | 30个单位 | 15个单位 |
test-container环境支持(示例):
提示一 : test-container基于Docker,使用test-container前需要安装Docker环境。
提示二 : test-container提供的环境不能应用于生产、只能用于测试环境等场景。
使用test-container提供单机redis:
-
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; /** * 单机redis环境支持 * * @author {@link JustryDeng} * @since 2020/11/13 16:14:18 */ @Slf4j @Testcontainers @Import(value = {ExcludedAllAutoConfiguration.class, RedisAutoConfiguration.class}) @ContextConfiguration(initializers = RedisStandaloneEnvSupport .Initializer.class) public class RedisStandaloneEnvSupport implements RedisEnvSupport { /** 标准的docker镜像(即${镜像名}:${tag名}) */ private static final String DOCKER_IMAGE_NAME = "redis:5.0.3-alpine"; /** docker开启的端口 */ private static final int CONTAINER_PORT = 6379; @Container public static GenericContainer<?> redisContainer = new GenericContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME)).withExposedPorts(CONTAINER_PORT); /** * init application context * * @author {@link JustryDeng} * @since 2020/11/14 19:22:23 */ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) { String redisIpAddress = redisContainer.getContainerIpAddress(); log.info("redisIpAddress is [{}]", redisIpAddress); System.setProperty("spring.redis.host", redisIpAddress); Integer redisPort = redisContainer.getMappedPort(CONTAINER_PORT); log.info("redisPort is [{}]", redisPort); Assert.assertNotNull("redisPort is null", redisPort); System.setProperty("spring.redis.port", redisPort.toString()); } } }
-
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.redis.RedisStandaloneEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import javax.annotation.Resource; import java.time.Duration; import java.util.concurrent.TimeUnit; /** * 测试 * * @author {@link JustryDeng} * @since 2020/11/13 16:36:21 */ @Slf4j @SpringBootTest public class RedisStandaloneTest extends RedisStandaloneEnvSupport { @Resource StringRedisTemplate stringRedisTemplate; @Test void one() throws InterruptedException { String name = stringRedisTemplate.opsForValue().get("name"); System.err.println(name); Assert.assertNull(name); String justryDeng = "JustryDeng"; stringRedisTemplate.opsForValue().set("name", justryDeng, Duration.ofSeconds(3)); name = stringRedisTemplate.opsForValue().get("name"); System.err.println(name); Assert.assertEquals(justryDeng, name); TimeUnit.SECONDS.sleep(3); name = stringRedisTemplate.opsForValue().get("name"); System.err.println(name); Assert.assertNull(name); } }
-
输出
使用test-container提供集群redis:
-
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.redis.helper.ClientResources4Test; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.FixedHostPortGenericContainer; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; /** * redis集群环境支持 * * @author {@link JustryDeng} * @since 2020/11/13 16:14:18 */ @Slf4j @Testcontainers @Import(value = {ExcludedAllAutoConfiguration.class, ClientResources4Test.class, RedisAutoConfiguration.class}) @ContextConfiguration(initializers = RedisClusterEnvSupport.Initializer.class) public class RedisClusterEnvSupport implements RedisEnvSupport { /** 标准的docker镜像(即${镜像名}:${tag名}) */ private static final String DOCKER_IMAGE_NAME = "grokzen/redis-cluster:6.0.7"; /** * 集群最好用FixedHostPortGenericContainer, 主动避免端口冲突即可 */ @Container @SuppressWarnings("deprecation") public static GenericContainer<?> redisContainer = new FixedHostPortGenericContainer<>(DOCKER_IMAGE_NAME) .withFixedExposedPort(7000, 7000) .withFixedExposedPort(7001, 7001) .withFixedExposedPort(7002, 7002) .withFixedExposedPort(7003, 7003) .withFixedExposedPort(7004, 7004) .withFixedExposedPort(7005, 7005); /** * init application context * * @author {@link JustryDeng} * @since 2020/11/14 19:22:23 */ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) { String redisIpAddress = redisContainer.getContainerIpAddress(); String nodesInfo = redisIpAddress + ":" + 7000 + "," + redisIpAddress + ":" + 7001 + "," + redisIpAddress + ":" + 7002 + "," + redisIpAddress + ":" + 7003 + "," + redisIpAddress + ":" + 7004 + "," + redisIpAddress + ":" + 7005; log.info("spring.redis.cluster.nodes is [{}]", nodesInfo); System.setProperty("spring.redis.cluster.nodes", nodesInfo); } } }
-
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.redis.RedisClusterEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import javax.annotation.Resource; import java.time.Duration; import java.util.concurrent.TimeUnit; /** * 测试 * * @author {@link JustryDeng} * @since 2020/11/13 16:36:21 */ @Slf4j @SpringBootTest public class RedisClusterTest extends RedisClusterEnvSupport { @Resource StringRedisTemplate stringRedisTemplate; @Test void one() throws InterruptedException { String name = stringRedisTemplate.opsForValue().get("name"); System.err.println(name); Assert.assertNull(name); String justryDeng = "JustryDeng"; stringRedisTemplate.opsForValue().set("name", justryDeng, Duration.ofSeconds(3)); name = stringRedisTemplate.opsForValue().get("name"); System.err.println(name); Assert.assertEquals(justryDeng, name); TimeUnit.SECONDS.sleep(3); name = stringRedisTemplate.opsForValue().get("name"); System.err.println(name); Assert.assertNull(name); } }
-
输出
使用test-container提供MySQL:
-
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.utility.DockerImageName; /** * Mysql8环境支持 * * @author {@link JustryDeng} * @since 2020/11/17 14:14:43 */ @Slf4j @ContextConfiguration(initializers = Mysql8EnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class, DataSourceAutoConfiguration.class}) public class Mysql8EnvSupport implements MysqlEnvSupport{ /** 标准的docker镜像(即${镜像名}:${tag名}) */ private static final String DOCKER_IMAGE_NAME = "mysql:8.0.22"; /** 数据库 */ private static final String DATABASE = "mine_database"; /** 连接池类型 */ private static final Class<?> POOL_TYPE_CLASS = HikariDataSource.class; @ClassRule public static MySQLContainer<?> mySqlContainer = new MySQLContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME)) .withDatabaseName(DATABASE) // 初始化脚本 .withInitScript("mysql/init_mysql.sql") /// 配置文件 ///.withConfigurationOverride("mysql/config") ; /** * init application context * * @author {@link JustryDeng} * @since 2020/11/14 19:22:23 */ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) { // start mySqlContainer.start(); String jdbcUrl = mySqlContainer.getJdbcUrl(); int endIndex = jdbcUrl.indexOf("?"); String additionalSetting = "?characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false"; if (endIndex < 0) { jdbcUrl = jdbcUrl + additionalSetting; } else { jdbcUrl = jdbcUrl.substring(0, endIndex) + additionalSetting; } System.setProperty("spring.datasource.url", jdbcUrl); System.setProperty("spring.datasource.username", mySqlContainer.getUsername()); System.setProperty("spring.datasource.password", mySqlContainer.getPassword()); System.setProperty("spring.datasource.driver-class-name", mySqlContainer.getDriverClassName()); System.setProperty("spring.datasource.type", POOL_TYPE_CLASS.getName()); } } }
-
基类中涉及到的脚本的位置及内容为
-
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.mysql.Mysql8EnvSupport; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; import java.util.List; import java.util.Map; /** * 测试 * * @author {@link JustryDeng} * @since 2020/11/13 16:36:21 */ @Slf4j @SpringBootTest public class Mysql8Test extends Mysql8EnvSupport { @Resource TestMapper testMapper; @Test void one() { System.err.println(testMapper.count()); List<Map<String, Object>> x = testMapper.selectAll(); System.err.println(x); } @Mapper public interface TestMapper { @Select("select count(*) from employee") int count(); @Select("select * from employee") List<Map<String, Object>> selectAll(); } }
-
输出
使用test-container提供pgSQL:
-
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.utility.DockerImageName; /** * PostgreSql10环境支持 * * @author {@link JustryDeng} * @since 2020/11/17 21:14:29 */ @Slf4j @ContextConfiguration(initializers = PostgreSql10EnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class, DataSourceAutoConfiguration.class}) public class PostgreSql10EnvSupport implements PostgreSqlEnvSupport { /** 标准的docker镜像(即${镜像名}:${tag名}) */ private static final String DOCKER_IMAGE_NAME = "postgres:10.15"; /** 数据库 */ private static final String DATABASE = "mine_database"; /** 连接池类型 */ private static final Class<?> POOL_TYPE_CLASS = HikariDataSource.class; @ClassRule public static PostgreSQLContainer<?> pgSqlContainer = new PostgreSQLContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME)) .withDatabaseName(DATABASE) // 初始化脚本 .withInitScript("postgresql/init_postgresql.sql"); /** * init application context * * @author {@link JustryDeng} * @since 2020/11/14 19:22:23 */ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) { // start pgSqlContainer.start(); System.setProperty("spring.datasource.url", pgSqlContainer.getJdbcUrl()); System.setProperty("spring.datasource.username", pgSqlContainer.getUsername()); System.setProperty("spring.datasource.password", pgSqlContainer.getPassword()); System.setProperty("spring.datasource.driver-class-name", pgSqlContainer.getDriverClassName()); System.setProperty("spring.datasource.type", POOL_TYPE_CLASS.getName()); } } }
-
基类中涉及到的脚本的位置及内容为
-
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.postgresql.PostgreSql10EnvSupport; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; import java.util.List; import java.util.Map; /** * 测试 * * @author {@link JustryDeng} * @since 2020/11/13 16:36:21 */ @Slf4j @SpringBootTest public class PostgreSql10Test extends PostgreSql10EnvSupport { @Resource TestMapper testMapper; @Test void one() { System.err.println(testMapper.count()); System.err.println(testMapper.selectAll()); } @Mapper public interface TestMapper { @Select("select count(*) from employee") int count(); @Select("select * from employee") List<Map<String, Object>> selectAll(); } }
-
输出
使用test-container提供Kafka:
-
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.kafka.annotation.EnableKafka; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.KafkaContainer; import org.testcontainers.utility.DockerImageName; /** * 一个简单的kafka环境支持 * * @author {@link JustryDeng} * @since 2020/11/18 12:11:54 */ @Slf4j @EnableKafka @ContextConfiguration(initializers = KafkaSimpleEnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class, KafkaAutoConfiguration.class}) public class KafkaSimpleEnvSupport implements KafkaEnvSupport { /** 标准的docker镜像(即${镜像名}:${tag名}) */ private static final String DOCKER_IMAGE_NAME = "confluentinc/cp-kafka:5.4.3"; @ClassRule public static KafkaContainer kafkaContainer = new KafkaContainer(DockerImageName.parse(DOCKER_IMAGE_NAME)); /** * init application context * * @author {@link JustryDeng} * @since 2020/11/14 19:22:23 */ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) { // start kafkaContainer.start(); String bootstrapServers = kafkaContainer.getBootstrapServers(); System.setProperty("spring.kafka.bootstrap-servers", bootstrapServers); // 因为是测试环境, 这里用earliest, 以避免在没有提交offset情况下,用latest不会读取旧数据的问题 System.setProperty("spring.kafka.consumer.auto-offset-reset", "earliest"); } } }
-
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.kafka.KafkaSimpleEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.core.KafkaTemplate; import javax.annotation.Resource; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * 测试 * * @author {@link JustryDeng} * @since 2020/11/18 12:15:47 */ @Slf4j @SpringBootTest @Import(value = {KafkaSimpleTest.MyConsumer.class, KafkaSimpleTest.MyProducer.class}) public class KafkaSimpleTest extends KafkaSimpleEnvSupport { static final String TOPIC_NAME4TEST = "my-topic4test"; @Resource MyProducer myProducer; @Test void one() throws InterruptedException { // 生产消息 for (int i = 0; i < 10; i++) { myProducer.sendMessage("邓沙利文-" + i); } // sleep几秒,以便观察消费者是否消费消息 TimeUnit.SECONDS.sleep(3); Assert.assertTrue("消费消息失败(或消费消息超时)", MyConsumer.hasConsumedMsg); } /** * 生产者 */ @Slf4j public static class MyProducer { @Resource private KafkaTemplate<String, String> kafkaTemplate; public void sendMessage(String message) { kafkaTemplate.send(TOPIC_NAME4TEST, "key-" + UUID.randomUUID().toString(), message); } } /** * 消费者 */ @SuppressWarnings("unused") @Slf4j public static class MyConsumer { /** 是否已经消费了消息 */ static boolean hasConsumedMsg = false; @KafkaListener(topics = TOPIC_NAME4TEST, groupId = "group-b") public void consumerOne(String message) { log.info("consumerOne消费了消息 [{}]", message); hasConsumedMsg = true; } } }
-
输出
使用test-container提供RabbitMQ:
-
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.RabbitMQContainer; /** * 一个简单的RabbitMQ环境支持 * * @author {@link JustryDeng} * @since 2020/11/20 12:49:45 */ @Slf4j @ContextConfiguration(initializers = RabbitMqSimpleEnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class}) public class RabbitMqSimpleEnvSupport { /** 标准的docker镜像(即${镜像名}:${tag名}) */ private static final String DOCKER_IMAGE_NAME = "rabbitmq:management-alpine"; @ClassRule public static RabbitMQContainer rabbitMqContainer = new RabbitMQContainer(DOCKER_IMAGE_NAME) .withAdminPassword("ds123"); /** * init application context * * @author {@link JustryDeng} * @since 2020/11/14 19:22:23 */ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) { // start rabbitMqContainer.start(); String host = rabbitMqContainer.getHost(); log.info("spring.rabbitmq.host={}", host); System.setProperty("spring.rabbitmq.host", host); Integer amqpPort = rabbitMqContainer.getAmqpPort(); log.info("spring.rabbitmq.port={}", amqpPort); System.setProperty("spring.rabbitmq.port", String.valueOf(amqpPort)); String adminUsername = rabbitMqContainer.getAdminUsername(); log.info("spring.rabbitmq.username={}", adminUsername); System.setProperty("spring.rabbitmq.username", adminUsername); String adminPassword = rabbitMqContainer.getAdminPassword(); log.info("spring.rabbitmq.password={}", adminPassword); System.setProperty("spring.rabbitmq.password", adminPassword); } } }
-
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.rabbitmq.RabbitMqSimpleEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; import static com.niantou.testcontainer.rabbitmq.test.RabbitMqSimpleTest.MyConfig.MY_EXCHANGE_NAME; import static com.niantou.testcontainer.rabbitmq.test.RabbitMqSimpleTest.MyConfig.QUEUE_NAME; import static com.niantou.testcontainer.rabbitmq.test.RabbitMqSimpleTest.MyConfig.ROUTING_KEY; /** * 测试 * * @author {@link JustryDeng} * @since 2020/11/18 12:15:47 */ @Slf4j @SpringBootTest @Import(value = {RabbitMqSimpleTest.MyConsumer.class, RabbitMqSimpleTest.MyProducer.class, RabbitMqSimpleTest.MyConfig.class}) public class RabbitMqSimpleTest extends RabbitMqSimpleEnvSupport { @Resource MyProducer myProducer; @Test void one() throws InterruptedException { // 生产消息 for (int i = 0; i < 10; i++) { myProducer.sendMessage("邓沙利文-" + i); } // sleep几秒,以便观察消费者是否消费消息 TimeUnit.SECONDS.sleep(3); Assert.assertTrue("消费消息失败(或消费消息超时)", MyConsumer.hasConsumedMsg); } /** * 配置类 */ @Slf4j public static class MyConfig { static final String ROUTING_KEY = "myRoutingKey"; static final String QUEUE_NAME = "my-queue"; static final String MY_EXCHANGE_NAME = "my-direct-exchange"; @Bean public Queue myQueue() { return new Queue(QUEUE_NAME); } @Bean public DirectExchange myDirectExchange() { return new DirectExchange(MY_EXCHANGE_NAME); } @Bean public Binding myBinding(Queue myQueue, DirectExchange myDirectExchange) { return BindingBuilder.bind(myQueue).to(myDirectExchange).with(ROUTING_KEY); } } /** * 生产者 */ @Slf4j public static class MyProducer { @Resource private AmqpTemplate amqpTemplate; public void sendMessage(String message) { amqpTemplate.convertAndSend(MY_EXCHANGE_NAME, ROUTING_KEY, message); } } /** * 消费者 */ @Slf4j public static class MyConsumer { /** 是否已经消费了消息 */ static boolean hasConsumedMsg = false; @SuppressWarnings("unused") @RabbitListener(queues = QUEUE_NAME) public void consumerOne(String message) { log.info("consumerOne消费了消息 [{}]", message); hasConsumedMsg = true; } } }
-
输出
test-containers,初步学习完毕!
^_^ 如有不当之处,欢迎指正
^_^ 参考链接
https://www.testcontainers.org/
^_^ 测试代码托管链接
https://github.com/JustryDeng…test-containers
^_^ 本文已经被收录进《程序员成长笔记》 ,笔者JustryDeng
更多推荐
所有评论(0)