9. API Documentation

You can browse the complete Javadoc online. The key APIs are described below:

9.1 Session

A Session is a simplified Map of name value pairs.

Typical usage might look like the following:

public class RepositoryDemo<S extends Session> {
	private SessionRepository<S> repository; (1)

	public void demo() {
		S toSave = this.repository.createSession(); (2)

		(3)
		User rwinch = new User("rwinch");
		toSave.setAttribute(ATTR_USER, rwinch);

		this.repository.save(toSave); (4)

		S session = this.repository.findById(toSave.getId()); (5)

		(6)
		User user = session.getAttribute(ATTR_USER);
		assertThat(user).isEqualTo(rwinch);
	}

	// ... setter methods ...
}
  • (1) We create a SessionRepository instance with a generic type, S , that extends Session . The generic type is defined in our class.
  • (2) We create a new Session using our SessionRepository and assign it to a variable of type S .
  • (3) We interact with the Session . In our example, we demonstrate saving a User to the Session .
  • (4) We now save the Session . This is why we needed the generic type S . The SessionRepository only allows saving Session instances that were created or retrieved using the same SessionRepository . This allows for the SessionRepository to make implementation specific optimizations (i.e. only writing attributes that have changed).
  • (5) We retrieve the Session from the SessionRepository .
  • (6) We obtain the persisted User from our Session without the need for explicitly casting our attribute.

Session API also provides attributes related to the Session instance’s expiration.

Typical usage might look like the following:

public class ExpiringRepositoryDemo<S extends Session> {
	private SessionRepository<S> repository; (1)

	public void demo() {
		S toSave = this.repository.createSession(); (2)
		// ...
		toSave.setMaxInactiveInterval(Duration.ofSeconds(30)); (3)

		this.repository.save(toSave); (4)

		S session = this.repository.findById(toSave.getId()); (5)
		// ...
	}

	// ... setter methods ...
}
  • (1) We create a SessionRepository instance with a generic type, S , that extends Session . The generic type is defined in our class.
  • (2) We create a new Session using our SessionRepository and assign it to a variable of type S .
  • (3) We interact with the Session . In our example, we demonstrate updating the amount of time the Session can be inactive before it expires.
  • (4) We now save the Session . This is why we needed the generic type S . The SessionRepository only allows saving Session instances that were created or retrieved using the same SessionRepository . This allows for the SessionRepository to make implementation specific optimizations (i.e. only writing attributes that have changed). The last accessed time is automatically updated when the Session is saved.
  • (5) We retrieve the Session from the SessionRepository . If the Session were expired, the result would be null.

9.2 SessionRepository

A SessionRepository is in charge of creating, retrieving, and persisting Session instances.

If possible, developers should not interact directly with a SessionRepository or a Session . Instead, developers should prefer interacting with SessionRepository and Session indirectly through the HttpSession and WebSocket integration.

9.3 FindByIndexNameSessionRepository

Spring Session’s most basic API for using a Session is the SessionRepository . This API is intentionally very simple, so that it is easy to provide additional implementations with basic functionality.

Some SessionRepository implementations may choose to implement FindByIndexNameSessionRepository also. For example, Spring’s Redis, JDBC and Hazelcast support all implement FindByIndexNameSessionRepository .

The FindByIndexNameSessionRepository provides a method to look up all the sessions with a given index name and index value. As a common use case that is supported by all provided FindByIndexNameSessionRepository implementations, there’s a convenient method to look up all the sessions for a particular user. This is done by ensuring that the session attribute with the name FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME is populated with the username. It is the responsibility of the developer to ensure the attribute is populated since Spring Session is not aware of the authentication mechanism being used. An example of how this might be used can be seen below:

String username = "username";
this.session.setAttribute(
		FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);

Note

Some implementations of FindByIndexNameSessionRepository will provide hooks to automatically index other session attributes. For example, many implementations will automatically ensure the current Spring Security user name is indexed with the index name FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME .

Once the session is indexed, it can be found using the following:

String username = "username";
Map<String, Session> sessionIdToSession = this.sessionRepository
		.findByPrincipalName(username);

9.4 ReactiveSessionRepository

A ReactiveSessionRepository is in charge of creating, retrieving, and persisting Session instances in a non-blocking and reactive manner.

If possible, developers should not interact directly with a ReactiveSessionRepository or a Session . Instead, developers should prefer interacting with ReactiveSessionRepository and Session indirectly through the WebSession integration.

9.5 EnableSpringHttpSession

The @EnableSpringHttpSession annotation can be added to an @Configuration class to expose the SessionRepositoryFilter as a bean named "springSessionRepositoryFilter". In order to leverage the annotation, a single SessionRepository bean must be provided. For example:

@EnableSpringHttpSession
@Configuration
public class SpringHttpSessionConfig {
	@Bean
	public MapSessionRepository sessionRepository() {
		return new MapSessionRepository(new ConcurrentHashMap<>());
	}
}

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.

9.6 EnableSpringWebSession

The @EnableSpringWebSession annotation can be added to an @Configuration class to expose the WebSessionManager as a bean named "webSessionManager". In order to leverage the annotation, a single ReactiveSessionRepository bean must be provided. For example:

@EnableSpringWebSession
public class SpringWebSessionConfig {
	@Bean
	public ReactiveSessionRepository reactiveSessionRepository() {
		return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
	}
}

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.

9.7 RedisOperationsSessionRepository

RedisOperationsSessionRepository is a SessionRepository that is implemented using Spring Data’s RedisOperations . In a web environment, this is typically used in combination with SessionRepositoryFilter . The implementation supports SessionDestroyedEvent and SessionCreatedEvent through SessionMessageListener .

9.7.1 Instantiating a RedisOperationsSessionRepository

A typical example of how to create a new instance can be seen below:

RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

// ... configure redisTemplate ...

SessionRepository<? extends Session> repository =
		new RedisOperationsSessionRepository(redisTemplate);

For additional information on how to create a RedisConnectionFactory , refer to the Spring Data Redis Reference.

9.7.2 EnableRedisHttpSession

In a web environment, the simplest way to create a new RedisOperationsSessionRepository is to use @EnableRedisHttpSession . Complete example usage can be found in the Chapter 3, Samples and Guides (Start Here) You can use the following attributes to customize the configuration:

  • maxInactiveIntervalInSeconds - the amount of time before the session will expire in seconds

  • redisNamespace - allows configuring an application specific namespace for the sessions. Redis keys and channel IDs will start with the prefix of <redisNamespace>: .

  • redisFlushMode - allows specifying when data will be written to Redis. The default is only when save is invoked on SessionRepository . A value of RedisFlushMode.IMMEDIATE will write to Redis as soon as possible.

Custom RedisSerializer

You can customize the serialization by creating a Bean named springSessionDefaultRedisSerializer that implements RedisSerializer<Object> .

9.7.3 Redis TaskExecutor

RedisOperationsSessionRepository is subscribed to receive events from redis using a RedisMessageListenerContainer . You can customize the way those events are dispatched, by creating a Bean named springSessionRedisTaskExecutor and/or a Bean springSessionRedisSubscriptionExecutor . More details on configuring redis task executors can be found here.

9.7.4 Storage Details

The sections below outline how Redis is updated for each operation. An example of creating a new session can be found below. The subsequent sections describe the details.

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \
	maxInactiveInterval 1800 \
	lastAccessedTime 1404360000000 \
	sessionAttr:attrName someAttrValue \
	sessionAttr2:attrName someAttrValue2
EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
EXPIRE spring:session:expirations1439245080000 2100

Saving a Session

Each session is stored in Redis as a Hash. Each session is set and updated using the HMSET command. An example of how each session is stored can be seen below.

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \
	maxInactiveInterval 1800 \
	lastAccessedTime 1404360000000 \
	sessionAttr:attrName someAttrValue \
	sessionAttr2:attrName someAttrValue2

In this example, the session following statements are true about the session:

  • The session ID is 33fdd1b6-b496-4b33-9f7d-df96679d32fe

  • The session was created at 1404360000000 in milliseconds since midnight of 1/1/1970 GMT.

  • The session expires in 1800 seconds (30 minutes).

  • The session was last accessed at 1404360000000 in milliseconds since midnight of 1/1/1970 GMT.

  • The session has two attributes. The first is "attrName" with the value of "someAttrValue". The second session attribute is named "attrName2" with the value of "someAttrValue2".

Optimized Writes

The Session instances managed by RedisOperationsSessionRepository keeps track of the properties that have changed and only updates those. This means if an attribute is written once and read many times we only need to write that attribute once. For example, assume the session attribute "sessionAttr2" from earlier was updated. The following would be executed upon saving:

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe sessionAttr:attrName2 newValue

Session Expiration

An expiration is associated to each session using the EXPIRE command based upon the Session.getMaxInactiveInterval() . For example:

EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100

You will note that the expiration that is set is 5 minutes after the session actually expires. This is necessary so that the value of the session can be accessed when the session expires. An expiration is set on the session itself five minutes after it actually expires to ensure it is cleaned up, but only after we perform any necessary processing.

Note

The SessionRepository.findById(String) method ensures that no expired sessions will be returned. This means there is no need to check the expiration before using a session.

Spring Session relies on the delete and expired keyspace notifications from Redis to fire a SessionDeletedEvent and SessionExpiredEvent respectively. It is the SessionDeletedEvent or SessionExpiredEvent that ensures resources associated with the Session are cleaned up. For example, when using Spring Session’s WebSocket support the Redis expired or delete event is what triggers any WebSocket connections associated with the session to be closed.

Expiration is not tracked directly on the session key itself since this would mean the session data would no longer be available. Instead a special session expires key is used. In our example the expires key is:

APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800

When a session expires key is deleted or expires, the keyspace notification triggers a lookup of the actual session and a SessionDestroyedEvent is fired.

One problem with relying on Redis expiration exclusively is that Redis makes no guarantee of when the expired event will be fired if the key has not been accessed. Specifically the background task that Redis uses to clean up expired keys is a low priority task and may not trigger the key expiration. For additional details see Timing of expired events section in the Redis documentation.

To circumvent the fact that expired events are not guaranteed to happen we can ensure that each key is accessed when it is expected to expire. This means that if the TTL is expired on the key, Redis will remove the key and fire the expired event when we try to access the key.

For this reason, each session expiration is also tracked to the nearest minute. This allows a background task to access the potentially expired sessions to ensure that Redis expired events are fired in a more deterministic fashion. For example:

SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
EXPIRE spring:session:expirations1439245080000 2100

The background task will then use these mappings to explicitly request each key. By accessing the key, rather than deleting it, we ensure that Redis deletes the key for us only if the TTL is expired.

Note

We do not explicitly delete the keys since in some instances there may be a race condition that incorrectly identifies a key as expired when it is not. Short of using distributed locks (which would kill our performance) there is no way to ensure the consistency of the expiration mapping. By simply accessing the key, we ensure that the key is only removed if the TTL on that key is expired.

9.7.5 SessionDeletedEvent and SessionExpiredEvent

SessionDeletedEvent and SessionExpiredEvent are both types of SessionDestroyedEvent .

RedisOperationsSessionRepository supports firing a SessionDeletedEvent whenever a Session is deleted or a SessionExpiredEvent when it expires. This is necessary to ensure resources associated with the Session are properly cleaned up.

For example, when integrating with WebSockets the SessionDestroyedEvent is in charge of closing any active WebSocket connections.

Firing SessionDeletedEvent or SessionExpiredEvent is made available through the SessionMessageListener which listens to Redis Keyspace events. In order for this to work, Redis Keyspace events for Generic commands and Expired events needs to be enabled. For example:

redis-cli config set notify-keyspace-events Egx

If you are using @EnableRedisHttpSession the SessionMessageListener and enabling the necessary Redis Keyspace events is done automatically. However, in a secured Redis enviornment the config command is disabled. This means that Spring Session cannot configure Redis Keyspace events for you. To disable the automatic configuration add ConfigureRedisAction.NO_OP as a bean.

For example, Java Configuration can use the following:

@Bean
public static ConfigureRedisAction configureRedisAction() {
	return ConfigureRedisAction.NO_OP;
}

XML Configuration can use the following:

<util:constant
	static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>

9.7.6 SessionCreatedEvent

When a session is created an event is sent to Redis with the channel of spring:session:channel:created:33fdd1b6-b496-4b33-9f7d-df96679d32fe such that 33fdd1b6-b496-4b33-9f7d-df96679d32fe is the session ID. The body of the event will be the session that was created.

If registered as a MessageListener (default), then RedisOperationsSessionRepository will then translate the Redis message into a SessionCreatedEvent .

9.7.7 Viewing the Session in Redis

After installing redis-cli, you can inspect the values in Redis using the redis-cli. For example, enter the following into a terminal:

$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
2) "spring:session:expirations:1418772300000" (2)
  • (1) The suffix of this key is the session identifier of the Spring Session.
  • (2) This key contains all the session IDs that should be deleted at the time 1418772300000 .

You can also view the attributes of each session.

redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"

9.8 ReactiveRedisOperationsSessionRepository

ReactiveRedisOperationsSessionRepository is a ReactiveSessionRepository that is implemented using Spring Data’s ReactiveRedisOperations . In a web environment, this is typically used in combination with WebSessionStore .

9.8.1 Instantiating a ReactiveRedisOperationsSessionRepository

A typical example of how to create a new instance can be seen below:

// ... create and configure connectionFactory and serializationContext ...

ReactiveRedisTemplate<String, Object> redisTemplate = new ReactiveRedisTemplate<>(
		connectionFactory, serializationContext);

ReactiveSessionRepository<? extends Session> repository =
		new ReactiveRedisOperationsSessionRepository(redisTemplate);

For additional information on how to create a ReactiveRedisConnectionFactory , refer to the Spring Data Redis Reference.

9.8.2 EnableRedisWebSession

In a web environment, the simplest way to create a new ReactiveRedisOperationsSessionRepository is to use @EnableRedisWebSession . You can use the following attributes to customize the configuration:

  • maxInactiveIntervalInSeconds - the amount of time before the session will expire in seconds

  • redisNamespace - allows configuring an application specific namespace for the sessions. Redis keys and channel IDs will start with the prefix of <redisNamespace>: .

  • redisFlushMode - allows specifying when data will be written to Redis. The default is only when save is invoked on ReactiveSessionRepository . A value of RedisFlushMode.IMMEDIATE will write to Redis as soon as possible.

Optimized Writes

The Session instances managed by ReactiveRedisOperationsSessionRepository keeps track of the properties that have changed and only updates those. This means if an attribute is written once and read many times we only need to write that attribute once.

9.8.3 Viewing the Session in Redis

After installing redis-cli, you can inspect the values in Redis using the redis-cli. For example, enter the following into a terminal:

$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
  • (1) The suffix of this key is the session identifier of the Spring Session.

You can also view the attributes of each session.

redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"

9.9 MapSessionRepository

The MapSessionRepository allows for persisting Session in a Map with the key being the Session ID and the value being the Session . The implementation can be used with a ConcurrentHashMap as a testing or convenience mechanism. Alternatively, it can be used with distributed Map implementations. For example, it can be used with Hazelcast.

9.9.1 Instantiating MapSessionRepository

Creating a new instance is as simple as:

SessionRepository<? extends Session> repository = new MapSessionRepository(
		new ConcurrentHashMap<>());

9.9.2 Using Spring Session and Hazlecast

The Hazelcast Sample is a complete application demonstrating using Spring Session with Hazelcast.

To run it use the following:

./gradlew :samples:hazelcast:tomcatRun

The Hazelcast Spring Sample is a complete application demonstrating using Spring Session with Hazelcast and Spring Security.

It includes example Hazelcast MapListener implementations that support firing SessionCreatedEvent , SessionDeletedEvent and SessionExpiredEvent .

To run it use the following:

./gradlew :samples:hazelcast-spring:tomcatRun

9.10 ReactiveMapSessionRepository

The ReactiveMapSessionRepository allows for persisting Session in a Map with the key being the Session ID and the value being the Session . The implementation can be used with a ConcurrentHashMap as a testing or convenience mechanism. Alternatively, it can be used with distributed Map implementations with the requirement that the supplied Map must be a non-blocking.

9.11 JdbcOperationsSessionRepository

JdbcOperationsSessionRepository is a SessionRepository implementation that uses Spring’s JdbcOperations to store sessions in a relational database. In a web environment, this is typically used in combination with SessionRepositoryFilter . Please note that this implementation does not support publishing of session events.

9.11.1 Instantiating a JdbcOperationsSessionRepository

A typical example of how to create a new instance can be seen below:

JdbcTemplate jdbcTemplate = new JdbcTemplate();

// ... configure JdbcTemplate ...

PlatformTransactionManager transactionManager = new DataSourceTransactionManager();

// ... configure transactionManager ...

SessionRepository<? extends Session> repository =
		new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);

For additional information on how to create and configure JdbcTemplate and PlatformTransactionManager , refer to the Spring Framework Reference Documentation.

9.11.2 EnableJdbcHttpSession

In a web environment, the simplest way to create a new JdbcOperationsSessionRepository is to use @EnableJdbcHttpSession . Complete example usage can be found in the Chapter 3, Samples and Guides (Start Here) You can use the following attributes to customize the configuration:

  • tableName - the name of database table used by Spring Session to store sessions

  • maxInactiveIntervalInSeconds - the amount of time before the session will expire in seconds

Custom LobHandler

You can customize the BLOB handling by creating a Bean named springSessionLobHandler that implements LobHandler .

Custom ConversionService

You can customize the default serialization and deserialization of the session by providing a ConversionService instance. When working in a typical Spring environment, the default ConversionService Bean (named conversionService ) will be automatically picked up and used for serialization and deserialization. However, you can override the default ConversionService by providing a Bean named springSessionConversionService .

9.11.3 Storage Details

By default, this implementation uses SPRING_SESSION and SPRING_SESSION_ATTRIBUTES tables to store sessions. Note that the table name can be easily customized as already described. In that case the table used to store attributes will be named using the provided table name, suffixed with _ATTRIBUTES . If further customizations are needed, SQL queries used by the repository can be customized using set*Query setter methods. In this case you need to manually configure the sessionRepository bean.

Due to the differences between the various database vendors, especially when it comes to storing binary data, make sure to use SQL script specific to your database. Scripts for most major database vendors are packaged as org/springframework/session/jdbc/schema-*.sql , where * is the target database type.

For example, with PostgreSQL database you would use the following schema script:

CREATE TABLE SPRING_SESSION (
	PRIMARY_ID CHAR(36) NOT NULL,
	SESSION_ID CHAR(36) NOT NULL,
	CREATION_TIME BIGINT NOT NULL,
	LAST_ACCESS_TIME BIGINT NOT NULL,
	MAX_INACTIVE_INTERVAL INT NOT NULL,
	EXPIRY_TIME BIGINT NOT NULL,
	PRINCIPAL_NAME VARCHAR(100),
	CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
);

CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);

CREATE TABLE SPRING_SESSION_ATTRIBUTES (
	SESSION_PRIMARY_ID CHAR(36) NOT NULL,
	ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
	ATTRIBUTE_BYTES BYTEA NOT NULL,
	CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
	CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);

And with MySQL database:

CREATE TABLE SPRING_SESSION (
	PRIMARY_ID CHAR(36) NOT NULL,
	SESSION_ID CHAR(36) NOT NULL,
	CREATION_TIME BIGINT NOT NULL,
	LAST_ACCESS_TIME BIGINT NOT NULL,
	MAX_INACTIVE_INTERVAL INT NOT NULL,
	EXPIRY_TIME BIGINT NOT NULL,
	PRINCIPAL_NAME VARCHAR(100),
	CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);

CREATE TABLE SPRING_SESSION_ATTRIBUTES (
	SESSION_PRIMARY_ID CHAR(36) NOT NULL,
	ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
	ATTRIBUTE_BYTES BLOB NOT NULL,
	CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
	CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

9.11.4 Transaction management

All JDBC operations in JdbcOperationsSessionRepository are executed in a transactional manner. Transactions are executed with propagation set to REQUIRES_NEW in order to avoid unexpected behavior due to interference with existing transactions (for example, executing save operation in a thread that already participates in a read-only transaction).

9.12 HazelcastSessionRepository

HazelcastSessionRepository is a SessionRepository implementation that stores sessions in Hazelcast’s distributed IMap . In a web environment, this is typically used in combination with SessionRepositoryFilter .

9.12.1 Instantiating a HazelcastSessionRepository

A typical example of how to create a new instance can be seen below:

Config config = new Config();

// ... configure Hazelcast ...

HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);

HazelcastSessionRepository repository =
		new HazelcastSessionRepository(hazelcastInstance);

For additional information on how to create and configure Hazelcast instance, refer to the Hazelcast documentation.

9.12.2 EnableHazelcastHttpSession

If you wish to use Hazelcast as your backing source for the SessionRepository , then the @EnableHazelcastHttpSession annotation can be added to an @Configuration class. This extends the functionality provided by the @EnableSpringHttpSession annotation but makes the SessionRepository for you in Hazelcast. You must provide a single HazelcastInstance bean for the configuration to work. Complete configuration example can be found in the Chapter 3, Samples and Guides (Start Here)

9.12.3 Basic Customization

You can use the following attributes on @EnableHazelcastHttpSession to customize the configuration:

  • maxInactiveIntervalInSeconds - the amount of time before the session will expire in seconds. Default is 1800 seconds (30 minutes)

  • sessionMapName - the name of the distributed Map that will be used in Hazelcast to store the session data.

9.12.4 Session Events

Using a MapListener to respond to entries being added, evicted, and removed from the distributed Map , these events will trigger publishing SessionCreatedEvent , SessionExpiredEvent , and SessionDeletedEvent events respectively using the ApplicationEventPublisher .

9.12.5 Storage Details

Sessions will be stored in a distributed IMap in Hazelcast. The IMap interface methods will be used to get() and put() Sessions. Additionally, values() method is used to support FindByIndexNameSessionRepository#findByIndexNameAndIndexValue operation, together with appropriate ValueExtractor that needs to be registered with Hazelcast. Refer to Hazelcast Spring Sample for more details on this configuration. The expiration of a session in the IMap is handled by Hazelcast’s support for setting the time to live on an entry when it is put() into the IMap . Entries (sessions) that have been idle longer than the time to live will be automatically removed from the IMap .

You shouldn’t need to configure any settings such as max-idle-seconds or time-to-live-seconds for the IMap within the Hazelcast configuration.

Note that if you use Hazelcast’s MapStore to persist your sessions IMap there are some limitations when reloading the sessions from MapStore :

  • reload triggers EntryAddedListener which results in SessionCreatedEvent being re-published

  • reload uses default TTL for a given IMap which results in sessions losing their original TTL