Add EnableSpringHttpSession

Fixes gh-231
This commit is contained in:
Rob Winch
2015-08-18 10:11:35 -05:00
parent db45698e25
commit 16b65973b7
7 changed files with 275 additions and 44 deletions

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2002-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.session.config.annotation.web.http;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.session.SessionRepository;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDestroyedEvent;
/**
* Add this annotation to an {@code @Configuration} class to expose the
* SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and
* backed by a user provided implementation of {@link SessionRepository}. In
* order to leverage the annotation, a single {@link SessionRepository} bean
* must be provided. For example:
*
* <pre>
* <code>
* {@literal @Configuration}
* {@literal @EnableSpringHttpSession}
* public class SpringHttpSessionConfig {
*
* {@literal @Bean}
* public MapSessionRepository sessionRepository() {
* return new MapSessionRepository();
* }
*
* }
* </code>
* </pre>
*
* <p>
* It is important to note that no infrastructure for session expirations is
* configured for you out of the box. This is because things like session
* expiration are highly implementation dependent. This means if you require
* cleaning up expired sessions, you are responsible for cleaning up the expired
* sessions.
* </p>
*
* <p>
* The following is provided for you with the base configuration:
* </p>
*
* <ul>
* <li>SessionRepositoryFilter - is responsible for wrapping the
* HttpServletRequest with an implementation of HttpSession that is backed by a
* SessionRepository</li>
* <li>SessionEventHttpSessionListenerAdapter - is responsible for translating
* Spring Session events into HttpSessionEvent. In order for it to work, the
* implementation of SessionRepository you provide must support
* {@link SessionCreatedEvent} and {@link SessionDestroyedEvent}.</li>
* <li>
* </ul>
*
* @author Rob Winch
* @since 1.0
*/
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import(SpringHttpSessionConfiguration.class)
@Configuration
public @interface EnableSpringHttpSession {
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2002-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.session.config.annotation.web.http;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDestroyedEvent;
import org.springframework.session.web.http.HttpSessionStrategy;
import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter;
import org.springframework.session.web.http.SessionRepositoryFilter;
/**
* Configures the basics for setting up Spring Session in a web environment. In
* order to use it, you must provide a {@link SessionRepository}. For example:
*
* <pre>
* {@literal @Configuration}
* {@literal @EnableSpringHttpSession}
* public class SpringHttpSessionConfig {
*
* {@literal @Bean}
* public MapSessionRepository sessionRepository() {
* return new MapSessionRepository();
* }
*
* }
* </pre>
*
* <p>
* It is important to note that no infrastructure for session expirations is
* configured for you out of the box. This is because things like session
* expiration are highly implementation dependent. This means if you require
* cleaning up expired sessions, you are responsible for cleaning up the expired
* sessions.
* </p>
*
* <p>
* The following is provided for you with the base configuration:
* </p>
*
* <ul>
* <li>SessionRepositoryFilter - is responsible for wrapping the
* HttpServletRequest with an implementation of HttpSession that is backed by a
* SessionRepository</li>
* <li>SessionEventHttpSessionListenerAdapter - is responsible for translating
* Spring Session events into HttpSessionEvent. In order for it to work, the
* implementation of SessionRepository you provide must support
* {@link SessionCreatedEvent} and {@link SessionDestroyedEvent}.</li>
* <li>
* </ul>
*
* @author Rob Winch
* @since 1.1
*
* @see EnableSpringHttpSession
*/
@Configuration
@EnableScheduling
public class SpringHttpSessionConfiguration {
private HttpSessionStrategy httpSessionStrategy;
private List<HttpSessionListener> httpSessionListeners = new ArrayList<HttpSessionListener>();
@Bean
public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
return new SessionEventHttpSessionListenerAdapter(httpSessionListeners);
}
@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository, ServletContext servletContext) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
sessionRepositoryFilter.setServletContext(servletContext);
if(httpSessionStrategy != null) {
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
}
return sessionRepositoryFilter;
}
@Autowired(required = false)
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
this.httpSessionStrategy = httpSessionStrategy;
}
@Autowired(required = false)
public void setHttpSessionListeners(List<HttpSessionListener> listeners) {
this.httpSessionListeners = listeners;
}
}

View File

@@ -22,6 +22,7 @@ import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
/**
* Add this annotation to an {@code @Configuration} class to expose the
@@ -29,6 +30,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
* backed by Redis. In order to leverage the annotation, a single {@link RedisConnectionFactory}
* must be provided. For example:
* <pre>
* <code>
* {@literal @Configuration}
* {@literal @EnableRedisHttpSession}
* public class RedisHttpSessionConfig {
@@ -39,12 +41,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
* }
*
* }
* </code>
* </pre>
*
* More advanced configurations can extend {@link RedisHttpSessionConfiguration} instead.
*
* @author Rob Winch
* @since 1.0
* @see EnableSpringHttpSession
*/
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})

View File

@@ -15,14 +15,9 @@
*/
package org.springframework.session.data.redis.config.annotation.web.http;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionListener;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,13 +37,10 @@ import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.web.http.HttpSessionStrategy;
import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -65,25 +57,16 @@ import org.springframework.util.StringUtils;
*/
@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration implements ImportAware, BeanClassLoaderAware {
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration implements ImportAware, BeanClassLoaderAware {
private ClassLoader beanClassLoader;
private Integer maxInactiveIntervalInSeconds = 1800;
private HttpSessionStrategy httpSessionStrategy;
private ConfigureRedisAction configureRedisAction = new ConfigureNotifyKeyspaceEventsAction();
private List<HttpSessionListener> httpSessionListeners = new ArrayList<HttpSessionListener>();
private String redisNamespace = "";
@Bean
public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
return new SessionEventHttpSessionListenerAdapter(httpSessionListeners);
}
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
RedisConnectionFactory connectionFactory, RedisOperationsSessionRepository messageListener) {
@@ -118,16 +101,6 @@ public class RedisHttpSessionConfiguration implements ImportAware, BeanClassLoad
return sessionRepository;
}
@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository, ServletContext servletContext) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
sessionRepositoryFilter.setServletContext(servletContext);
if(httpSessionStrategy != null) {
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
}
return sessionRepositoryFilter;
}
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
@@ -164,16 +137,6 @@ public class RedisHttpSessionConfiguration implements ImportAware, BeanClassLoad
this.redisNamespace = enableAttrs.getString("redisNamespace");
}
@Autowired(required = false)
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
this.httpSessionStrategy = httpSessionStrategy;
}
@Autowired(required = false)
public void setHttpSessionListeners(List<HttpSessionListener> listeners) {
this.httpSessionListeners = listeners;
}
@Bean
public InitializingBean enableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory) {
return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory, configureRedisAction);