Optimize save operation in HazelcastSessionRepository (#516)

This commit improves saving of sessions to only execute save
operation if something has been changed
(e.g. session.setAttribute(String, Object) was called).
Further, configurable flush mode that specifies when to write
to the backing Hazelcast instance is introduced. It can be
'on save' (default) or 'immediate'.

Fixes gh-516, fixes gh-641
This commit is contained in:
Aleksandar Stojsavljevic
2016-09-26 11:49:25 +02:00
committed by Vedran Pavic
parent b5ea6c752d
commit 6a78101db5
7 changed files with 381 additions and 37 deletions

View File

@@ -22,6 +22,7 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.MapSession;
import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession;
import static org.assertj.core.api.Assertions.assertThat;
@@ -41,7 +42,7 @@ public abstract class AbstractHazelcastRepositoryITests {
@Test
public void createAndDestroySession() {
MapSession sessionToSave = this.repository.createSession();
HazelcastSession sessionToSave = this.repository.createSession();
String sessionId = sessionToSave.getId();
IMap<String, MapSession> hazelcastMap = this.hazelcast.getMap(

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2014-2016 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;
import org.springframework.session.SessionRepository;
/**
* Specifies when to write to the backing Hazelcast instance.
*
* @author Aleksandar Stojsavljevic
* @since 1.3
*/
public enum HazelcastFlushMode {
/**
* Only writes to Hazelcast when
* {@link SessionRepository#save(org.springframework.session.Session)} is invoked. In
* a web environment this is typically done as soon as the HTTP response is committed.
*/
ON_SAVE,
/**
* Writes to Hazelcast as soon as possible. For example
* {@link SessionRepository#createSession()} will write the session to Hazelcast. Another
* example is that setting an attribute on the session will also write to Hazelcast
* immediately.
*/
IMMEDIATE
}

View File

@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
@@ -36,8 +37,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.session.ExpiringSession;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
@@ -100,10 +103,11 @@ import org.springframework.util.Assert;
* @author Vedran Pavic
* @author Tommy Ludwig
* @author Mark Anderson
* @author Aleksandar Stojsavljevic
* @since 1.3.0
*/
public class HazelcastSessionRepository implements
FindByIndexNameSessionRepository<MapSession>,
FindByIndexNameSessionRepository<HazelcastSessionRepository.HazelcastSession>,
EntryAddedListener<String, MapSession>,
EntryEvictedListener<String, MapSession>,
EntryRemovedListener<String, MapSession> {
@@ -117,6 +121,8 @@ public class HazelcastSessionRepository implements
private final IMap<String, MapSession> sessions;
private HazelcastFlushMode hazelcastFlushMode = HazelcastFlushMode.ON_SAVE;
private ApplicationEventPublisher eventPublisher = new ApplicationEventPublisher() {
public void publishEvent(ApplicationEvent event) {
@@ -175,20 +181,33 @@ public class HazelcastSessionRepository implements
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
}
public MapSession createSession() {
MapSession result = new MapSession();
/**
* Sets the Hazelcast flush mode. Default flush mode is {@link HazelcastFlushMode#ON_SAVE}.
*
* @param hazelcastFlushMode the new Hazelcast flush mode
*/
public void setHazelcastFlushMode(HazelcastFlushMode hazelcastFlushMode) {
Assert.notNull(hazelcastFlushMode, "HazelcastFlushMode cannot be null");
this.hazelcastFlushMode = hazelcastFlushMode;
}
public HazelcastSession createSession() {
HazelcastSession result = new HazelcastSession();
if (this.defaultMaxInactiveInterval != null) {
result.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval);
}
return result;
}
public void save(MapSession session) {
this.sessions.put(session.getId(), session,
session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
public void save(HazelcastSession session) {
if (session.isChanged()) {
this.sessions.put(session.getId(), session.getDelegate(),
session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
session.markUnchanged();
}
}
public MapSession getSession(String id) {
public HazelcastSession getSession(String id) {
MapSession saved = this.sessions.get(id);
if (saved == null) {
return null;
@@ -197,24 +216,24 @@ public class HazelcastSessionRepository implements
delete(saved.getId());
return null;
}
return saved;
return new HazelcastSession(saved);
}
public void delete(String id) {
this.sessions.remove(id);
}
public Map<String, MapSession> findByIndexNameAndIndexValue(
public Map<String, HazelcastSession> findByIndexNameAndIndexValue(
String indexName, String indexValue) {
if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) {
return Collections.emptyMap();
}
Collection<MapSession> sessions = this.sessions.values(
Predicates.equal(PRINCIPAL_NAME_ATTRIBUTE, indexValue));
Map<String, MapSession> sessionMap = new HashMap<String, MapSession>(
Map<String, HazelcastSession> sessionMap = new HashMap<String, HazelcastSession>(
sessions.size());
for (MapSession session : sessions) {
sessionMap.put(session.getId(), session);
sessionMap.put(session.getId(), new HazelcastSession(session));
}
return sessionMap;
}
@@ -242,4 +261,106 @@ public class HazelcastSessionRepository implements
.publishEvent(new SessionDeletedEvent(this, event.getOldValue()));
}
/**
* A custom implementation of {@link Session} that uses a {@link MapSession} as the
* basis for its mapping. It keeps track if changes have been made since last save.
*
* @author Aleksandar Stojsavljevic
* @since 1.3
*/
final class HazelcastSession implements ExpiringSession {
private final MapSession delegate;
private boolean changed;
/**
* Creates a new instance ensuring to mark all of the new attributes to be
* persisted in the next save operation.
*/
HazelcastSession() {
this(new MapSession());
this.changed = true;
flushImmediateIfNecessary();
}
/**
* Creates a new instance from the provided {@link MapSession}.
*
* @param cached the {@link MapSession} that represents the persisted session that was
* retrieved. Cannot be null.
*/
HazelcastSession(MapSession cached) {
Assert.notNull(cached, "MapSession cannot be null");
this.delegate = cached;
}
public void setLastAccessedTime(long lastAccessedTime) {
this.delegate.setLastAccessedTime(lastAccessedTime);
this.changed = true;
flushImmediateIfNecessary();
}
public boolean isExpired() {
return this.delegate.isExpired();
}
public long getCreationTime() {
return this.delegate.getCreationTime();
}
public String getId() {
return this.delegate.getId();
}
public long getLastAccessedTime() {
return this.delegate.getLastAccessedTime();
}
public void setMaxInactiveIntervalInSeconds(int interval) {
this.delegate.setMaxInactiveIntervalInSeconds(interval);
this.changed = true;
flushImmediateIfNecessary();
}
public int getMaxInactiveIntervalInSeconds() {
return this.delegate.getMaxInactiveIntervalInSeconds();
}
public <T> T getAttribute(String attributeName) {
return this.delegate.getAttribute(attributeName);
}
public Set<String> getAttributeNames() {
return this.delegate.getAttributeNames();
}
public void setAttribute(String attributeName, Object attributeValue) {
this.delegate.setAttribute(attributeName, attributeValue);
this.changed = true;
flushImmediateIfNecessary();
}
public void removeAttribute(String attributeName) {
this.delegate.removeAttribute(attributeName);
this.changed = true;
flushImmediateIfNecessary();
}
boolean isChanged() {
return this.changed;
}
void markUnchanged() {
this.changed = false;
}
MapSession getDelegate() {
return this.delegate;
}
private void flushImmediateIfNecessary() {
if (HazelcastSessionRepository.this.hazelcastFlushMode == HazelcastFlushMode.IMMEDIATE) {
HazelcastSessionRepository.this.save(this);
}
}
}
}

View File

@@ -23,7 +23,9 @@ import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.session.MapSession;
import org.springframework.session.SessionRepository;
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
import org.springframework.session.hazelcast.HazelcastFlushMode;
/**
* Add this annotation to a {@code @Configuration} class to expose the
@@ -48,6 +50,7 @@ import org.springframework.session.config.annotation.web.http.EnableSpringHttpSe
* instead.
*
* @author Tommy Ludwig
* @author Aleksandar Stojsavljevic
* @since 1.1
* @see EnableSpringHttpSession
*/
@@ -73,4 +76,21 @@ public @interface EnableHazelcastHttpSession {
*/
String sessionMapName() default HazelcastHttpSessionConfiguration.DEFAULT_SESSION_MAP_NAME;
/**
* <p>
* Sets the flush mode for the Hazelcast sessions. The default is ON_SAVE which only
* updates the backing Hazelcast when
* {@link SessionRepository#save(org.springframework.session.Session)} is invoked. In
* a web environment this happens just before the HTTP response is committed.
* </p>
* <p>
* Setting the value to IMMEDIATE will ensure that the any updates to the Session are
* immediately written to the Hazelcast instance.
* </p>
*
* @return the {@link HazelcastFlushMode} to use
* @since 1.3
*/
HazelcastFlushMode hazelcastFlushMode() default HazelcastFlushMode.ON_SAVE;
}

View File

@@ -29,6 +29,7 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
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.web.http.SessionRepositoryFilter;
@@ -52,6 +53,8 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
private String sessionMapName = DEFAULT_SESSION_MAP_NAME;
private HazelcastFlushMode hazelcastFlushMode = HazelcastFlushMode.ON_SAVE;
@Bean
public HazelcastSessionRepository sessionRepository(
HazelcastInstance hazelcastInstance,
@@ -63,6 +66,7 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
sessionRepository.setApplicationEventPublisher(eventPublisher);
sessionRepository.setDefaultMaxInactiveInterval(
this.maxInactiveIntervalInSeconds);
sessionRepository.setHazelcastFlushMode(this.hazelcastFlushMode);
return sessionRepository;
}
@@ -73,6 +77,7 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
setMaxInactiveIntervalInSeconds(
(Integer) enableAttrs.getNumber("maxInactiveIntervalInSeconds"));
setSessionMapName(enableAttrs.getString("sessionMapName"));
setHazelcastFlushMode((HazelcastFlushMode) enableAttrs.getEnum("hazelcastFlushMode"));
}
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
@@ -83,4 +88,7 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
this.sessionMapName = sessionMapName;
}
public void setHazelcastFlushMode(HazelcastFlushMode hazelcastFlushMode) {
this.hazelcastFlushMode = hazelcastFlushMode;
}
}

View File

@@ -36,11 +36,13 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -49,6 +51,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
* Tests for {@link HazelcastSessionRepository}.
*
* @author Vedran Pavic
* @author Aleksandar Stojsavljevic
*/
@RunWith(MockitoJUnitRunner.class)
public class HazelcastSessionRepositoryTests {
@@ -78,7 +81,7 @@ public class HazelcastSessionRepositoryTests {
@Test
public void createSessionDefaultMaxInactiveInterval() throws Exception {
MapSession session = this.repository.createSession();
HazelcastSession session = this.repository.createSession();
assertThat(session.getMaxInactiveIntervalInSeconds())
.isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds());
@@ -90,61 +93,167 @@ public class HazelcastSessionRepositoryTests {
int interval = 1;
this.repository.setDefaultMaxInactiveInterval(interval);
MapSession session = this.repository.createSession();
HazelcastSession session = this.repository.createSession();
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(interval);
verifyZeroInteractions(this.sessions);
}
@Test
public void saveNew() {
MapSession session = this.repository.createSession();
public void saveNewFlushModeOnSave() {
HazelcastSession session = this.repository.createSession();
verifyZeroInteractions(this.sessions);
this.repository.save(session);
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session),
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
}
@Test
public void saveUpdatedAttributes() {
MapSession session = new MapSession();
public void saveNewFlushModeImmediate() {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
}
@Test
public void saveUpdatedAttributeFlushModeOnSave() {
HazelcastSession session = this.repository.createSession();
session.setAttribute("testName", "testValue");
verifyZeroInteractions(this.sessions);
this.repository.save(session);
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session),
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
}
@SuppressWarnings("unchecked")
@Test
public void saveUpdatedLastAccessedTime() {
MapSession session = new MapSession();
public void saveUpdatedAttributeFlushModeImmediate() {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
session.setAttribute("testName", "testValue");
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
reset(this.sessions);
this.repository.save(session);
verifyZeroInteractions(this.sessions);
}
@Test
public void removeAttributeFlushModeOnSave() {
HazelcastSession session = this.repository.createSession();
session.removeAttribute("testName");
verifyZeroInteractions(this.sessions);
this.repository.save(session);
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
}
@SuppressWarnings("unchecked")
@Test
public void removeAttributeFlushModeImmediate() {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
session.removeAttribute("testName");
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
reset(this.sessions);
this.repository.save(session);
verifyZeroInteractions(this.sessions);
}
@Test
public void saveUpdatedLastAccessedTimeFlushModeOnSave() {
HazelcastSession session = this.repository.createSession();
session.setLastAccessedTime(System.currentTimeMillis());
verifyZeroInteractions(this.sessions);
this.repository.save(session);
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session),
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
}
@SuppressWarnings("unchecked")
@Test
public void saveUnchanged() {
MapSession session = new MapSession();
public void saveUpdatedLastAccessedTimeFlushModeImmediate() {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
session.setLastAccessedTime(System.currentTimeMillis());
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
reset(this.sessions);
this.repository.save(session);
verifyZeroInteractions(this.sessions);
}
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session),
@Test
public void saveUpdatedMaxInactiveIntervalInSecondsFlushModeOnSave() {
HazelcastSession session = this.repository.createSession();
session.setMaxInactiveIntervalInSeconds(1);
verifyZeroInteractions(this.sessions);
this.repository.save(session);
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
// TODO - once save optimization is implemented, should be replaced with:
//verifyZeroInteractions(this.sessions);
}
@SuppressWarnings("unchecked")
@Test
public void saveUpdatedMaxInactiveIntervalInSecondsFlushModeImmediate() {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
session.setMaxInactiveIntervalInSeconds(1);
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
reset(this.sessions);
this.repository.save(session);
verifyZeroInteractions(this.sessions);
}
@SuppressWarnings("unchecked")
@Test
public void saveUnchangedFlushModeOnSave() {
HazelcastSession session = this.repository.createSession();
this.repository.save(session);
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
reset(this.sessions);
this.repository.save(session);
verifyZeroInteractions(this.sessions);
}
@SuppressWarnings("unchecked")
@Test
public void saveUnchangedFlushModeImmediate() {
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
HazelcastSession session = this.repository.createSession();
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
isA(Long.class), eq(TimeUnit.SECONDS));
reset(this.sessions);
this.repository.save(session);
verifyZeroInteractions(this.sessions);
}
@Test
public void getSessionNotFound() {
String sessionId = "testSessionId";
MapSession session = this.repository.getSession(sessionId);
HazelcastSession session = this.repository.getSession(sessionId);
assertThat(session).isNull();
verify(this.sessions, times(1)).get(eq(sessionId));
@@ -157,7 +266,7 @@ public class HazelcastSessionRepositoryTests {
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
given(this.sessions.get(eq(expired.getId()))).willReturn(expired);
MapSession session = this.repository.getSession(expired.getId());
HazelcastSession session = this.repository.getSession(expired.getId());
assertThat(session).isNull();
verify(this.sessions, times(1)).get(eq(expired.getId()));
@@ -170,7 +279,7 @@ public class HazelcastSessionRepositoryTests {
saved.setAttribute("savedName", "savedValue");
given(this.sessions.get(eq(saved.getId()))).willReturn(saved);
MapSession session = this.repository.getSession(saved.getId());
HazelcastSession session = this.repository.getSession(saved.getId());
assertThat(session.getId()).isEqualTo(saved.getId());
assertThat(session.getAttribute("savedName")).isEqualTo("savedValue");
@@ -190,7 +299,7 @@ public class HazelcastSessionRepositoryTests {
public void findByIndexNameAndIndexValueUnknownIndexName() {
String indexValue = "testIndexValue";
Map<String, MapSession> sessions = this.repository.findByIndexNameAndIndexValue(
Map<String, HazelcastSession> sessions = this.repository.findByIndexNameAndIndexValue(
"testIndexName", indexValue);
assertThat(sessions).isEmpty();
@@ -201,7 +310,7 @@ public class HazelcastSessionRepositoryTests {
public void findByIndexNameAndIndexValuePrincipalIndexNameNotFound() {
String principal = "username";
Map<String, MapSession> sessions = this.repository.findByIndexNameAndIndexValue(
Map<String, HazelcastSession> sessions = this.repository.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal);
assertThat(sessions).isEmpty();
@@ -222,7 +331,7 @@ public class HazelcastSessionRepositoryTests {
saved.add(saved2);
given(this.sessions.values(isA(EqualPredicate.class))).willReturn(saved);
Map<String, MapSession> sessions = this.repository.findByIndexNameAndIndexValue(
Map<String, HazelcastSession> sessions = this.repository.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal);
assertThat(sessions).hasSize(2);

View File

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.hazelcast.HazelcastFlushMode;
import org.springframework.session.hazelcast.HazelcastSessionRepository;
import org.springframework.test.util.ReflectionTestUtils;
@@ -42,6 +43,7 @@ import static org.mockito.Matchers.isA;
* Tests for {@link HazelcastHttpSessionConfiguration}.
*
* @author Vedran Pavic
* @author Aleksandar Stojsavljevic
*/
@RunWith(MockitoJUnitRunner.class)
public class HazelcastHttpSessionConfigurationTests {
@@ -50,6 +52,8 @@ public class HazelcastHttpSessionConfigurationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600;
private static final HazelcastFlushMode HAZELCAST_FLUSH_MODE = HazelcastFlushMode.IMMEDIATE;
@Rule
public final ExpectedException thrown = ExpectedException.none();
@@ -139,6 +143,29 @@ public class HazelcastHttpSessionConfigurationTests {
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
@Test
public void customFlushImmediately() {
registerAndRefresh(CustomFlushImmediatelyConfiguration.class);
HazelcastSessionRepository repository = this.context
.getBean(HazelcastSessionRepository.class);
assertThat(repository).isNotNull();
assertThat(ReflectionTestUtils.getField(repository, "hazelcastFlushMode")).isEqualTo(
HazelcastFlushMode.IMMEDIATE);
}
@Test
public void setCustomFlushImmediately() {
registerAndRefresh(BaseConfiguration.class,
CustomFlushImmediatelySetConfiguration.class);
HazelcastSessionRepository repository = this.context
.getBean(HazelcastSessionRepository.class);
assertThat(repository).isNotNull();
assertThat(ReflectionTestUtils.getField(repository, "hazelcastFlushMode")).isEqualTo(
HazelcastFlushMode.IMMEDIATE);
}
private void registerAndRefresh(Class<?>... annotatedClasses) {
this.context.register(annotatedClasses);
this.context.refresh();
@@ -194,4 +221,20 @@ public class HazelcastHttpSessionConfigurationTests {
extends BaseConfiguration {
}
@Configuration
static class CustomFlushImmediatelySetConfiguration
extends HazelcastHttpSessionConfiguration {
CustomFlushImmediatelySetConfiguration() {
setHazelcastFlushMode(HAZELCAST_FLUSH_MODE);
}
}
@Configuration
@EnableHazelcastHttpSession(hazelcastFlushMode = HazelcastFlushMode.IMMEDIATE)
static class CustomFlushImmediatelyConfiguration
extends BaseConfiguration {
}
}