From c00a42f437258e4b59e37ced1adc9cf82856d64e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 21 Sep 2017 12:43:18 +0100 Subject: [PATCH] Add auto-configuration for separate Spring Session Data MongoDB module Closes gh-9552 --- spring-boot-autoconfigure/pom.xml | 5 + .../session/MongoSessionConfiguration.java | 58 ++++++++++++ .../session/MongoSessionProperties.java | 43 +++++++++ .../session/SessionAutoConfiguration.java | 4 +- .../session/SessionStoreMappings.java | 1 + .../boot/autoconfigure/session/StoreType.java | 5 + .../SessionAutoConfigurationJdbcTests.java | 2 + .../SessionAutoConfigurationMongoTests.java | 91 +++++++++++++++++++ .../SessionAutoConfigurationRedisTests.java | 4 +- spring-boot-dependencies/pom.xml | 6 ++ .../appendix-application-properties.adoc | 3 + .../main/asciidoc/spring-boot-features.adoc | 1 + 12 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionProperties.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index a8e7c79bd66..75e92bd158d 100755 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -527,6 +527,11 @@ spring-session-core true + + org.springframework.session + spring-session-data-mongodb + true + org.springframework.session spring-session-data-redis diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java new file mode 100644 index 00000000000..af47de8d70d --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionConfiguration.java @@ -0,0 +1,58 @@ +/* + * 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.session; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.session.SessionRepository; +import org.springframework.session.data.mongo.config.annotation.web.http.MongoHttpSessionConfiguration; + +/** + * Mongo-backed session configuration. + * + * @author EddĂș MelĂ©ndez + * @author Stephane Nicoll + */ +@Configuration +@ConditionalOnMissingBean(SessionRepository.class) +@ConditionalOnBean(MongoOperations.class) +@Conditional(SessionCondition.class) +@EnableConfigurationProperties(MongoSessionProperties.class) +class MongoSessionConfiguration { + + @Configuration + public static class SpringBootMongoHttpSessionConfiguration + extends MongoHttpSessionConfiguration { + + @Autowired + public void customize(SessionProperties sessionProperties, + MongoSessionProperties mongoSessionProperties) { + Integer timeout = sessionProperties.getTimeout(); + if (timeout != null) { + setMaxInactiveIntervalInSeconds(timeout); + } + setCollectionName(mongoSessionProperties.getCollectionName()); + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionProperties.java new file mode 100644 index 00000000000..929caa9c1eb --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/MongoSessionProperties.java @@ -0,0 +1,43 @@ +/* + * 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.session; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Mongo-backed Spring Session. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +@ConfigurationProperties(prefix = "spring.session.mongo") +public class MongoSessionProperties { + + /** + * Collection name used to store sessions. + */ + private String collectionName = "sessions"; + + public String getCollectionName() { + return this.collectionName; + } + + public void setCollectionName(String collectionName) { + this.collectionName = collectionName; + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java index bd9d894d018..803728342ec 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration.SessionRepositoryConfiguration; import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration.SessionRepositoryValidator; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -58,7 +59,8 @@ import org.springframework.session.SessionRepository; @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(SessionProperties.class) @AutoConfigureAfter({ DataSourceAutoConfiguration.class, HazelcastAutoConfiguration.class, - JdbcTemplateAutoConfiguration.class, RedisAutoConfiguration.class }) + JdbcTemplateAutoConfiguration.class, MongoAutoConfiguration.class, + RedisAutoConfiguration.class }) @Import({ SessionRepositoryConfiguration.class, SessionRepositoryValidator.class, SessionRepositoryFilterConfiguration.class }) public class SessionAutoConfiguration { diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java index ee4617f8c28..a7961e1e9bc 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java @@ -35,6 +35,7 @@ final class SessionStoreMappings { static { Map> mappings = new HashMap<>(); mappings.put(StoreType.REDIS, RedisSessionConfiguration.class); + mappings.put(StoreType.MONGO, MongoSessionConfiguration.class); mappings.put(StoreType.JDBC, JdbcSessionConfiguration.class); mappings.put(StoreType.HAZELCAST, HazelcastSessionConfiguration.class); mappings.put(StoreType.NONE, NoOpSessionConfiguration.class); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java index 5ba79625f52..4272519a8c3 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/StoreType.java @@ -31,6 +31,11 @@ public enum StoreType { */ REDIS, + /** + * Mongo backed sessions. + */ + MONGO, + /** * JDBC backed sessions. */ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java index 34b2a37c6bd..aa031e57410 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java @@ -32,6 +32,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.session.data.mongo.MongoOperationsSessionRepository; import org.springframework.session.data.redis.RedisOperationsSessionRepository; import org.springframework.session.hazelcast.HazelcastSessionRepository; import org.springframework.session.jdbc.JdbcOperationsSessionRepository; @@ -69,6 +70,7 @@ public class SessionAutoConfigurationJdbcTests this.contextRunner .withClassLoader( new HideClassesClassLoader(HazelcastSessionRepository.class, + MongoOperationsSessionRepository.class, RedisOperationsSessionRepository.class)) .withConfiguration( AutoConfigurations.of(JdbcTemplateAutoConfiguration.class)) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java new file mode 100644 index 00000000000..593779b81aa --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationMongoTests.java @@ -0,0 +1,91 @@ +/* + * 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.session; + +import org.junit.Test; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration; +import org.springframework.boot.test.context.HideClassesClassLoader; +import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; +import org.springframework.boot.test.context.runner.ContextConsumer; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.session.data.mongo.MongoOperationsSessionRepository; +import org.springframework.session.data.redis.RedisOperationsSessionRepository; +import org.springframework.session.hazelcast.HazelcastSessionRepository; +import org.springframework.session.jdbc.JdbcOperationsSessionRepository; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Mongo-specific tests for {@link SessionAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class SessionAutoConfigurationMongoTests + extends AbstractSessionAutoConfigurationTests { + + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class)); + + @Test + public void defaultConfig() { + this.contextRunner.withPropertyValues("spring.session.store-type=mongo") + .withConfiguration(AutoConfigurations.of( + EmbeddedMongoAutoConfiguration.class, + MongoAutoConfiguration.class, MongoDataAutoConfiguration.class)) + .run(validateSpringSessionUsesMongo("sessions")); + } + + @Test + public void defaultConfigWithUniqueStoreImplementation() { + this.contextRunner + .withClassLoader( + new HideClassesClassLoader(HazelcastSessionRepository.class, + JdbcOperationsSessionRepository.class, + RedisOperationsSessionRepository.class)) + .withConfiguration(AutoConfigurations.of( + EmbeddedMongoAutoConfiguration.class, + MongoAutoConfiguration.class, MongoDataAutoConfiguration.class)) + .run(validateSpringSessionUsesMongo("sessions")); + } + + @Test + public void mongoSessionStoreWithCustomizations() { + this.contextRunner + .withConfiguration(AutoConfigurations.of( + EmbeddedMongoAutoConfiguration.class, + MongoAutoConfiguration.class, MongoDataAutoConfiguration.class)) + .withPropertyValues("spring.session.store-type=mongo", + "spring.session.mongo.collection-name=foo") + .run(validateSpringSessionUsesMongo("foo")); + } + + private ContextConsumer validateSpringSessionUsesMongo( + String collectionName) { + return (context) -> { + MongoOperationsSessionRepository repository = validateSessionRepository( + context, MongoOperationsSessionRepository.class); + assertThat(new DirectFieldAccessor(repository) + .getPropertyValue("collectionName")).isEqualTo(collectionName); + }; + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java index c330fc68812..bca24554094 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java @@ -27,6 +27,7 @@ import org.springframework.boot.test.context.assertj.AssertableWebApplicationCon import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.testsupport.rule.RedisTestServer; +import org.springframework.session.data.mongo.MongoOperationsSessionRepository; import org.springframework.session.data.redis.RedisFlushMode; import org.springframework.session.data.redis.RedisOperationsSessionRepository; import org.springframework.session.hazelcast.HazelcastSessionRepository; @@ -61,7 +62,8 @@ public class SessionAutoConfigurationRedisTests this.contextRunner .withClassLoader( new HideClassesClassLoader(HazelcastSessionRepository.class, - JdbcOperationsSessionRepository.class)) + JdbcOperationsSessionRepository.class, + MongoOperationsSessionRepository.class)) .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) .run(validateSpringSessionUsesRedis("spring:session:event:created:", RedisFlushMode.ON_SAVE)); diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 07ecd329641..1daf8a88a42 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -174,6 +174,7 @@ 1.2.1.RELEASE 5.0.0.M4 2.0.0.M4 + 2.0.0.M3 2.0.0.M4 3.0.0.M3 2.0.0.M3 @@ -2402,6 +2403,11 @@ spring-session-data-redis ${spring-session.version} + + org.springframework.session + spring-session-data-mongodb + ${spring-session-data-mongodb.version} + org.springframework.session spring-session-hazelcast diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 4f250a1c428..ee4bc501477 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -427,6 +427,9 @@ content into your application; rather pick only the properties that you need. spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.session.jdbc.table-name=SPRING_SESSION # Name of database table used to store sessions. + # SPRING SESSION MONGO ({sc-spring-boot-autoconfigure}/session/MonogoSessionProperties.{sc-ext}[MongoSessionProperties]) + spring.session.mongo.collection-name=sessions # Collection name used to store sessions. + # SPRING SESSION REDIS ({sc-spring-boot-autoconfigure}/session/RedisSessionProperties.{sc-ext}[RedisSessionProperties]) spring.session.redis.flush-mode=on-save # Sessions flush mode. spring.session.redis.namespace= # Namespace for keys used to store sessions. diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 513c9693075..82a3b61b7d6 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5364,6 +5364,7 @@ classes for more details. Spring Boot provides Spring Session auto-configuration for a wide range of stores: * JDBC +* MongoDB * Redis * Hazelcast