Using Spring Sessions with NCache
This section will guide you through integrating NCache into your Spring Boot applications for efficient and scalable session management.
These sessions can be regular or indexed. For indexed sessions the prinicipal name of the authenticated users is stored as a NCache Tag.
Prerequisites
- The minimum required Java version is 17.0.
- The Spring Framework version should be 6.0.12 or higher.
Add Maven Packages
You must add the following in your pom.xml
file while working with the NCache Spring Sessions integration.
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Session Core -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<!-- Spring Boot Test Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot Thymeleaf Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>x.x.x</version>
</dependency>
<!-- NCache Spring Session Integration -->
<dependency>
<groupId>com.alachisoft.ncache</groupId>
<artifactId>ncache-spring-session</artifactId>
<version>x.x.x</version>
</dependency>
Configure Application Properties
Ensure your application.properties
or application.yml
file contains the necessary configurations, such as NCache connection details.
Spring Sessions Implementation
You will have to add an annotation to your application to connect spring sessions with NCache. To do so, add the following to the class with the main function:
@SpringBootApplication // this is needed so that spring can read the user created Beans and Configurations
Further, you will also have to add one of the following to add configurations:
@EnableNCacheSession // uses the default configutaions
@EnableNCacheSession(cacheName = "ClusteredCache")
However, if you want to add indexed sessions, you must use the @EnableNCacheIndexedSession
which can be defined using the configurations mentioned above.
If you require custom settings you will have to pass arguments in the annotation. These custom settings are separated by a comma like cacheName="demoCache", namespace="randomNamespace"
and can include the following:
cacheName -> default: demoCache
namespace -> default: "spring:sessions:"
maxInactiveInterval -> default: 1000 seconds
saveMode -> default: ON_SAVE
flushMode -> default: ON_SAVE
Your spring application will employ an interface that calls an Adapter that gets and sets the session creation time, last access time, the sliding inactivity interval, and any other attributes necessary. This will look something like the following:
class HttpSessionAdapter<S extends Session> implements HttpSession {
private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);
private final S session;
private final ServletContext servletContext;
private boolean invalidated;
private boolean old;
HttpSessionAdapter(S session, ServletContext servletContext) {
if (session == null) {
throw new IllegalArgumentException("session cannot be null");
} else if (servletContext == null) {
throw new IllegalArgumentException("servletContext cannot be null");
} else {
this.session = session;
this.servletContext = servletContext;
}
}
S getSession() {
return this.session;
}
public long getCreationTime() {
this.checkState();
return this.session.getCreationTime().toEpochMilli();
}
public String getId() {
return this.session.getId();
}
public long getLastAccessedTime() {
this.checkState();
return this.session.getLastAccessedTime().toEpochMilli();
}
public ServletContext getServletContext() {
return this.servletContext;
}
public void setMaxInactiveInterval(int interval) {
this.session.setMaxInactiveInterval(Duration.ofSeconds((long)interval));
}
public int getMaxInactiveInterval() {
return (int)this.session.getMaxInactiveInterval().getSeconds();
}
public Object getAttribute(String name) {
this.checkState();
return this.session.getAttribute(name);
}
public Enumeration<String> getAttributeNames() {
this.checkState();
return Collections.enumeration(this.session.getAttributeNames());
}
public void setAttribute(String name, Object value) {
this.checkState();
Object oldValue = this.session.getAttribute(name);
this.session.setAttribute(name, value);
if (value != oldValue) {
if (oldValue instanceof HttpSessionBindingListener) {
try {
((HttpSessionBindingListener)oldValue).valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
} catch (Throwable var6) {
logger.error("Error invoking session binding event listener", var6);
}
}
if (value instanceof HttpSessionBindingListener) {
try {
((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this, name, value));
} catch (Throwable var5) {
logger.error("Error invoking session binding event listener", var5);
}
}
}
}
public void removeAttribute(String name) {
this.checkState();
Object oldValue = this.session.getAttribute(name);
this.session.removeAttribute(name);
if (oldValue instanceof HttpSessionBindingListener) {
try {
((HttpSessionBindingListener)oldValue).valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
} catch (Throwable var4) {
logger.error("Error invoking session binding event listener", var4);
}
}
}
public void invalidate() {
this.checkState();
this.invalidated = true;
}
public boolean isNew() {
this.checkState();
return !this.old;
}
void markNotNew() {
this.old = true;
}
private void checkState() {
if (this.invalidated) {
throw new IllegalStateException("The HttpSession has already be invalidated.");
}
}
}
See Also
Configure Application for Generic Spring Caching Provider
NCache as Spring Data Cache