diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastServerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastServerConfiguration.java index 63fe94612e7..98ce41e1083 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastServerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastServerConfiguration.java @@ -25,8 +25,12 @@ import com.hazelcast.config.YamlConfigBuilder; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.spring.context.SpringManagedContext; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -60,10 +64,14 @@ class HazelcastServerConfiguration { static class HazelcastServerConfigFileConfiguration { @Bean - HazelcastInstance hazelcastInstance(HazelcastProperties properties, ResourceLoader resourceLoader) + HazelcastInstance hazelcastInstance(HazelcastProperties properties, ResourceLoader resourceLoader, + ObjectProvider customizerProvider) throws IOException { Resource configLocation = properties.resolveConfigLocation(); Config config = (configLocation != null) ? loadConfig(configLocation) : Config.load(); + customizerProvider.ifAvailable(c -> { + c.customize(config); + }); config.setClassLoader(resourceLoader.getClassLoader()); return getHazelcastInstance(config); } @@ -93,7 +101,6 @@ class HazelcastServerConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnSingleCandidate(Config.class) static class HazelcastServerConfigConfiguration { - @Bean HazelcastInstance hazelcastInstance(Config config) { return getHazelcastInstance(config); @@ -101,6 +108,29 @@ class HazelcastServerConfiguration { } + @FunctionalInterface + private interface ConfigurationCustomizer { + void customize(Config configuration); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(name = "com.hazelcast.spring.context.SpringManagedContext") + static class HazelcastConfigCustomizerConfiguration { + private final ApplicationContext applicationContext; + + public HazelcastConfigCustomizerConfiguration(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public ConfigurationCustomizer springManagedContextConfigurationCustomizer() { + return configuration -> { + SpringManagedContext springManagedContext = new SpringManagedContext(applicationContext); + configuration.setManagedContext(springManagedContext); + }; + } + } + /** * {@link HazelcastConfigResourceCondition} that checks if the * {@code spring.hazelcast.config} configuration key is defined. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java index 3856dc99416..192837198c0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java @@ -22,14 +22,21 @@ import com.hazelcast.config.Config; import com.hazelcast.config.QueueConfig; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.EntryProcessor; +import com.hazelcast.map.IMap; +import com.hazelcast.spring.context.SpringAware; +import com.hazelcast.spring.context.SpringManagedContext; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.testsupport.classpath.ClassPathExclusions; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @@ -164,6 +171,55 @@ class HazelcastAutoConfigurationServerTests { }); } + @Test + void defaultConfigFile_injectManagedContext() { + this.contextRunner.run((context) -> { + HazelcastInstance hz = context.getBean(HazelcastInstance.class); + IMap map = hz.getMap("myMap"); + boolean contextInjected = map.executeOnKey(42, new SpringAwareEntryProcessor<>()); + assertThat(contextInjected).isEqualTo(true); + }); + } + + @Test + void defaultConfigFile_injectManagedContext_SpringHazelcastModuleNotAvailable() { + this.contextRunner + .withClassLoader(new FilteredClassLoader(SpringManagedContext.class)) + .run((context) -> { + HazelcastInstance hz = context.getBean(HazelcastInstance.class); + IMap map = hz.getMap("myMap"); + boolean contextInjected = map.executeOnKey(42, new SpringAwareEntryProcessor<>()); + assertThat(contextInjected).isEqualTo(false); + }); + } + + @Test + void explicitConfigFile_injectManagedContext() { + this.contextRunner + .withSystemProperties(HazelcastServerConfiguration.CONFIG_SYSTEM_PROPERTY + + "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.yaml") + .run((context) -> { + HazelcastInstance hz = context.getBean(HazelcastInstance.class); + IMap map = hz.getMap("myMap"); + boolean contextInjected = map.executeOnKey(42, new SpringAwareEntryProcessor<>()); + assertThat(contextInjected).isEqualTo(true); + }); + } + + @Test + void explicitConfigFile_injectManagedContext_SpringHazelcastModuleNotAvailable() { + this.contextRunner + .withClassLoader(new FilteredClassLoader(SpringManagedContext.class)) + .withSystemProperties(HazelcastServerConfiguration.CONFIG_SYSTEM_PROPERTY + + "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.yaml") + .run((context) -> { + HazelcastInstance hz = context.getBean(HazelcastInstance.class); + IMap map = hz.getMap("myMap"); + boolean contextInjected = map.executeOnKey(42, new SpringAwareEntryProcessor<>()); + assertThat(contextInjected).isEqualTo(false); + }); + } + @Configuration(proxyBeanMethods = false) static class HazelcastConfigWithName { @@ -174,6 +230,17 @@ class HazelcastAutoConfigurationServerTests { } + @SpringAware + static class SpringAwareEntryProcessor implements EntryProcessor { + @Autowired + private ApplicationContext context; + + @Override + public Boolean process(Map.Entry entry) { + return context != null; + } + } + @Configuration(proxyBeanMethods = false) static class HazelcastConfigNoName {