Koneksi layanan adalah koneksi ke layanan jarak jauh apa pun. Konfigurasi otomatis Spring Boot dapat menggunakan detail koneksi layanan dan menggunakannya untuk membuat koneksi ke layanan jarak jauh. Saat melakukannya, detail koneksi lebih diutamakan daripada properti konfigurasi terkait koneksi.
Saat Anda menggunakan Docker compose, Anda dapat membuat detail koneksi secara otomatis untuk layanan yang berjalan dalam kontainer dengan menambahkan @SpringBootTest anotasi dengan spring.docker.compose.file properti di kelas pengujian.
Tabel berikut ini menyediakan informasi tentang kelas pabrik detail koneksi yang didukung dalam spring-cloud-azure-docker-compose JAR:
<properties>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-storage-blob</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-storage-queue</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-eventhubs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-eventhubs</artifactId>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-stream-binder-eventhubs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-messaging-azure-servicebus</artifactId>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-stream-binder-servicebus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-autoconfigure</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
storage-compose.yaml:
services:
storage:
image: mcr.microsoft.com/azure-storage/azurite:latest
ports:
- '10000'
- '10001'
- '10002'
command: azurite -l /data --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck
storage-compose.yaml:
services:
storage:
image: mcr.microsoft.com/azure-storage/azurite:latest
ports:
- '10000'
- '10001'
- '10002'
command: azurite -l /data --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck
eventhubs-compose.yaml:
services:
eventhubs:
image: mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest
pull_policy: always
volumes:
# Mount the emulator configuration to the path expected by the emulator image
- "./Config.json:/Eventhubs_Emulator/ConfigFiles/Config.json"
ports:
- "5672"
environment:
# Event Hubs emulator requires external blob/metadata storage provided by azurite
BLOB_SERVER: azurite
METADATA_SERVER: azurite
ACCEPT_EULA: Y
depends_on:
- azurite
networks:
eh-emulator:
aliases:
- "eh-emulator"
azurite:
image: "mcr.microsoft.com/azure-storage/azurite:latest"
ports:
- "10000"
- "10001"
- "10002"
networks:
eh-emulator:
aliases:
- "azurite"
networks:
eh-emulator:
Config.json:
{
"UserConfig": {
"NamespaceConfig": [
{
"Type": "EventHub",
"Name": "emulatorns1",
"Entities": [
{
"Name": "eh1",
"PartitionCount": "2",
"ConsumerGroups": []
}
]
}
],
"LoggingConfig": {
"Type": "File"
}
}
}
eventhubs-compose.yaml:
services:
eventhubs:
image: mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest
pull_policy: always
volumes:
# Mount the emulator configuration to the path expected by the emulator image
- "./Config.json:/Eventhubs_Emulator/ConfigFiles/Config.json"
ports:
- "5672"
environment:
# Event Hubs emulator requires external blob/metadata storage provided by azurite
BLOB_SERVER: azurite
METADATA_SERVER: azurite
ACCEPT_EULA: Y
depends_on:
- azurite
networks:
eh-emulator:
aliases:
- "eh-emulator"
azurite:
image: "mcr.microsoft.com/azure-storage/azurite:latest"
command: "azurite -l /data --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck"
ports:
- "10000"
- "10001"
- "10002"
networks:
eh-emulator:
aliases:
- "azurite"
networks:
eh-emulator:
Config.json:
{
"UserConfig": {
"NamespaceConfig": [
{
"Type": "EventHub",
"Name": "emulatorns1",
"Entities": [
{
"Name": "eh1",
"PartitionCount": "2",
"ConsumerGroups": []
}
]
}
],
"LoggingConfig": {
"Type": "File"
}
}
}
servicebus-compose.yaml:
services:
servicebus:
image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
pull_policy: always
volumes:
- "./Config.json:/ServiceBus_Emulator/ConfigFiles/Config.json"
ports:
- "5672"
environment:
SQL_SERVER: sqledge
MSSQL_SA_PASSWORD: A_Str0ng_Required_Password
ACCEPT_EULA: Y
depends_on:
- sqledge
networks:
sb-emulator:
aliases:
- "sb-emulator"
sqledge:
image: "mcr.microsoft.com/azure-sql-edge:latest"
networks:
sb-emulator:
aliases:
- "sqledge"
environment:
ACCEPT_EULA: Y
MSSQL_SA_PASSWORD: A_Str0ng_Required_Password
networks:
sb-emulator:
Config.json:
{
"UserConfig": {
"Namespaces": [
{
"Name": "sbemulatorns",
"Queues": [
{
"Name": "queue.1",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"DuplicateDetectionHistoryTimeWindow": "PT20S",
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"RequiresDuplicateDetection": false,
"RequiresSession": false
}
}
],
"Topics": [
{
"Name": "topic.1",
"Properties": {
"DefaultMessageTimeToLive": "PT1H",
"DuplicateDetectionHistoryTimeWindow": "PT20S",
"RequiresDuplicateDetection": false
},
"Subscriptions": [
{
"Name": "subscription.1",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"RequiresSession": false
},
"Rules": [
{
"Name": "app-prop-filter-1",
"Properties": {
"FilterType": "Correlation",
"CorrelationFilter": {
"ContentType": "application/text",
"CorrelationId": "id1",
"Label": "subject1",
"MessageId": "msgid1",
"ReplyTo": "someQueue",
"ReplyToSessionId": "sessionId",
"SessionId": "session1",
"To": "xyz"
}
}
}
]
},
{
"Name": "subscription.2",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"RequiresSession": false
},
"Rules": [
{
"Name": "user-prop-filter-1",
"Properties": {
"FilterType": "Correlation",
"CorrelationFilter": {
"Properties": {
"prop3": "value3"
}
}
}
}
]
},
{
"Name": "subscription.3",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"RequiresSession": false
}
}
]
}
]
}
],
"Logging": {
"Type": "File"
}
}
}
servicebus-compose.yaml:
services:
servicebus:
image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
pull_policy: always
volumes:
- "./Config.json:/ServiceBus_Emulator/ConfigFiles/Config.json"
ports:
- "5672"
environment:
SQL_SERVER: sqledge
MSSQL_SA_PASSWORD: A_Str0ng_Required_Password
ACCEPT_EULA: Y
depends_on:
- sqledge
networks:
sb-emulator:
aliases:
- "sb-emulator"
sqledge:
image: "mcr.microsoft.com/azure-sql-edge:latest"
networks:
sb-emulator:
aliases:
- "sqledge"
environment:
ACCEPT_EULA: Y
MSSQL_SA_PASSWORD: A_Str0ng_Required_Password
networks:
sb-emulator:
Config.json:
{
"UserConfig": {
"Namespaces": [
{
"Name": "sbemulatorns",
"Queues": [
{
"Name": "queue.1",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"DuplicateDetectionHistoryTimeWindow": "PT20S",
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"RequiresDuplicateDetection": false,
"RequiresSession": false
}
}
],
"Topics": [
{
"Name": "topic.1",
"Properties": {
"DefaultMessageTimeToLive": "PT1H",
"DuplicateDetectionHistoryTimeWindow": "PT20S",
"RequiresDuplicateDetection": false
},
"Subscriptions": [
{
"Name": "subscription.1",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"RequiresSession": false
},
"Rules": [
{
"Name": "app-prop-filter-1",
"Properties": {
"FilterType": "Correlation",
"CorrelationFilter": {
"ContentType": "application/text",
"CorrelationId": "id1",
"Label": "subject1",
"MessageId": "msgid1",
"ReplyTo": "someQueue",
"ReplyToSessionId": "sessionId",
"SessionId": "session1",
"To": "xyz"
}
}
}
]
},
{
"Name": "subscription.2",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"RequiresSession": false
},
"Rules": [
{
"Name": "user-prop-filter-1",
"Properties": {
"FilterType": "Correlation",
"CorrelationFilter": {
"Properties": {
"prop3": "value3"
}
}
}
}
]
},
{
"Name": "subscription.3",
"Properties": {
"DeadLetteringOnMessageExpiration": false,
"DefaultMessageTimeToLive": "PT1H",
"LockDuration": "PT1M",
"MaxDeliveryCount": 10,
"ForwardDeadLetteredMessagesTo": "",
"ForwardTo": "",
"RequiresSession": false
}
}
]
}
]
}
],
"Logging": {
"Type": "File"
}
}
}
@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:storage-compose.yaml",
"spring.docker.compose.stop.command=down"
})
public class AzureBlobResourceDockerComposeTest {
@Value("azure-blob://testcontainers/message.txt")
private Resource blobFile;
@Test
void blobResourceShouldWriteAndReadContent() throws IOException {
String originalContent = "Hello World!";
try (OutputStream os = ((WritableResource) this.blobFile).getOutputStream()) {
os.write(originalContent.getBytes());
}
String resultContent = StreamUtils.copyToString(this.blobFile.getInputStream(), Charset.defaultCharset());
assertThat(resultContent).isEqualTo(originalContent);
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureStorageBlobAutoConfiguration.class,
AzureStorageBlobResourceAutoConfiguration.class})
static class Config {
}
}
Dengan spring.docker.compose.file, konfigurasi ini memungkinkan kacang terkait di aplikasi untuk berkomunikasi dengan Blob Storage yang berjalan di dalam kontainer Docker. Tindakan ini dilakukan dengan secara otomatis menentukan AzureStorageBlobConnectionDetails kacang, yang kemudian digunakan oleh konfigurasi otomatis Blob Storage, mengambil alih properti konfigurasi terkait koneksi apa pun.
@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:storage-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.cloud.azure.storage.queue.queue-name=devstoreaccount1/tc-queue"
})
class StorageQueueDockerComposeTest {
@Autowired
private QueueClient queueClient;
@Test
void queueClientShouldSendAndReceiveMessage() {
String message = "Hello World!";
this.queueClient.create();
this.queueClient.sendMessage(message);
var messageItem = this.queueClient.receiveMessage();
assertThat(messageItem.getBody().toString()).isEqualTo(message);
}
@Configuration
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureStorageQueueAutoConfiguration.class})
static class Config {
}
}
Dengan spring.docker.compose.file, konfigurasi ini memungkinkan kacang terkait di aplikasi untuk berkomunikasi dengan Queue Storage yang berjalan di dalam kontainer Docker. Tindakan ini dilakukan dengan secara otomatis menentukan AzureStorageQueueConnectionDetails kacang, yang kemudian digunakan oleh konfigurasi otomatis Queue Storage, mengambil alih properti konfigurasi terkait koneksi apa pun.
@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:eventhubs-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.docker.compose.readiness.timeout=PT5M",
"spring.cloud.azure.eventhubs.event-hub-name=eh1",
"spring.cloud.azure.eventhubs.producer.event-hub-name=eh1"
})
class EventHubsDockerComposeTest {
@Autowired
private AzureEventHubsConnectionDetails connectionDetails;
@Autowired
private EventHubProducerClient producerClient;
@Test
void connectionDetailsShouldBeProvidedByFactory() {
assertThat(connectionDetails).isNotNull();
assertThat(connectionDetails.getConnectionString())
.isNotBlank()
.startsWith("Endpoint=sb://");
}
@Test
void producerClientCanSendMessage() {
// Wait for Event Hubs emulator to be fully ready and event hub entity to be available
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
EventData event = new EventData("Hello World!");
this.producerClient.send(Collections.singletonList(event));
});
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureEventHubsAutoConfiguration.class})
static class Config {
}
}
Dengan spring.docker.compose.file, konfigurasi ini memungkinkan kacang terkait di aplikasi untuk berkomunikasi dengan Azure Event Hubs yang berjalan di dalam kontainer Docker. Tindakan ini dilakukan dengan secara otomatis menentukan AzureEventHubsConnectionDetails kacang, yang kemudian digunakan oleh konfigurasi otomatis Azure Event Hubs, mengambil alih properti konfigurasi terkait koneksi apa pun.
@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:eventhubs-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.docker.compose.readiness.timeout=PT5M",
"spring.cloud.function.definition=consume;supply",
"spring.cloud.stream.bindings.consume-in-0.destination=eh1",
"spring.cloud.stream.bindings.consume-in-0.group=$Default",
"spring.cloud.stream.bindings.supply-out-0.destination=eh1",
"spring.cloud.stream.eventhubs.bindings.consume-in-0.consumer.checkpoint.mode=MANUAL",
"spring.cloud.stream.poller.fixed-delay=1000",
"spring.cloud.stream.poller.initial-delay=0"
})
class EventHubsDockerComposeTest {
private static final Logger LOGGER = LoggerFactory.getLogger(EventHubsDockerComposeTest.class);
private static final Set<String> RECEIVED_MESSAGES = ConcurrentHashMap.newKeySet();
private static final AtomicInteger MESSAGE_SEQUENCE = new AtomicInteger(0);
@Test
void supplierAndConsumerShouldWorkThroughEventHub() {
waitAtMost(Duration.ofSeconds(120))
.pollDelay(Duration.ofSeconds(2))
.pollInterval(Duration.ofSeconds(2))
.untilAsserted(() -> {
assertThat(RECEIVED_MESSAGES).isNotEmpty();
LOGGER.info("✓ Test passed - Consumer received {} message(s)", RECEIVED_MESSAGES.size());
});
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureEventHubsAutoConfiguration.class,
AzureEventHubsMessagingAutoConfiguration.class})
static class Config {
private static final String CHECKPOINT_CONTAINER_NAME = "eventhubs-checkpoint";
@Bean
public BlobCheckpointStore blobCheckpointStore(AzureStorageBlobConnectionDetails connectionDetails) {
BlobServiceAsyncClient blobServiceAsyncClient = new BlobServiceClientBuilder()
.connectionString(connectionDetails.getConnectionString())
.buildAsyncClient();
BlobContainerAsyncClient containerAsyncClient = blobServiceAsyncClient
.getBlobContainerAsyncClient(CHECKPOINT_CONTAINER_NAME);
if (Boolean.FALSE.equals(containerAsyncClient.exists().block(Duration.ofSeconds(3)))) {
containerAsyncClient.create().block(Duration.ofSeconds(3));
}
return new BlobCheckpointStore(containerAsyncClient);
}
@Bean
public Supplier<Message<String>> supply() {
return () -> {
int sequence = MESSAGE_SEQUENCE.getAndIncrement();
String payload = "Hello world, " + sequence;
LOGGER.info("[Supplier] Invoked - message sequence: {}", sequence);
return MessageBuilder.withPayload(payload).build();
};
}
@Bean
public Consumer<Message<String>> consume() {
return message -> {
String payload = message.getPayload();
RECEIVED_MESSAGES.add(payload);
LOGGER.info("[Consumer] Received message: {}", payload);
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
if (checkpointer != null) {
checkpointer.success()
.doOnSuccess(s -> LOGGER.info("[Consumer] Message checkpointed"))
.doOnError(e -> LOGGER.error("[Consumer] Checkpoint failed", e))
.block();
}
};
}
}
}
Dengan spring.docker.compose.file, konfigurasi ini memungkinkan kacang terkait di aplikasi untuk berkomunikasi dengan Azure Event Hubs yang berjalan di dalam kontainer Docker. Tindakan ini dilakukan dengan secara otomatis menentukan AzureEventHubsConnectionDetails kacang, yang kemudian digunakan oleh konfigurasi otomatis Azure Event Hubs, mengambil alih properti konfigurasi terkait koneksi apa pun.
@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:servicebus-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.docker.compose.readiness.timeout=PT5M",
"spring.cloud.azure.servicebus.namespace=sbemulatorns",
"spring.cloud.azure.servicebus.entity-name=queue.1",
"spring.cloud.azure.servicebus.entity-type=queue",
"spring.cloud.azure.servicebus.producer.entity-name=queue.1",
"spring.cloud.azure.servicebus.producer.entity-type=queue",
"spring.cloud.azure.servicebus.processor.entity-name=queue.1",
"spring.cloud.azure.servicebus.processor.entity-type=queue"
})
class ServiceBusDockerComposeTest {
@Autowired
private AzureServiceBusConnectionDetails connectionDetails;
@Autowired
private ServiceBusSenderClient senderClient;
@Autowired
private ServiceBusTemplate serviceBusTemplate;
@Test
void connectionDetailsShouldBeProvidedByFactory() {
assertThat(connectionDetails).isNotNull();
assertThat(connectionDetails.getConnectionString())
.isNotBlank()
.startsWith("Endpoint=sb://");
}
@Test
void senderClientCanSendMessage() {
// Wait for Service Bus emulator to be fully ready and queue entity to be available
// The emulator depends on SQL Edge and needs time to initialize the messaging entities
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
this.senderClient.sendMessage(new ServiceBusMessage("Hello World!"));
});
waitAtMost(Duration.ofSeconds(30)).pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
assertThat(Config.MESSAGES).contains("Hello World!");
});
}
@Test
void serviceBusTemplateCanSendMessage() {
// Wait for Service Bus emulator to be fully ready and queue entity to be available
// The emulator depends on SQL Edge and needs time to initialize the messaging entities
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
this.serviceBusTemplate.sendAsync("queue.1",
MessageBuilder.withPayload("Hello from ServiceBusTemplate!").build()).block(Duration.ofSeconds(10));
});
waitAtMost(Duration.ofSeconds(30)).pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
assertThat(Config.MESSAGES).contains("Hello from ServiceBusTemplate!");
});
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureServiceBusAutoConfiguration.class,
AzureServiceBusMessagingAutoConfiguration.class})
static class Config {
private static final Set<String> MESSAGES = ConcurrentHashMap.newKeySet();
@Bean
ServiceBusRecordMessageListener processMessage() {
return context -> {
MESSAGES.add(context.getMessage().getBody().toString());
};
}
@Bean
ServiceBusErrorHandler errorHandler() {
// No-op error handler for tests: acknowledge errors without affecting test execution.
return (context) -> {
};
}
}
}
Dengan spring.docker.compose.file, konfigurasi ini memungkinkan biji terkait di aplikasi untuk berkomunikasi dengan Service Bus yang berjalan di dalam kontainer Docker. Tindakan ini dilakukan dengan secara otomatis menentukan AzureServiceBusConnectionDetails kacang, yang kemudian digunakan oleh konfigurasi otomatis Azure Service Bus, mengambil alih properti konfigurasi terkait koneksi apa pun.
@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:servicebus-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.cloud.function.definition=consume;supply",
"spring.cloud.stream.bindings.consume-in-0.destination=queue.1",
"spring.cloud.stream.bindings.supply-out-0.destination=queue.1",
"spring.cloud.stream.servicebus.bindings.consume-in-0.consumer.auto-complete=false",
"spring.cloud.stream.servicebus.bindings.supply-out-0.producer.entity-type=queue",
"spring.cloud.stream.poller.fixed-delay=1000",
"spring.cloud.stream.poller.initial-delay=0"
})
class ServiceBusDockerComposeTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceBusDockerComposeTest.class);
private static final Set<String> RECEIVED_MESSAGES = ConcurrentHashMap.newKeySet();
private static final AtomicInteger MESSAGE_SEQUENCE = new AtomicInteger(0);
@Test
void supplierAndConsumerShouldWorkThroughServiceBusQueue() {
waitAtMost(Duration.ofSeconds(60))
.pollDelay(Duration.ofSeconds(2))
.untilAsserted(() -> {
assertThat(RECEIVED_MESSAGES).isNotEmpty();
LOGGER.info("✓ Test passed - Consumer received {} message(s)", RECEIVED_MESSAGES.size());
});
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureServiceBusAutoConfiguration.class,
AzureServiceBusMessagingAutoConfiguration.class})
static class Config {
@Bean
public Supplier<Message<String>> supply() {
return () -> {
int sequence = MESSAGE_SEQUENCE.getAndIncrement();
String payload = "Hello world, " + sequence;
LOGGER.info("[Supplier] Invoked - message sequence: {}", sequence);
return MessageBuilder.withPayload(payload).build();
};
}
@Bean
public Consumer<Message<String>> consume() {
return message -> {
String payload = message.getPayload();
RECEIVED_MESSAGES.add(payload);
LOGGER.info("[Consumer] Received message: {}", payload);
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
if (checkpointer != null) {
checkpointer.success()
.doOnSuccess(s -> LOGGER.info("[Consumer] Message checkpointed"))
.doOnError(e -> LOGGER.error("[Consumer] Checkpoint failed", e))
.block();
}
};
}
}
}
Dengan spring.docker.compose.file, konfigurasi ini memungkinkan biji terkait di aplikasi untuk berkomunikasi dengan Service Bus yang berjalan di dalam kontainer Docker. Tindakan ini dilakukan dengan secara otomatis menentukan AzureServiceBusConnectionDetails kacang, yang kemudian digunakan oleh konfigurasi otomatis Azure Service Bus, mengambil alih properti konfigurasi terkait koneksi apa pun.