Create spring-boot-session modules
This commit is contained in:
committed by
Phillip Webb
parent
014240d576
commit
e288c81b7b
@@ -0,0 +1,27 @@
|
||||
plugins {
|
||||
id "java-library"
|
||||
id "org.springframework.boot.auto-configuration"
|
||||
id "org.springframework.boot.configuration-properties"
|
||||
id "org.springframework.boot.deployed"
|
||||
id "org.springframework.boot.optional-dependencies"
|
||||
}
|
||||
|
||||
description = "Spring Boot Session Hazelcast"
|
||||
|
||||
dependencies {
|
||||
api(project(":spring-boot-project:spring-boot"))
|
||||
api(project(":spring-boot-project:spring-boot-session"))
|
||||
api("org.springframework.session:spring-session-hazelcast")
|
||||
|
||||
implementation(project(":spring-boot-project:spring-boot-hazelcast"))
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
|
||||
testImplementation(project(":spring-boot-project:spring-boot-test"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
||||
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-session")))
|
||||
testImplementation("jakarta.servlet:jakarta.servlet-api")
|
||||
testImplementation("org.springframework:spring-web")
|
||||
|
||||
testRuntimeOnly("ch.qos.logback:logback-classic")
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.session.hazelcast.autoconfigure;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;
|
||||
import org.springframework.boot.session.autoconfigure.SessionProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
import org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Session Hazelcast.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration(before = SessionAutoConfiguration.class)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass(HazelcastIndexedSessionRepository.class)
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@ConditionalOnBean(HazelcastInstance.class)
|
||||
@EnableConfigurationProperties({ HazelcastSessionProperties.class, ServerProperties.class, SessionProperties.class })
|
||||
@Import(HazelcastHttpSessionConfiguration.class)
|
||||
public class HazelcastSessionAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
SessionRepositoryCustomizer<HazelcastIndexedSessionRepository> springBootSessionRepositoryCustomizer(
|
||||
SessionProperties sessionProperties, HazelcastSessionProperties hazelcastSessionProperties,
|
||||
ServerProperties serverProperties) {
|
||||
return (sessionRepository) -> {
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(sessionProperties.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
|
||||
.to(sessionRepository::setDefaultMaxInactiveInterval);
|
||||
map.from(hazelcastSessionProperties::getMapName).to(sessionRepository::setSessionMapName);
|
||||
map.from(hazelcastSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);
|
||||
map.from(hazelcastSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.session.hazelcast.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.SaveMode;
|
||||
|
||||
/**
|
||||
* Configuration properties for Hazelcast backed Spring Session.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.session.hazelcast")
|
||||
public class HazelcastSessionProperties {
|
||||
|
||||
/**
|
||||
* Name of the map used to store sessions.
|
||||
*/
|
||||
private String mapName = "spring:session:sessions";
|
||||
|
||||
/**
|
||||
* Sessions flush mode. Determines when session changes are written to the session
|
||||
* store.
|
||||
*/
|
||||
private FlushMode flushMode = FlushMode.ON_SAVE;
|
||||
|
||||
/**
|
||||
* Sessions save mode. Determines how session changes are tracked and saved to the
|
||||
* session store.
|
||||
*/
|
||||
private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
|
||||
|
||||
public String getMapName() {
|
||||
return this.mapName;
|
||||
}
|
||||
|
||||
public void setMapName(String mapName) {
|
||||
this.mapName = mapName;
|
||||
}
|
||||
|
||||
public FlushMode getFlushMode() {
|
||||
return this.flushMode;
|
||||
}
|
||||
|
||||
public void setFlushMode(FlushMode flushMode) {
|
||||
this.flushMode = flushMode;
|
||||
}
|
||||
|
||||
public SaveMode getSaveMode() {
|
||||
return this.saveMode;
|
||||
}
|
||||
|
||||
public void setSaveMode(SaveMode saveMode) {
|
||||
this.saveMode = saveMode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Spring Session Hazelcast.
|
||||
*/
|
||||
package org.springframework.boot.session.hazelcast.autoconfigure;
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"groups": [],
|
||||
"properties": []
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.session.hazelcast.autoconfigure.HazelcastSessionAutoConfiguration
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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
|
||||
*
|
||||
* https://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.session.hazelcast.autoconfigure;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.session.autoconfigure.AbstractSessionAutoConfigurationTests;
|
||||
import org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link HazelcastSessionAutoConfiguration}.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
class HazelcastSessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@BeforeEach
|
||||
void prepareContextRunner() {
|
||||
this.contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(SessionAutoConfiguration.class, HazelcastSessionAutoConfiguration.class))
|
||||
.withUserConfiguration(HazelcastConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
new ServerProperties().getServlet().getSession().getTimeout());
|
||||
HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);
|
||||
then(hazelcastInstance).should().getMap("spring:session:sessions");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customMapName() {
|
||||
this.contextRunner.withPropertyValues("spring.session.hazelcast.map-name=foo:bar:biz").run((context) -> {
|
||||
validateSessionRepository(context, HazelcastIndexedSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);
|
||||
then(hazelcastInstance).should().getMap("foo:bar:biz");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customFlushMode() {
|
||||
this.contextRunner.withPropertyValues("spring.session.hazelcast.flush-mode=immediate").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSaveMode() {
|
||||
this.contextRunner.withPropertyValues("spring.session.hazelcast.save-mode=on-get-attribute").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheUserDefinesTheirOwnSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {
|
||||
this.contextRunner.withUserConfiguration(CustomizerConfiguration.class)
|
||||
.withPropertyValues("spring.session.hazelcast.save-mode=on-get-attribute")
|
||||
.run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ALWAYS);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class HazelcastConfiguration {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
HazelcastInstance hazelcastInstance() {
|
||||
IMap<Object, Object> map = mock(IMap.class);
|
||||
HazelcastInstance mock = mock(HazelcastInstance.class);
|
||||
given(mock.getMap("spring:session:sessions")).willReturn(map);
|
||||
given(mock.getMap("foo:bar:biz")).willReturn(map);
|
||||
return mock;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
SessionRepositoryCustomizer<HazelcastIndexedSessionRepository> sessionRepositoryCustomizer() {
|
||||
return (repository) -> repository.setSaveMode(SaveMode.ALWAYS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user