Polish "Add auto-configuration support for Hazelcast client"

Closes gh-7469
pull/2934/merge
Stephane Nicoll 8 years ago
parent 3fbf1a2ea6
commit 0aded58884

@ -16,12 +16,10 @@
package org.springframework.boot.autoconfigure.hazelcast;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -39,21 +37,7 @@ import org.springframework.context.annotation.Import;
@Configuration
@ConditionalOnClass(HazelcastInstance.class)
@EnableConfigurationProperties(HazelcastProperties.class)
@Import({ HazelcastClientConfiguration.class, HazelcastServerConfiguration.class })
public class HazelcastAutoConfiguration {
@Configuration
@ConditionalOnMissingBean(HazelcastInstance.class)
@Import(HazelcastServerConfiguration.class)
static class ServerConfiguration {
}
@Configuration
@ConditionalOnClass(HazelcastClient.class)
@ConditionalOnMissingBean(HazelcastInstance.class)
@Import(HazelcastClientConfiguration.class)
static class ClientConfiguration {
}
}

@ -22,6 +22,7 @@ import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.core.HazelcastInstance;
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.annotation.Bean;
@ -33,8 +34,10 @@ import org.springframework.core.io.Resource;
* Configuration for Hazelcast client.
*
* @author Vedran Pavic
* @since 2.0.0
* @author Stephane Nicoll
*/
@ConditionalOnClass(HazelcastClient.class)
@ConditionalOnMissingBean(HazelcastInstance.class)
class HazelcastClientConfiguration {
static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.client.config";
@ -49,7 +52,7 @@ class HazelcastClientConfiguration {
throws IOException {
Resource config = properties.resolveConfigLocation();
if (config != null) {
return HazelcastInstanceFactory.createHazelcastClient(config);
return new HazelcastClientFactory(config).getHazelcastInstance();
}
return HazelcastClient.newHazelcastClient();
}
@ -62,7 +65,7 @@ class HazelcastClientConfiguration {
@Bean
public HazelcastInstance hazelcastInstance(ClientConfig config) {
return HazelcastInstanceFactory.createHazelcastClient(config);
return new HazelcastClientFactory(config).getHazelcastInstance();
}
}

@ -0,0 +1,78 @@
/*
* Copyright 2012-2017 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
*
* http://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.boot.autoconfigure.hazelcast;
import java.io.IOException;
import java.net.URL;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.config.XmlClientConfigBuilder;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Factory that can be used to create a client {@link HazelcastInstance}.
*
* @author Vedran Pavic
* @since 2.0.0
*/
public class HazelcastClientFactory {
private final ClientConfig clientConfig;
/**
* Create a {@link HazelcastClientFactory} for the specified configuration location.
* @param clientConfigLocation the location of the configuration file
* @throws IOException if the configuration location could not be read
*/
public HazelcastClientFactory(Resource clientConfigLocation) throws IOException {
this.clientConfig = getClientConfig(clientConfigLocation);
}
/**
* Create a {@link HazelcastClientFactory} for the specified configuration.
* @param clientConfig the configuration
*/
public HazelcastClientFactory(ClientConfig clientConfig) {
Assert.notNull(clientConfig, "ClientConfig must not be null");
this.clientConfig = clientConfig;
}
private ClientConfig getClientConfig(Resource clientConfigLocation)
throws IOException {
URL configUrl = clientConfigLocation.getURL();
return new XmlClientConfigBuilder(configUrl).build();
}
/**
* Get the {@link HazelcastInstance}.
* @return the {@link HazelcastInstance}
*/
public HazelcastInstance getHazelcastInstance() {
if (StringUtils.hasText(this.clientConfig.getInstanceName())) {
return HazelcastClient.getHazelcastClientByName(
this.clientConfig.getInstanceName());
}
return HazelcastClient.newHazelcastClient(this.clientConfig);
}
}

@ -19,9 +19,6 @@ package org.springframework.boot.autoconfigure.hazelcast;
import java.io.IOException;
import java.net.URL;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.config.XmlClientConfigBuilder;
import com.hazelcast.config.Config;
import com.hazelcast.config.XmlConfigBuilder;
import com.hazelcast.core.Hazelcast;
@ -37,33 +34,32 @@ import org.springframework.util.StringUtils;
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Vedran Pavic
* @since 1.3.0
*/
public abstract class HazelcastInstanceFactory {
public class HazelcastInstanceFactory {
/**
* Get the {@link HazelcastInstance}.
* @param config the configuration
* @return the {@link HazelcastInstance}
*/
public static HazelcastInstance createHazelcastInstance(Config config) {
Assert.notNull(config, "Config must not be null");
if (StringUtils.hasText(config.getInstanceName())) {
return Hazelcast.getOrCreateHazelcastInstance(config);
}
return Hazelcast.newHazelcastInstance(config);
}
private final Config config;
/**
* Get the {@link HazelcastInstance}.
* Create a {@link HazelcastInstanceFactory} for the specified configuration location.
* @param configLocation the location of the configuration file
* @return the {@link HazelcastInstance}
* @throws IOException if the configuration location could not be read
*/
public static HazelcastInstance createHazelcastInstance(Resource configLocation)
throws IOException {
public HazelcastInstanceFactory(Resource configLocation) throws IOException {
Assert.notNull(configLocation, "ConfigLocation must not be null");
this.config = getConfig(configLocation);
}
/**
* Create a {@link HazelcastInstanceFactory} for the specified configuration.
* @param config the configuration
*/
public HazelcastInstanceFactory(Config config) {
Assert.notNull(config, "Config must not be null");
this.config = config;
}
private Config getConfig(Resource configLocation) throws IOException {
URL configUrl = configLocation.getURL();
Config config = new XmlConfigBuilder(configUrl).build();
if (ResourceUtils.isFileURL(configUrl)) {
@ -72,34 +68,18 @@ public abstract class HazelcastInstanceFactory {
else {
config.setConfigurationUrl(configUrl);
}
return createHazelcastInstance(config);
return config;
}
/**
* Get the client {@link HazelcastInstance}.
* @param config the client configuration
* @return the client {@link HazelcastInstance}
* Get the {@link HazelcastInstance}.
* @return the {@link HazelcastInstance}
*/
public static HazelcastInstance createHazelcastClient(ClientConfig config) {
Assert.notNull(config, "Config must not be null");
if (StringUtils.hasText(config.getInstanceName())) {
return HazelcastClient.getHazelcastClientByName(config.getInstanceName());
public HazelcastInstance getHazelcastInstance() {
if (StringUtils.hasText(this.config.getInstanceName())) {
return Hazelcast.getOrCreateHazelcastInstance(this.config);
}
return HazelcastClient.newHazelcastClient(config);
}
/**
* Get the client {@link HazelcastInstance}.
* @param configLocation the location of the client configuration file
* @return the client {@link HazelcastInstance}
* @throws IOException if the configuration location could not be read
*/
public static HazelcastInstance createHazelcastClient(Resource configLocation)
throws IOException {
Assert.notNull(configLocation, "ConfigLocation must not be null");
URL configUrl = configLocation.getURL();
ClientConfig config = new XmlClientConfigBuilder(configUrl).build();
return createHazelcastClient(config);
return Hazelcast.newHazelcastInstance(this.config);
}
}

@ -34,8 +34,8 @@ import org.springframework.core.io.Resource;
*
* @author Stephane Nicoll
* @author Vedran Pavic
* @since 2.0.0
*/
@ConditionalOnMissingBean(HazelcastInstance.class)
class HazelcastServerConfiguration {
static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.config";
@ -50,7 +50,7 @@ class HazelcastServerConfiguration {
throws IOException {
Resource config = properties.resolveConfigLocation();
if (config != null) {
return HazelcastInstanceFactory.createHazelcastInstance(config);
return new HazelcastInstanceFactory(config).getHazelcastInstance();
}
return Hazelcast.newHazelcastInstance();
}
@ -63,7 +63,7 @@ class HazelcastServerConfiguration {
@Bean
public HazelcastInstance hazelcastInstance(Config config) {
return HazelcastInstanceFactory.createHazelcastInstance(config);
return new HazelcastInstanceFactory(config).getHazelcastInstance();
}
}

@ -39,9 +39,10 @@ import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for client {@link HazelcastAutoConfiguration}.
* Tests for {@link HazelcastAutoConfiguration} specific to the client.
*
* @author Vedran Pavic
* @author Stephane Nicoll
*/
public class HazelcastAutoConfigurationClientTests {
@ -50,24 +51,27 @@ public class HazelcastAutoConfigurationClientTests {
private AnnotationConfigApplicationContext context;
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
private static HazelcastInstance hazelcastInstance;
/**
* Servers the test clients will connect to.
*/
private static HazelcastInstance hazelcastServer;
@BeforeClass
public static void init() {
hazelcastInstance = Hazelcast.newHazelcastInstance();
hazelcastServer = Hazelcast.newHazelcastInstance();
}
@AfterClass
public static void close() {
if (hazelcastInstance != null) {
hazelcastInstance.shutdown();
if (hazelcastServer != null) {
hazelcastServer.shutdown();
}
}
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@ -115,7 +119,7 @@ public class HazelcastAutoConfigurationClientTests {
}
@Test
public void clientConfigHasPriority() {
public void clientConfigTakesPrecedence() {
load(HazelcastServerAndClientConfig.class, "spring.hazelcast.config=this-is-ignored.xml");
HazelcastInstance hazelcastInstance = this.context
.getBean(HazelcastInstance.class);

@ -41,7 +41,7 @@ import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link HazelcastAutoConfiguration}.
* Tests for {@link HazelcastAutoConfiguration} when the client library is not present.
*
* @author Stephane Nicoll
*/

@ -0,0 +1,64 @@
/*
* Copyright 2012-2017 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
*
* http://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.boot.autoconfigure.hazelcast;
import java.io.IOException;
import com.hazelcast.core.HazelcastInstance;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link HazelcastAutoConfiguration} with full classpath.
*
* @author Stephane Nicoll
*/
public class HazelcastAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void defaultConfigFile() throws IOException {
load(); // no hazelcast-client.xml and hazelcast.xml is present in root classpath
HazelcastInstance hazelcastInstance = this.context
.getBean(HazelcastInstance.class);
assertThat(hazelcastInstance.getConfig().getConfigurationUrl())
.isEqualTo(new ClassPathResource("hazelcast.xml").getURL());
}
private void load(String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment);
ctx.register(HazelcastAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
}

@ -5111,9 +5111,8 @@ provide good examples of how to write XA wrappers.
[[boot-features-hazelcast]]
== Hazelcast
If hazelcast is on the classpath, Spring Boot will auto-configure an `HazelcastInstance`
that you can inject in your application. The `HazelcastInstance` is only created if a
configuration is found.
If hazelcast is on the classpath and a suitable configuration is found, Spring Boot
will auto-configure an `HazelcastInstance` that you can inject in your application.
You can define a `com.hazelcast.config.Config` bean and we'll use that. If your
configuration defines an instance name, we'll try to locate an existing instance rather
@ -5132,6 +5131,14 @@ classpath. We also check if the `hazelcast.config` system property is set. Check
http://docs.hazelcast.org/docs/latest/manual/html-single/[Hazelcast documentation] for
more details.
If `hazelcast-client` is present on the classpath, Spring Boot will first attempt to
create a client with similar rules as above, that is:
* The presence of a `com.hazelcast.client.config.ClientConfig` bean
* A configuration file defined by the `spring.hazelcast.config` property
* The presence of the `hazelcast.client.config` system property
* A `hazelcast-client.xml` in the working directory or at the root of the classpath
NOTE: Spring Boot also has an
<<boot-features-caching-provider-hazelcast,explicit caching support for Hazelcast>>. The
`HazelcastInstance` is automatically wrapped in a `CacheManager` implementation if

Loading…
Cancel
Save