GH-342 - Allow disabling event externalization.

We now expose spring.modulith.events.externalization.enabled that can be set to false to disable the event externalization completely. Useful in test cases, for example.
This commit is contained in:
Oliver Drotbohm
2023-10-23 12:22:42 +02:00
parent 69fd64dbf7
commit 576b8f5074
11 changed files with 235 additions and 1 deletions

View File

@@ -23,6 +23,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -40,6 +41,9 @@ import org.springframework.modulith.events.support.DelegatingEventExternalizer;
@AutoConfiguration
@AutoConfigureAfter(EventExternalizationAutoConfiguration.class)
@ConditionalOnClass(RabbitTemplate.class)
@ConditionalOnProperty(name = "spring.modulith.events.externalization.enabled",
havingValue = "true",
matchIfMissing = true)
class RabbitEventExternalizerConfiguration {
private static final Logger logger = LoggerFactory.getLogger(RabbitEventExternalizerConfiguration.class);

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.modulith.events.amqp;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitMessageOperations;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.modulith.events.EventExternalizationConfiguration;
import org.springframework.modulith.events.support.DelegatingEventExternalizer;
/**
* Integration tests for {@link RabbitEventExternalizerConfiguration}.
*
* @author Oliver Drotbohm
* @since 1.1
*/
class RabbitEventExternalizerConfigurationIntegrationTests {
@Test // GH-342
void registersExternalizerByDefault() {
basicSetup()
.run(ctxt -> {
assertThat(ctxt).hasSingleBean(DelegatingEventExternalizer.class);
});
}
@Test // GH-342
void disablesExternalizationIfConfigured() {
basicSetup()
.withPropertyValues("spring.modulith.events.externalization.enabled=false")
.run(ctxt -> {
assertThat(ctxt).doesNotHaveBean(DelegatingEventExternalizer.class);
});
}
private ApplicationContextRunner basicSetup() {
return new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(RabbitEventExternalizerConfiguration.class))
.withBean(EventExternalizationConfiguration.class, () -> EventExternalizationConfiguration.disabled())
.withBean(RabbitMessageOperations.class, () -> mock(RabbitMessageOperations.class));
}
}

View File

@@ -77,6 +77,15 @@ public interface EventExternalizationConfiguration {
return new Selector();
}
/**
* Disables event externalization by not matching any events at all.
*
* @return will never be {@literal null}.
*/
public static EventExternalizationConfiguration disabled() {
return externalizing().select(__ -> false).build();
}
/**
* A {@link Predicate} to select all events annotated as to be externalized. The currently supported annotations are:
* <ul>

View File

@@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
@@ -30,7 +31,6 @@ import org.springframework.context.event.EventListenerFactory;
import org.springframework.core.Ordered;
import org.springframework.modulith.events.EventExternalizationConfiguration;
import org.springframework.modulith.events.core.ConditionalEventListener;
import org.springframework.modulith.events.support.PersistentApplicationEventMulticaster;
import org.springframework.transaction.event.TransactionalApplicationListenerMethodAdapter;
import org.springframework.transaction.event.TransactionalEventListenerFactory;
@@ -40,6 +40,9 @@ import org.springframework.transaction.event.TransactionalEventListenerFactory;
* @author Oliver Drotbohm
* @since 1.1
*/
@ConditionalOnProperty(name = "spring.modulith.events.externalization.enabled",
havingValue = "true",
matchIfMissing = true)
@AutoConfiguration
@AutoConfigureAfter(EventPublicationConfiguration.class)
public class EventExternalizationAutoConfiguration {

View File

@@ -11,6 +11,12 @@
"type": "java.lang.boolean",
"description": "Whether to republish outstanding event publications on restarts of the application.",
"defaultValue": "false"
},
{
"name": "spring.modulith.events.externalization.enabled",
"type": "java.lang.boolean",
"description": "Whether to enable event externalization.",
"defaultValue": "true"
}
]
}

View File

@@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsOperations;
import org.springframework.modulith.events.EventExternalizationConfiguration;
@@ -36,6 +37,9 @@ import org.springframework.modulith.events.support.DelegatingEventExternalizer;
@AutoConfiguration
@AutoConfigureAfter(EventExternalizationAutoConfiguration.class)
@ConditionalOnClass(JmsOperations.class)
@ConditionalOnProperty(name = "spring.modulith.events.externalization.enabled",
havingValue = "true",
matchIfMissing = true)
class JmsEventExternalizerConfiguration {
private static final Logger logger = LoggerFactory.getLogger(JmsEventExternalizerConfiguration.class);

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.modulith.events.jms;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.jms.core.JmsOperations;
import org.springframework.modulith.events.EventExternalizationConfiguration;
import org.springframework.modulith.events.core.EventSerializer;
import org.springframework.modulith.events.support.DelegatingEventExternalizer;
/**
* Integration tests for {@link JmsEventExternalizerConfiguration}.
*
* @author Oliver Drotbohm
* @since 1.1
*/
class JmsEventExternalizerConfigurationIntegrationTests {
@Test // GH-342
void registersExternalizerByDefault() {
basicSetup()
.run(ctxt -> {
assertThat(ctxt).hasSingleBean(DelegatingEventExternalizer.class);
});
}
@Test // GH-342
void disablesExternalizationIfConfigured() {
basicSetup()
.withPropertyValues("spring.modulith.events.externalization.enabled=false")
.run(ctxt -> {
assertThat(ctxt).doesNotHaveBean(DelegatingEventExternalizer.class);
});
}
private ApplicationContextRunner basicSetup() {
return new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(JmsEventExternalizerConfiguration.class))
.withBean(EventExternalizationConfiguration.class, () -> EventExternalizationConfiguration.disabled())
.withBean(EventSerializer.class, () -> mock(EventSerializer.class))
.withBean(JmsOperations.class, () -> mock(JmsOperations.class));
}
}

View File

@@ -40,6 +40,14 @@
<optional>true</optional>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -21,6 +21,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -37,9 +38,13 @@ import org.springframework.modulith.events.support.DelegatingEventExternalizer;
* @author Oliver Drotbohm
* @since 1.1
*/
@AutoConfiguration
@AutoConfigureAfter(EventExternalizationAutoConfiguration.class)
@ConditionalOnClass(KafkaTemplate.class)
@ConditionalOnProperty(name = "spring.modulith.events.externalization.enabled",
havingValue = "true",
matchIfMissing = true)
class KafkaEventExternalizerConfiguration {
private static final Logger logger = LoggerFactory.getLogger(KafkaEventExternalizerConfiguration.class);

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.modulith.events.kafka;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.kafka.core.KafkaOperations;
import org.springframework.modulith.events.EventExternalizationConfiguration;
import org.springframework.modulith.events.support.DelegatingEventExternalizer;
/**
* Integration tests for {@link KafkaEventExternalizerConfiguration}.
*
* @author Oliver Drotbohm
* @since 1.1
*/
class KafkaEventExternalizerConfigurationIntegrationTests {
@Test // GH-342
void registersExternalizerByDefault() {
basicSetup()
.run(ctxt -> {
assertThat(ctxt).hasSingleBean(DelegatingEventExternalizer.class);
});
}
@Test // GH-342
void disablesExternalizationIfConfigured() {
basicSetup()
.withPropertyValues("spring.modulith.events.externalization.enabled=false")
.run(ctxt -> {
assertThat(ctxt).doesNotHaveBean(DelegatingEventExternalizer.class);
});
}
private ApplicationContextRunner basicSetup() {
return new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(KafkaEventExternalizerConfiguration.class))
.withBean(EventExternalizationConfiguration.class, () -> EventExternalizationConfiguration.disabled())
.withBean(KafkaOperations.class, () -> mock(KafkaOperations.class));
}
}

View File

@@ -13,6 +13,10 @@
|`true`
|Whether to configure defaults for the async processing termination, namely to wait for task completion for 2 seconds. See `TaskExecutionProperties` for details.
|`spring.modulith.events.externalization.enabled`
|`true`
|Whether to enable event externalization.
|`spring.modulith.events.jdbc.schema-initialization.enabled`
|`false`
|Whether to initialize the JDBC event publication schema.