Skip to content

Commit 0bc03c7

Browse files
committed
Associate application classloader to auto-configured Hazelcast instance
Closes gh-24836
1 parent 5576f26 commit 0bc03c7

File tree

8 files changed

+124
-54
lines changed

8 files changed

+124
-54
lines changed

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/hazelcast/Hazelcast3HazelcastHealthIndicatorTests.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,18 +16,17 @@
1616

1717
package org.springframework.boot.actuate.hazelcast;
1818

19-
import java.io.IOException;
20-
2119
import com.hazelcast.core.HazelcastException;
2220
import com.hazelcast.core.HazelcastInstance;
2321
import org.junit.jupiter.api.Test;
2422

2523
import org.springframework.boot.actuate.health.Health;
2624
import org.springframework.boot.actuate.health.Status;
27-
import org.springframework.boot.autoconfigure.hazelcast.HazelcastInstanceFactory;
25+
import org.springframework.boot.autoconfigure.AutoConfigurations;
26+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
27+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2828
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
2929
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
30-
import org.springframework.core.io.ClassPathResource;
3130

3231
import static org.assertj.core.api.Assertions.assertThat;
3332
import static org.mockito.ArgumentMatchers.any;
@@ -45,19 +44,16 @@
4544
class Hazelcast3HazelcastHealthIndicatorTests {
4645

4746
@Test
48-
void hazelcastUp() throws IOException {
49-
HazelcastInstance hazelcast = new HazelcastInstanceFactory(new ClassPathResource("hazelcast-3.xml"))
50-
.getHazelcastInstance();
51-
try {
52-
Health health = new HazelcastHealthIndicator(hazelcast).health();
53-
assertThat(health.getStatus()).isEqualTo(Status.UP);
54-
assertThat(health.getDetails()).containsOnlyKeys("name", "uuid").containsEntry("name",
55-
"actuator-hazelcast-3");
56-
assertThat(health.getDetails().get("uuid")).asString().isNotEmpty();
57-
}
58-
finally {
59-
hazelcast.shutdown();
60-
}
47+
void hazelcastUp() {
48+
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
49+
.withPropertyValues("spring.hazelcast.config=hazelcast-3.xml").run((context) -> {
50+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
51+
Health health = new HazelcastHealthIndicator(hazelcast).health();
52+
assertThat(health.getStatus()).isEqualTo(Status.UP);
53+
assertThat(health.getDetails()).containsOnlyKeys("name", "uuid").containsEntry("name",
54+
"actuator-hazelcast-3");
55+
assertThat(health.getDetails().get("uuid")).asString().isNotEmpty();
56+
});
6157
}
6258

6359
@Test

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/hazelcast/HazelcastHealthIndicatorTests.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,16 +16,15 @@
1616

1717
package org.springframework.boot.actuate.hazelcast;
1818

19-
import java.io.IOException;
20-
2119
import com.hazelcast.core.HazelcastException;
2220
import com.hazelcast.core.HazelcastInstance;
2321
import org.junit.jupiter.api.Test;
2422

2523
import org.springframework.boot.actuate.health.Health;
2624
import org.springframework.boot.actuate.health.Status;
27-
import org.springframework.boot.autoconfigure.hazelcast.HazelcastInstanceFactory;
28-
import org.springframework.core.io.ClassPathResource;
25+
import org.springframework.boot.autoconfigure.AutoConfigurations;
26+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
27+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2928

3029
import static org.assertj.core.api.Assertions.assertThat;
3130
import static org.mockito.ArgumentMatchers.any;
@@ -41,19 +40,16 @@
4140
class HazelcastHealthIndicatorTests {
4241

4342
@Test
44-
void hazelcastUp() throws IOException {
45-
HazelcastInstance hazelcast = new HazelcastInstanceFactory(new ClassPathResource("hazelcast.xml"))
46-
.getHazelcastInstance();
47-
try {
48-
Health health = new HazelcastHealthIndicator(hazelcast).health();
49-
assertThat(health.getStatus()).isEqualTo(Status.UP);
50-
assertThat(health.getDetails()).containsOnlyKeys("name", "uuid").containsEntry("name",
51-
"actuator-hazelcast");
52-
assertThat(health.getDetails().get("uuid")).asString().isNotEmpty();
53-
}
54-
finally {
55-
hazelcast.shutdown();
56-
}
43+
void hazelcastUp() {
44+
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
45+
.withPropertyValues("spring.hazelcast.config=hazelcast.xml").run((context) -> {
46+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
47+
Health health = new HazelcastHealthIndicator(hazelcast).health();
48+
assertThat(health.getStatus()).isEqualTo(Status.UP);
49+
assertThat(health.getDetails()).containsOnlyKeys("name", "uuid").containsEntry("name",
50+
"actuator-hazelcast");
51+
assertThat(health.getDetails().get("uuid")).asString().isNotEmpty();
52+
});
5753
}
5854

5955
@Test

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastClientConfiguration.java

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,9 +17,12 @@
1717
package org.springframework.boot.autoconfigure.hazelcast;
1818

1919
import java.io.IOException;
20+
import java.net.URL;
2021

2122
import com.hazelcast.client.HazelcastClient;
2223
import com.hazelcast.client.config.ClientConfig;
24+
import com.hazelcast.client.config.XmlClientConfigBuilder;
25+
import com.hazelcast.client.config.YamlClientConfigBuilder;
2326
import com.hazelcast.core.HazelcastInstance;
2427

2528
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -29,6 +32,8 @@
2932
import org.springframework.context.annotation.Conditional;
3033
import org.springframework.context.annotation.Configuration;
3134
import org.springframework.core.io.Resource;
35+
import org.springframework.core.io.ResourceLoader;
36+
import org.springframework.util.StringUtils;
3237

3338
/**
3439
* Configuration for Hazelcast client.
@@ -43,18 +48,34 @@ class HazelcastClientConfiguration {
4348

4449
static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.client.config";
4550

51+
private static HazelcastInstance getHazelcastInstance(ClientConfig config) {
52+
if (StringUtils.hasText(config.getInstanceName())) {
53+
return HazelcastClient.getOrCreateHazelcastClient(config);
54+
}
55+
return HazelcastClient.newHazelcastClient(config);
56+
}
57+
4658
@Configuration(proxyBeanMethods = false)
4759
@ConditionalOnMissingBean(ClientConfig.class)
4860
@Conditional(HazelcastClientConfigAvailableCondition.class)
4961
static class HazelcastClientConfigFileConfiguration {
5062

5163
@Bean
52-
HazelcastInstance hazelcastInstance(HazelcastProperties properties) throws IOException {
53-
Resource config = properties.resolveConfigLocation();
54-
if (config != null) {
55-
return new HazelcastClientFactory(config).getHazelcastInstance();
64+
HazelcastInstance hazelcastInstance(HazelcastProperties properties, ResourceLoader resourceLoader)
65+
throws IOException {
66+
Resource configLocation = properties.resolveConfigLocation();
67+
ClientConfig config = (configLocation != null) ? loadClientConfig(configLocation) : ClientConfig.load();
68+
config.setClassLoader(resourceLoader.getClassLoader());
69+
return getHazelcastInstance(config);
70+
}
71+
72+
private ClientConfig loadClientConfig(Resource configLocation) throws IOException {
73+
URL configUrl = configLocation.getURL();
74+
String configFileName = configUrl.getPath();
75+
if (configFileName.endsWith(".yaml")) {
76+
return new YamlClientConfigBuilder(configUrl).build();
5677
}
57-
return HazelcastClient.newHazelcastClient();
78+
return new XmlClientConfigBuilder(configUrl).build();
5879
}
5980

6081
}
@@ -65,7 +86,7 @@ static class HazelcastClientConfigConfiguration {
6586

6687
@Bean
6788
HazelcastInstance hazelcastInstance(ClientConfig config) {
68-
return new HazelcastClientFactory(config).getHazelcastInstance();
89+
return getHazelcastInstance(config);
6990
}
7091

7192
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastClientFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,9 @@
3434
*
3535
* @author Vedran Pavic
3636
* @since 2.0.0
37+
* @deprecated since 2.3.4 in favor of using the Hazelcast API directly
3738
*/
39+
@Deprecated
3840
public class HazelcastClientFactory {
3941

4042
private final ClientConfig clientConfig;

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastInstanceFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,7 +36,9 @@
3636
* @author Stephane Nicoll
3737
* @author Phillip Webb
3838
* @since 1.3.0
39+
* @deprecated since 2.3.4 in favor of using the Hazelcast API directly
3940
*/
41+
@Deprecated
4042
public class HazelcastInstanceFactory {
4143

4244
private final Config config;

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastServerConfiguration.java

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,11 @@
1717
package org.springframework.boot.autoconfigure.hazelcast;
1818

1919
import java.io.IOException;
20+
import java.net.URL;
2021

2122
import com.hazelcast.config.Config;
23+
import com.hazelcast.config.XmlConfigBuilder;
24+
import com.hazelcast.config.YamlConfigBuilder;
2225
import com.hazelcast.core.Hazelcast;
2326
import com.hazelcast.core.HazelcastInstance;
2427

@@ -28,6 +31,9 @@
2831
import org.springframework.context.annotation.Conditional;
2932
import org.springframework.context.annotation.Configuration;
3033
import org.springframework.core.io.Resource;
34+
import org.springframework.core.io.ResourceLoader;
35+
import org.springframework.util.ResourceUtils;
36+
import org.springframework.util.StringUtils;
3137

3238
/**
3339
* Configuration for Hazelcast server.
@@ -41,18 +47,45 @@ class HazelcastServerConfiguration {
4147

4248
static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.config";
4349

50+
private static HazelcastInstance getHazelcastInstance(Config config) {
51+
if (StringUtils.hasText(config.getInstanceName())) {
52+
return Hazelcast.getOrCreateHazelcastInstance(config);
53+
}
54+
return Hazelcast.newHazelcastInstance(config);
55+
}
56+
4457
@Configuration(proxyBeanMethods = false)
4558
@ConditionalOnMissingBean(Config.class)
4659
@Conditional(ConfigAvailableCondition.class)
4760
static class HazelcastServerConfigFileConfiguration {
4861

4962
@Bean
50-
HazelcastInstance hazelcastInstance(HazelcastProperties properties) throws IOException {
51-
Resource config = properties.resolveConfigLocation();
52-
if (config != null) {
53-
return new HazelcastInstanceFactory(config).getHazelcastInstance();
63+
HazelcastInstance hazelcastInstance(HazelcastProperties properties, ResourceLoader resourceLoader)
64+
throws IOException {
65+
Resource configLocation = properties.resolveConfigLocation();
66+
Config config = (configLocation != null) ? loadConfig(configLocation) : Config.load();
67+
config.setClassLoader(resourceLoader.getClassLoader());
68+
return getHazelcastInstance(config);
69+
}
70+
71+
private Config loadConfig(Resource configLocation) throws IOException {
72+
URL configUrl = configLocation.getURL();
73+
Config config = loadConfig(configUrl);
74+
if (ResourceUtils.isFileURL(configUrl)) {
75+
config.setConfigurationFile(configLocation.getFile());
76+
}
77+
else {
78+
config.setConfigurationUrl(configUrl);
79+
}
80+
return config;
81+
}
82+
83+
private static Config loadConfig(URL configUrl) throws IOException {
84+
String configFileName = configUrl.getPath();
85+
if (configFileName.endsWith(".yaml")) {
86+
return new YamlConfigBuilder(configUrl).build();
5487
}
55-
return Hazelcast.newHazelcastInstance();
88+
return new XmlConfigBuilder(configUrl).build();
5689
}
5790

5891
}
@@ -63,7 +96,7 @@ static class HazelcastServerConfigConfiguration {
6396

6497
@Bean
6598
HazelcastInstance hazelcastInstance(Config config) {
66-
return new HazelcastInstanceFactory(config).getHazelcastInstance();
99+
return getHazelcastInstance(config);
67100
}
68101

69102
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationClientTests.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -135,6 +135,18 @@ void clientConfigWithInstanceNameCreatesClientIfNecessary() {
135135
.extracting(HazelcastInstance::getName).isEqualTo("spring-boot"));
136136
}
137137

138+
@Test
139+
void autoConfiguredClientConfigUsesApplicationClassLoader() {
140+
this.contextRunner.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
141+
+ "hazelcast/hazelcast-client-specific.xml").run((context) -> {
142+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
143+
assertThat(hazelcast).isInstanceOf(HazelcastClientProxy.class);
144+
ClientConfig clientConfig = ((HazelcastClientProxy) hazelcast).getClientConfig();
145+
assertThat(clientConfig.getClassLoader())
146+
.isSameAs(context.getSourceApplicationContext().getClassLoader());
147+
});
148+
}
149+
138150
private ContextConsumer<AssertableApplicationContext> assertSpecificHazelcastClient(String label) {
139151
return (context) -> assertThat(context).getBean(HazelcastInstance.class).isInstanceOf(HazelcastInstance.class)
140152
.has(labelEqualTo(label));

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -156,6 +156,14 @@ void configInstanceWithoutName() {
156156
});
157157
}
158158

159+
@Test
160+
void autoConfiguredConfigUsesApplicationClassLoader() {
161+
this.contextRunner.run((context) -> {
162+
Config config = context.getBean(HazelcastInstance.class).getConfig();
163+
assertThat(config.getClassLoader()).isSameAs(context.getSourceApplicationContext().getClassLoader());
164+
});
165+
}
166+
159167
@Configuration(proxyBeanMethods = false)
160168
static class HazelcastConfigWithName {
161169

0 commit comments

Comments
 (0)