Improve Hazelcast configuration
This commit improves Hazelcast configuration by introducing `@SpringSessionHazelcastInstance` qualifier for explicitly declaring a `HazelcastInstance` to be used by Spring Session. This is in particular useful in scenarios with multiple `HazelcastInstance` beans present in the application context. Closes gh-912
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2014-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.session.hazelcast.config.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.session.hazelcast.HazelcastSessionRepository;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for a {@link HazelcastInstance} to be injected in
|
||||
* {@link HazelcastSessionRepository}.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,
|
||||
ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Qualifier
|
||||
public @interface SpringSessionHazelcastInstance {
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.IMap;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.session.MapSession;
|
||||
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
|
||||
import org.springframework.session.hazelcast.HazelcastFlushMode;
|
||||
import org.springframework.session.hazelcast.HazelcastSessionRepository;
|
||||
import org.springframework.session.hazelcast.config.annotation.SpringSessionHazelcastInstance;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
|
||||
/**
|
||||
@@ -57,15 +59,21 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
|
||||
|
||||
@Bean
|
||||
public HazelcastSessionRepository sessionRepository(
|
||||
HazelcastInstance hazelcastInstance,
|
||||
@SpringSessionHazelcastInstance ObjectProvider<HazelcastInstance> springSessionHazelcastInstance,
|
||||
ObjectProvider<HazelcastInstance> hazelcastInstance,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
IMap<String, MapSession> sessions = hazelcastInstance.getMap(
|
||||
this.sessionMapName);
|
||||
HazelcastInstance hazelcastInstanceToUse = springSessionHazelcastInstance
|
||||
.getIfAvailable();
|
||||
if (hazelcastInstanceToUse == null) {
|
||||
hazelcastInstanceToUse = hazelcastInstance.getObject();
|
||||
}
|
||||
IMap<String, MapSession> sessions = hazelcastInstanceToUse
|
||||
.getMap(this.sessionMapName);
|
||||
HazelcastSessionRepository sessionRepository = new HazelcastSessionRepository(
|
||||
sessions);
|
||||
sessionRepository.setApplicationEventPublisher(eventPublisher);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(
|
||||
this.maxInactiveIntervalInSeconds);
|
||||
sessionRepository
|
||||
.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
|
||||
sessionRepository.setHazelcastFlushMode(this.hazelcastFlushMode);
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
@@ -19,25 +19,24 @@ package org.springframework.session.hazelcast.config.annotation.web.http;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.IMap;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.session.hazelcast.HazelcastFlushMode;
|
||||
import org.springframework.session.hazelcast.HazelcastSessionRepository;
|
||||
import org.springframework.session.hazelcast.config.annotation.SpringSessionHazelcastInstance;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link HazelcastHttpSessionConfiguration}.
|
||||
@@ -45,7 +44,6 @@ import static org.mockito.BDDMockito.given;
|
||||
* @author Vedran Pavic
|
||||
* @author Aleksandar Stojsavljevic
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
private static final String MAP_NAME = "spring:test:sessions";
|
||||
@@ -57,19 +55,8 @@ public class HazelcastHttpSessionConfigurationTests {
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
private static HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Mock
|
||||
private IMap<Object, Object> sessions;
|
||||
|
||||
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
given(hazelcastInstance.getMap(isA(String.class))).willReturn(this.sessions);
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
if (this.context != null) {
|
||||
@@ -79,18 +66,17 @@ public class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void noHazelcastInstanceConfiguration() {
|
||||
this.thrown.expect(UnsatisfiedDependencyException.class);
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("HazelcastInstance");
|
||||
|
||||
registerAndRefresh(EmptyConfiguration.class);
|
||||
registerAndRefresh(NoHazelcastInstanceConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultConfiguration() {
|
||||
registerAndRefresh(DefaultConfiguration.class);
|
||||
|
||||
assertThat(this.context.getBean(HazelcastSessionRepository.class))
|
||||
.isNotNull();
|
||||
assertThat(this.context.getBean(HazelcastSessionRepository.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -128,8 +114,8 @@ public class HazelcastHttpSessionConfigurationTests {
|
||||
HazelcastSessionRepository repository = this.context
|
||||
.getBean(HazelcastSessionRepository.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval")).isEqualTo(
|
||||
MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval"))
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,6 +152,70 @@ public class HazelcastHttpSessionConfigurationTests {
|
||||
.isEqualTo(HazelcastFlushMode.IMMEDIATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifiedHazelcastInstanceConfiguration() {
|
||||
registerAndRefresh(QualifiedHazelcastInstanceConfiguration.class);
|
||||
|
||||
HazelcastSessionRepository repository = this.context
|
||||
.getBean(HazelcastSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = this.context
|
||||
.getBean("qualifiedHazelcastInstance", HazelcastInstance.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(hazelcastInstance).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "sessions")).isEqualTo(
|
||||
QualifiedHazelcastInstanceConfiguration.qualifiedHazelcastInstanceSessions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void primaryHazelcastInstanceConfiguration() {
|
||||
registerAndRefresh(PrimaryHazelcastInstanceConfiguration.class);
|
||||
|
||||
HazelcastSessionRepository repository = this.context
|
||||
.getBean(HazelcastSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = this.context
|
||||
.getBean("primaryHazelcastInstance", HazelcastInstance.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(hazelcastInstance).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "sessions")).isEqualTo(
|
||||
PrimaryHazelcastInstanceConfiguration.primaryHazelcastInstanceSessions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifiedAndPrimaryHazelcastInstanceConfiguration() {
|
||||
registerAndRefresh(QualifiedAndPrimaryHazelcastInstanceConfiguration.class);
|
||||
|
||||
HazelcastSessionRepository repository = this.context
|
||||
.getBean(HazelcastSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = this.context
|
||||
.getBean("qualifiedHazelcastInstance", HazelcastInstance.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(hazelcastInstance).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "sessions")).isEqualTo(
|
||||
QualifiedAndPrimaryHazelcastInstanceConfiguration.qualifiedHazelcastInstanceSessions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namedDataSourceConfiguration() {
|
||||
registerAndRefresh(NamedHazelcastInstanceConfiguration.class);
|
||||
|
||||
HazelcastSessionRepository repository = this.context
|
||||
.getBean(HazelcastSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = this.context.getBean("hazelcastInstance",
|
||||
HazelcastInstance.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(hazelcastInstance).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "sessions")).isEqualTo(
|
||||
NamedHazelcastInstanceConfiguration.hazelcastInstanceSessions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleDataSourceConfiguration() {
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("sessionRepository");
|
||||
|
||||
registerAndRefresh(MultipleHazelcastInstanceConfiguration.class);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -173,13 +223,19 @@ public class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession
|
||||
static class EmptyConfiguration {
|
||||
static class NoHazelcastInstanceConfiguration {
|
||||
}
|
||||
|
||||
static class BaseConfiguration {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> defaultHazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
public HazelcastInstance defaultHazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(defaultHazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
@@ -233,8 +289,108 @@ public class HazelcastHttpSessionConfigurationTests {
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession(hazelcastFlushMode = HazelcastFlushMode.IMMEDIATE)
|
||||
static class CustomFlushImmediatelyConfiguration
|
||||
static class CustomFlushImmediatelyConfiguration extends BaseConfiguration {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession
|
||||
static class QualifiedHazelcastInstanceConfiguration extends BaseConfiguration {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> qualifiedHazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@Bean
|
||||
@SpringSessionHazelcastInstance
|
||||
public HazelcastInstance qualifiedHazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(qualifiedHazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession
|
||||
static class PrimaryHazelcastInstanceConfiguration extends BaseConfiguration {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> primaryHazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public HazelcastInstance primaryHazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(primaryHazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession
|
||||
static class QualifiedAndPrimaryHazelcastInstanceConfiguration
|
||||
extends BaseConfiguration {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> qualifiedHazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> primaryHazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@Bean
|
||||
@SpringSessionHazelcastInstance
|
||||
public HazelcastInstance qualifiedHazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(qualifiedHazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public HazelcastInstance primaryHazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(primaryHazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession
|
||||
static class NamedHazelcastInstanceConfiguration extends BaseConfiguration {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> hazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(hazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableHazelcastHttpSession
|
||||
static class MultipleHazelcastInstanceConfiguration extends BaseConfiguration {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static IMap<Object, Object> secondaryHazelcastInstanceSessions = mock(IMap.class);
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance secondaryHazelcastInstance() {
|
||||
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
|
||||
given(hazelcastInstance.getMap(anyString()))
|
||||
.willReturn(secondaryHazelcastInstanceSessions);
|
||||
return hazelcastInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user