Skip to content

Commit 721b5a2

Browse files
committed
Hazelcast auto-configuration
Provide a general purpose Hazelcast integration (i.e. not tied to caching). Auto-configure a `HazelcastInstance` either based on the presence of a `Config` bean or a configuration file. Said configuration file can be specified explicitly or automatically found from default locations. The cache integration already supports Hazelcast so it has been reworked to automatically reuse an existing `HazelcastInstance` if available. Closes gh-2942
1 parent 35b2bca commit 721b5a2

File tree

14 files changed

+680
-85
lines changed

14 files changed

+680
-85
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/EhCacheCacheConfiguration.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import net.sf.ehcache.CacheManager;
2121

2222
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.boot.autoconfigure.condition.ResourceCondition;
2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2425
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2526
import org.springframework.cache.ehcache.EhCacheCacheManager;
@@ -68,10 +69,10 @@ public CacheManager ehCacheCacheManager() {
6869
* default configuration has been found or if property referring to the file to use
6970
* has been set.
7071
*/
71-
static class ConfigAvailableCondition extends CacheConfigFileCondition {
72+
static class ConfigAvailableCondition extends ResourceCondition {
7273

7374
public ConfigAvailableCondition() {
74-
super("EhCache", "spring.cache.ehcache", "classpath:/ehcache.xml");
75+
super("EhCache", "spring.cache.ehcache", "config", "classpath:/ehcache.xml");
7576
}
7677

7778
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastCacheConfiguration.java

+77-44
Original file line numberDiff line numberDiff line change
@@ -16,85 +16,118 @@
1616

1717
package org.springframework.boot.autoconfigure.cache;
1818

19+
import java.io.Closeable;
1920
import java.io.IOException;
2021

22+
import com.hazelcast.core.Hazelcast;
23+
import com.hazelcast.core.HazelcastInstance;
24+
import com.hazelcast.spring.cache.HazelcastCacheManager;
25+
2126
import org.springframework.beans.factory.annotation.Autowired;
22-
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
27+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2328
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2429
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
31+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
32+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastConfigResourceCondition;
2533
import org.springframework.cache.CacheManager;
2634
import org.springframework.context.annotation.Bean;
27-
import org.springframework.context.annotation.ConditionContext;
2835
import org.springframework.context.annotation.Conditional;
2936
import org.springframework.context.annotation.Configuration;
3037
import org.springframework.core.io.Resource;
31-
import org.springframework.core.type.AnnotatedTypeMetadata;
32-
33-
import com.hazelcast.config.Config;
34-
import com.hazelcast.config.XmlConfigBuilder;
35-
import com.hazelcast.core.Hazelcast;
36-
import com.hazelcast.core.HazelcastInstance;
37-
import com.hazelcast.spring.cache.HazelcastCacheManager;
3838

3939
/**
40-
* Hazelcast cache configuration. Only kick in if a configuration file location is set or
41-
* if a default configuration file exists (either placed in the default location or set
42-
* via the {@value #CONFIG_SYSTEM_PROPERTY} system property).
40+
* Hazelcast cache configuration. Can either reuse the {@link HazelcastInstance} that
41+
* has been configured by the general {@link HazelcastAutoConfiguration} or create
42+
* a separate one if the {@code spring.cache.hazelcast.config} property has been set.
43+
* <p>
44+
* If the {@link HazelcastAutoConfiguration} has been disabled, an attempt to configure
45+
* a default {@link HazelcastInstance} is still made, using the same defaults.
4346
*
4447
* @author Stephane Nicoll
4548
* @since 1.3.0
49+
* @see HazelcastConfigResourceCondition
4650
*/
4751
@Configuration
48-
@ConditionalOnClass({ HazelcastInstance.class, HazelcastCacheManager.class })
52+
@ConditionalOnClass({HazelcastInstance.class, HazelcastCacheManager.class})
4953
@ConditionalOnMissingBean(CacheManager.class)
50-
@Conditional({ CacheCondition.class,
51-
HazelcastCacheConfiguration.ConfigAvailableCondition.class })
54+
@Conditional(CacheCondition.class)
55+
@AutoConfigureAfter(HazelcastAutoConfiguration.class)
5256
class HazelcastCacheConfiguration {
5357

54-
static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.config";
58+
@Configuration
59+
@ConditionalOnSingleCandidate(HazelcastInstance.class)
60+
static class ExistingHazelcastInstanceConfiguration {
61+
62+
@Autowired
63+
private CacheProperties cacheProperties;
5564

56-
@Autowired
57-
private CacheProperties cacheProperties;
65+
@Bean
66+
public HazelcastCacheManager cacheManager(HazelcastInstance existingHazelcastInstance)
67+
throws IOException {
68+
Resource location = this.cacheProperties
69+
.resolveConfigLocation(this.cacheProperties.getHazelcast().getConfig());
70+
if (location != null) {
71+
HazelcastInstance cacheHazelcastInstance =
72+
HazelcastAutoConfiguration.createHazelcastInstance(location);
73+
return new CloseableHazelcastCacheManager(cacheHazelcastInstance);
74+
}
75+
else {
76+
return new HazelcastCacheManager(existingHazelcastInstance);
77+
}
5878

59-
@Bean
60-
public HazelcastCacheManager cacheManager(HazelcastInstance hazelcastInstance) {
61-
return new HazelcastCacheManager(hazelcastInstance);
79+
}
6280
}
6381

64-
@Bean
65-
@ConditionalOnMissingBean
66-
public HazelcastInstance hazelcastInstance() throws IOException {
67-
Resource location = this.cacheProperties
68-
.resolveConfigLocation(this.cacheProperties.getHazelcast().getConfig());
69-
if (location != null) {
70-
Config cfg = new XmlConfigBuilder(location.getURL()).build();
71-
return Hazelcast.newHazelcastInstance(cfg);
82+
@Configuration
83+
@ConditionalOnMissingBean(HazelcastInstance.class)
84+
@Conditional(ConfigAvailableCondition.class)
85+
static class DefaultHazelcastInstanceConfiguration {
86+
87+
@Autowired
88+
private CacheProperties cacheProperties;
89+
90+
@Bean
91+
public HazelcastInstance hazelcastInstance() throws IOException {
92+
Resource location = this.cacheProperties
93+
.resolveConfigLocation(this.cacheProperties.getHazelcast().getConfig());
94+
if (location != null) {
95+
HazelcastAutoConfiguration.createHazelcastInstance(location);
96+
}
97+
return Hazelcast.newHazelcastInstance();
98+
}
99+
100+
@Bean
101+
public HazelcastCacheManager cacheManager() throws IOException {
102+
return new HazelcastCacheManager(hazelcastInstance());
72103
}
73-
return Hazelcast.newHazelcastInstance();
104+
74105
}
75106

76107
/**
77-
* Determines if the Hazelcast configuration is available. This either kicks in if a
78-
* default configuration has been found or if property referring to the file to use
79-
* has been set.
108+
* {@link HazelcastConfigResourceCondition} that checks if the
109+
* {@code spring.cache.hazelcast.config} configuration key is defined.
80110
*/
81-
static class ConfigAvailableCondition extends CacheConfigFileCondition {
111+
static class ConfigAvailableCondition extends HazelcastConfigResourceCondition {
82112

83113
public ConfigAvailableCondition() {
84-
super("Hazelcast", "spring.cache.hazelcast", "file:./hazelcast.xml",
85-
"classpath:/hazelcast.xml");
114+
super("spring.cache.hazelcast", "config");
86115
}
87116

88-
@Override
89-
protected ConditionOutcome getResourceOutcome(ConditionContext context,
90-
AnnotatedTypeMetadata metadata) {
91-
if (System.getProperty(CONFIG_SYSTEM_PROPERTY) != null) {
92-
return ConditionOutcome.match("System property '"
93-
+ CONFIG_SYSTEM_PROPERTY + "' is set.");
94-
}
95-
return super.getResourceOutcome(context, metadata);
117+
}
118+
119+
private static class CloseableHazelcastCacheManager extends HazelcastCacheManager implements Closeable {
120+
private final HazelcastInstance hazelcastInstance;
121+
122+
public CloseableHazelcastCacheManager(HazelcastInstance hazelcastInstance) {
123+
super(hazelcastInstance);
124+
this.hazelcastInstance = hazelcastInstance;
96125
}
97126

127+
@Override
128+
public void close() throws IOException {
129+
this.hazelcastInstance.shutdown();
130+
}
98131
}
99132

100133
}
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,44 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.autoconfigure.cache;
17+
package org.springframework.boot.autoconfigure.condition;
1818

19-
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
20-
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
2119
import org.springframework.boot.bind.RelaxedPropertyResolver;
2220
import org.springframework.context.annotation.ConditionContext;
2321
import org.springframework.core.io.Resource;
2422
import org.springframework.core.type.AnnotatedTypeMetadata;
2523

2624
/**
27-
* {@link SpringBootCondition} used to check if a cache configuration file can be found.
25+
* {@link SpringBootCondition} used to check if a resource can be found using a
26+
* configurable property and optional default location(s).
2827
*
2928
* @author Stephane Nicoll
3029
* @author Phillip Webb
30+
* @since 1.3.0
3131
*/
32-
abstract class CacheConfigFileCondition extends SpringBootCondition {
32+
public abstract class ResourceCondition extends SpringBootCondition {
3333

3434
private final String name;
3535

3636
private final String prefix;
3737

38+
private final String propertyName;
39+
3840
private final String[] resourceLocations;
3941

40-
public CacheConfigFileCondition(String name, String prefix,
42+
/**
43+
* Create a new condition.
44+
* @param name the name of the component
45+
* @param prefix the prefix of the configuration key
46+
* @param propertyName the name of the configuration key
47+
* @param resourceLocations default location(s) where the configuration file can be
48+
* found if the configuration key is not specified
49+
*/
50+
protected ResourceCondition(String name, String prefix, String propertyName,
4151
String... resourceLocations) {
4252
this.name = name;
4353
this.prefix = (prefix.endsWith(".") ? prefix : prefix + ".");
54+
this.propertyName = propertyName;
4455
this.resourceLocations = resourceLocations;
4556
}
4657

@@ -49,13 +60,19 @@ public ConditionOutcome getMatchOutcome(ConditionContext context,
4960
AnnotatedTypeMetadata metadata) {
5061
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
5162
context.getEnvironment(), this.prefix);
52-
if (resolver.containsProperty("config")) {
53-
return ConditionOutcome.match("A '" + this.prefix + ".config' "
63+
if (resolver.containsProperty(propertyName)) {
64+
return ConditionOutcome.match("A '" + this.prefix + propertyName +"' "
5465
+ "property is specified");
5566
}
5667
return getResourceOutcome(context, metadata);
5768
}
5869

70+
/**
71+
* Check if one of the default resource locations actually exists.
72+
* @param context the condition context
73+
* @param metadata the annotation metadata
74+
* @return the condition outcome
75+
*/
5976
protected ConditionOutcome getResourceOutcome(ConditionContext context,
6077
AnnotatedTypeMetadata metadata) {
6178
for (String location : this.resourceLocations) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright 2012-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.hazelcast;
18+
19+
import java.io.IOException;
20+
import java.net.URL;
21+
22+
import com.hazelcast.config.Config;
23+
import com.hazelcast.config.XmlConfigBuilder;
24+
import com.hazelcast.core.Hazelcast;
25+
import com.hazelcast.core.HazelcastInstance;
26+
27+
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
32+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
33+
import org.springframework.context.annotation.Bean;
34+
import org.springframework.context.annotation.Conditional;
35+
import org.springframework.context.annotation.Configuration;
36+
import org.springframework.core.io.Resource;
37+
import org.springframework.util.Assert;
38+
import org.springframework.util.ResourceUtils;
39+
import org.springframework.util.StringUtils;
40+
41+
/**
42+
* {@link EnableAutoConfiguration Auto-configuration} for Hazelcast. Creates a
43+
* {@link HazelcastInstance} based on explicit configuration or when a default
44+
* configuration file is found in the environment.
45+
*
46+
* @author Stephane Nicoll
47+
* @since 1.3.0
48+
* @see HazelcastConfigResourceCondition
49+
*/
50+
@Configuration
51+
@ConditionalOnClass(HazelcastInstance.class)
52+
@ConditionalOnMissingBean(HazelcastInstance.class)
53+
@EnableConfigurationProperties(HazelcastProperties.class)
54+
public class HazelcastAutoConfiguration {
55+
56+
57+
/**
58+
* Create a {@link HazelcastInstance} based on the specified configuration location.
59+
* @param location the location of the configuration file
60+
* @return a {@link HazelcastInstance} for the specified configuration
61+
* @throws IOException the configuration file could not be read
62+
*/
63+
public static HazelcastInstance createHazelcastInstance(Resource location)
64+
throws IOException {
65+
Assert.notNull(location, "Config must not be null");
66+
URL configUrl = location.getURL();
67+
Config config = new XmlConfigBuilder(configUrl).build();
68+
if (ResourceUtils.isFileURL(configUrl)) {
69+
config.setConfigurationFile(location.getFile());
70+
}
71+
else {
72+
config.setConfigurationUrl(configUrl);
73+
}
74+
return createHazelcastInstance(config);
75+
}
76+
77+
private static HazelcastInstance createHazelcastInstance(Config config) {
78+
if (StringUtils.hasText(config.getInstanceName())) {
79+
return Hazelcast.getOrCreateHazelcastInstance(config);
80+
}
81+
return Hazelcast.newHazelcastInstance(config);
82+
}
83+
84+
85+
@Configuration
86+
@ConditionalOnMissingBean({HazelcastInstance.class, Config.class})
87+
@Conditional(ConfigAvailableCondition.class)
88+
static class HazelcastConfigFileConfiguration {
89+
90+
@Autowired
91+
private HazelcastProperties hazelcastProperties;
92+
93+
@Bean
94+
@ConditionalOnMissingBean
95+
public HazelcastInstance hazelcastInstance() throws IOException {
96+
Resource config = this.hazelcastProperties.resolveConfigLocation();
97+
if (config != null) {
98+
return createHazelcastInstance(config);
99+
}
100+
return Hazelcast.newHazelcastInstance();
101+
}
102+
103+
}
104+
105+
@Configuration
106+
@ConditionalOnMissingBean(HazelcastInstance.class)
107+
@ConditionalOnSingleCandidate(Config.class)
108+
static class HazelcastConfigConfiguration {
109+
110+
@Bean
111+
public HazelcastInstance hazelcastInstance(Config config) {
112+
return createHazelcastInstance(config);
113+
}
114+
115+
}
116+
117+
/**
118+
* {@link HazelcastConfigResourceCondition} that checks if the
119+
* {@code spring.hazelcast.config} configuration key is defined.
120+
*/
121+
static class ConfigAvailableCondition extends HazelcastConfigResourceCondition {
122+
123+
public ConfigAvailableCondition() {
124+
super("spring.hazelcast", "config");
125+
}
126+
}
127+
128+
}

0 commit comments

Comments
 (0)