diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index 861567a67f..ce883887b9 100644
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -400,6 +400,11 @@
spring-security-jwt
true
+
+ org.springframework.session
+ spring-session
+ true
+
org.springframework.amqp
spring-rabbit
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
new file mode 100644
index 0000000000..e2a0aae66f
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012-2015 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 javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+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.redis.RedisAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.session.Session;
+import org.springframework.session.data.redis.RedisOperationsSessionRepository;
+import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
+import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Spring Session.
+ *
+ * @author Andy Wilkinson
+ * @since 1.3.0
+ */
+@Configuration
+@ConditionalOnClass(Session.class)
+@EnableConfigurationProperties(ServerProperties.class)
+@AutoConfigureAfter(RedisAutoConfiguration.class)
+public class SessionAutoConfiguration {
+
+ @ConditionalOnClass(RedisConnectionFactory.class)
+ @ConditionalOnWebApplication
+ @ConditionalOnMissingBean(RedisHttpSessionConfiguration.class)
+ @EnableRedisHttpSession
+ @Configuration
+ public static class SessionRedisHttpConfiguration {
+
+ @Autowired
+ private ServerProperties serverProperties;
+
+ @Autowired
+ private RedisOperationsSessionRepository sessionRepository;
+
+ @PostConstruct
+ public void applyConfigurationProperties() {
+ if (this.serverProperties.getSessionTimeout() != null) {
+ this.sessionRepository
+ .setDefaultMaxInactiveInterval(this.serverProperties
+ .getSessionTimeout());
+ }
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index 13070919f3..171256c361 100644
--- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -53,6 +53,7 @@ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
+org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index e5f1c8d900..a4b99d4ff8 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -135,6 +135,7 @@
4.0.1.RELEASE
1.0.3.RELEASE
2.0.7.RELEASE
+ 1.0.1.RELEASE
1.1.2.RELEASE
2.0.1.RELEASE
1.0.1.RELEASE
@@ -1695,6 +1696,11 @@
spring-security-oauth2
${spring-security-oauth.version}
+
+ org.springframework.session
+ spring-session
+ ${spring-session.version}
+
org.springframework.social
spring-social-config
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 cdb04b88a3..7abe2979ce 100644
--- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -2812,6 +2812,16 @@ class for more details.
+[[boot-features-session]]
+== Spring Session
+Spring Session provides support for managing a user's session information. If you are
+writing a web application and Spring Session and Spring Data Redis are both on the
+classpath, Spring Boot will auto-configure Spring Session through its
+`@EnableRedisHttpSession`. Session data will be stored in Redis and the session timeout
+can be configured using the `server.session-timeout` property.
+
+
+
[[boot-features-jmx]]
== Monitoring and management over JMX
Java Management Extensions (JMX) provide a standard mechanism to monitor and manage
diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml
index 86da1a0274..fa65e4bc82 100644
--- a/spring-boot-samples/pom.xml
+++ b/spring-boot-samples/pom.xml
@@ -62,6 +62,7 @@
spring-boot-sample-secure
spring-boot-sample-secure-oauth2
spring-boot-sample-servlet
+ spring-boot-sample-session-redis
spring-boot-sample-simple
spring-boot-sample-testng
spring-boot-sample-tomcat
diff --git a/spring-boot-samples/spring-boot-sample-session-redis/pom.xml b/spring-boot-samples/spring-boot-sample-session-redis/pom.xml
new file mode 100644
index 0000000000..18525dbbca
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-session-redis/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ 1.3.0.BUILD-SNAPSHOT
+
+ spring-boot-sample-session-redis
+ Spring Boot Session Redis Sample
+ Spring Boot Session Redis Sample
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-redis
+
+
+ org.springframework.session
+ spring-session
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-session-redis/src/main/java/sample/session/redis/SampleSessionRedisApplication.java b/spring-boot-samples/spring-boot-sample-session-redis/src/main/java/sample/session/redis/SampleSessionRedisApplication.java
new file mode 100644
index 0000000000..cb52020687
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-session-redis/src/main/java/sample/session/redis/SampleSessionRedisApplication.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012-2015 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 sample.session.redis;
+
+import java.util.UUID;
+
+import javax.servlet.http.HttpSession;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+public class SampleSessionRedisApplication {
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(SampleSessionRedisApplication.class);
+ }
+
+ @RestController
+ static class HelloRestController {
+
+ @RequestMapping("/")
+ String uid(HttpSession session) {
+ UUID uid = (UUID) session.getAttribute("uid");
+ if (uid == null) {
+ uid = UUID.randomUUID();
+ }
+ session.setAttribute("uid", uid);
+ return uid.toString();
+ }
+ }
+}
diff --git a/spring-boot-samples/spring-boot-sample-session-redis/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-session-redis/src/main/resources/application.properties
new file mode 100644
index 0000000000..3ccb651442
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-session-redis/src/main/resources/application.properties
@@ -0,0 +1 @@
+server.session-timeout: 5
\ No newline at end of file
diff --git a/spring-boot-samples/spring-boot-sample-session-redis/src/test/java/sample/session/redis/SampleSessionRedisApplicationTests.java b/spring-boot-samples/spring-boot-sample-session-redis/src/test/java/sample/session/redis/SampleSessionRedisApplicationTests.java
new file mode 100644
index 0000000000..c7a8501ade
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-session-redis/src/test/java/sample/session/redis/SampleSessionRedisApplicationTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012-2015 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 sample.session.redis;
+
+import java.net.URI;
+
+import org.junit.Test;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.data.redis.RedisConnectionFailureException;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests for {@link SampleSessionRedisApplication}.
+ *
+ * @author Andy Wilkinson
+ */
+public class SampleSessionRedisApplicationTests {
+
+ @Test
+ public void sessionExpiry() throws Exception {
+
+ String port = null;
+
+ try {
+ ConfigurableApplicationContext context = new SpringApplicationBuilder()
+ .sources(SampleSessionRedisApplication.class)
+ .properties("server.port:0")
+ .initializers(new ServerPortInfoApplicationContextInitializer())
+ .run();
+ port = context.getEnvironment().getProperty("local.server.port");
+ }
+ catch (RuntimeException ex) {
+ if (!redisServerRunning(ex)) {
+ return;
+ }
+ }
+
+ URI uri = URI.create("http://localhost:" + port + "/");
+ RestTemplate restTemplate = new RestTemplate();
+
+ ResponseEntity response = restTemplate.getForEntity(uri, String.class);
+ String uuid1 = response.getBody();
+ HttpHeaders requestHeaders = new HttpHeaders();
+ requestHeaders.set("Cookie", response.getHeaders().getFirst("Set-Cookie"));
+
+ RequestEntity request = new RequestEntity(requestHeaders,
+ HttpMethod.GET, uri);
+
+ String uuid2 = restTemplate.exchange(request, String.class).getBody();
+ assertThat(uuid1, is(equalTo(uuid2)));
+
+ Thread.sleep(5000);
+
+ String uuid3 = restTemplate.exchange(request, String.class).getBody();
+ assertThat(uuid2, is(not(equalTo(uuid3))));
+ }
+
+ private boolean redisServerRunning(Throwable ex) {
+ if (ex instanceof RedisConnectionFailureException) {
+ return false;
+ }
+ return (ex.getCause() == null || redisServerRunning(ex.getCause()));
+ }
+
+}