Inject SpringManagedContext into Hazelcast configuration

This commit makes it possible to inject Spring managed beans into
objects instantiated by Hazelcast.

See gh-28801
pull/29200/head
Jaromir Hamala 3 years ago committed by Stephane Nicoll
parent 6d55b687f7
commit b875b55711

@ -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<ConfigurationCustomizer> 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.

@ -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<Integer, Integer> 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<Integer, Integer> 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<Integer, Integer> 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<Integer, Integer> 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<K, V> implements EntryProcessor<K, V, Boolean> {
@Autowired
private ApplicationContext context;
@Override
public Boolean process(Map.Entry<K, V> entry) {
return context != null;
}
}
@Configuration(proxyBeanMethods = false)
static class HazelcastConfigNoName {

Loading…
Cancel
Save