You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by an...@apache.org on 2023/09/01 04:39:27 UTC

[ignite-extensions] branch ignite-18302 created (now d0f27f9a)

This is an automated email from the ASF dual-hosted git repository.

anovikov pushed a change to branch ignite-18302
in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git


      at d0f27f9a IGNITE-18302 Add support for different save modes.

This branch includes the following new commits:

     new 8cc4550f IGNITE-18302 IgniteSession serialization drags its parent class.
     new d0f27f9a IGNITE-18302 Add support for different save modes.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[ignite-extensions] 02/02: IGNITE-18302 Add support for different save modes.

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

anovikov pushed a commit to branch ignite-18302
in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git

commit d0f27f9a16c2605b3eeefedbd2896463adf941f4
Author: Andrey Novikov <an...@gridgain.com>
AuthorDate: Fri Sep 1 11:38:41 2023 +0700

    IGNITE-18302 Add support for different save modes.
---
 .../sessions/IgniteIndexedSessionRepository.java   | 75 +++++++++++++++++++---
 .../ignite/spring/sessions/IgniteSession.java      | 71 +++++++++++++-------
 .../spring/sessions/proxy/ClientSessionProxy.java  |  5 ++
 .../spring/sessions/proxy/IgniteSessionProxy.java  |  5 ++
 .../ignite/spring/sessions/proxy/SessionProxy.java |  9 +++
 5 files changed, 133 insertions(+), 32 deletions(-)

diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java
index 4d83f0b5..25a3e315 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java
@@ -93,6 +93,13 @@ public class IgniteIndexedSessionRepository
      */
     public static final String DEFAULT_SESSION_MAP_NAME = "spring:session:sessions";
 
+    /**
+     * Maximum of attempts for atomicity replace. If something wrong with IgniteSession, old value can never be equal to
+     * value from repository. In this case replace will never end the loop. If this value is exceeded, then plain
+     * {@link SessionProxy#replace(String, IgniteSession)} will be used.
+     */
+    private static final int MAX_UPDATE_ATTEMPT = 100;
+
     /** */
     private static final Log logger = LogFactory.getLog(IgniteIndexedSessionRepository.class);
 
@@ -109,7 +116,7 @@ public class IgniteIndexedSessionRepository
     private FlushMode flushMode = FlushMode.ON_SAVE;
 
     /** The save mode. */
-    private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
+    private SaveMode saveMode = SaveMode.ALWAYS;
 
     /** The index resolver. */
     private IndexResolver<Session> idxResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
@@ -173,8 +180,8 @@ public class IgniteIndexedSessionRepository
 
     /**
      * Set the maximum inactive interval in seconds between requests before newly created
-     * sessions will be invalidated. A negative time indicates that the session will never
-     * timeout. The default is 1800 (30 minutes).
+     * sessions will be invalidated. A negative time indicates that the session will never timeout.
+     * The default is 1800 (30 minutes).
      * @param dfltMaxInactiveInterval the maximum inactive interval in seconds
      */
     public void setDefaultMaxInactiveInterval(Integer dfltMaxInactiveInterval) {
@@ -223,14 +230,22 @@ public class IgniteIndexedSessionRepository
     @Override public void save(IgniteSession ses) {
         if (ses.isNew())
             ttlSessions(ses.getMaxInactiveInterval()).put(ses.getId(), ses);
-        else if (ses.hasChangedSessionId()) {
-            String originalId = ses.getDelegate().getOriginalId();
+        else {
+            String originalId = ses.getOriginalId();
 
-            sessions.remove(originalId);
-            ttlSessions(ses.getMaxInactiveInterval()).put(ses.getId(), ses);
+            if (!ses.getId().equals(originalId)) {
+                sessions.remove(originalId);
+
+                ses.resetOriginalId();
+                ttlSessions(ses.getMaxInactiveInterval()).put(ses.getId(), ses);
+            }
+            else if (ses.hasChanges()) {
+                if (saveMode == SaveMode.ALWAYS)
+                    ttlSessions(ses.getMaxInactiveInterval()).replace(ses.getId(), ses);
+                else
+                    updatePartial(ses);
+            }
         }
-        else if (ses.hasChanges())
-            ttlSessions(ses.getMaxInactiveInterval()).replace(ses.getId(), ses);
         
         ses.clearChangeFlags();
     }
@@ -344,4 +359,46 @@ public class IgniteIndexedSessionRepository
         if (flushMode == FlushMode.IMMEDIATE)
             save(ses);
     }
+
+    /**
+     * @param targetSes Target session.
+     * @param activeSes Active session.
+     */
+    private void copyChanges(IgniteSession targetSes, IgniteSession activeSes) {
+        if (activeSes.isLastAccessedTimeChanged())
+            targetSes.setLastAccessedTime(activeSes.getLastAccessedTime());
+
+        Map<String, Object> changes = activeSes.getAttributesChanges();
+
+        if (!changes.isEmpty())
+            changes.forEach(targetSes::setAttribute);
+    }
+
+    /**
+     * @param ses Session.
+     */
+    private void updatePartial(IgniteSession ses) {
+        IgniteSession oldSes, updatedSes;
+        int attempt = 0;
+
+        do {
+            attempt++;
+
+            oldSes = sessions.get(ses.getId());
+
+            if (oldSes == null)
+                break;
+
+            updatedSes = new IgniteSession(oldSes.getDelegate(), idxResolver, false, saveMode, this::flushImmediateIfNecessary);
+            copyChanges(updatedSes, ses);
+
+            if (attempt > MAX_UPDATE_ATTEMPT) {
+                logger.warn("Session maximum update attempts has been reached," +
+                    " 'replace' will be used instead [id=" + updatedSes.getId() + "]");
+
+                ttlSessions(ses.getMaxInactiveInterval()).replace(ses.getId(), updatedSes);
+                break;
+            }
+        } while (ttlSessions(ses.getMaxInactiveInterval()).replace(ses.getId(), oldSes, updatedSes));
+    }
 }
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java
index 1d0ce5bc..7663086a 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java
@@ -2,6 +2,7 @@ package org.apache.ignite.spring.sessions;
 
 import java.time.Duration;
 import java.time.Instant;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -13,6 +14,7 @@ import org.springframework.session.SaveMode;
 import org.springframework.session.Session;
 
 import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
+import static org.springframework.session.SaveMode.ON_GET_ATTRIBUTE;
 
 /**
  * A custom implementation of {@link Session} that uses a {@link MapSession} as the basis for its mapping. It keeps
@@ -43,7 +45,7 @@ public class IgniteSession implements Session {
 
     /** */
     @GridDirectTransient
-    private transient boolean attrsChanged;
+    private final transient Map<String, Object> delta = new HashMap<>();
 
     /** The index resolver. */
     @GridDirectTransient
@@ -58,33 +60,33 @@ public class IgniteSession implements Session {
     private final transient Consumer<IgniteSession> flusher;
 
     /**
-     * @param cached The map session.
+     * @param delegate The map session.
      * @param idxResolver The index resolver.
      * @param isNew Is new flag.
      * @param saveMode Mode of tracking and saving session changes to session store.
      * @param flusher Flusher for session store.
      */
     IgniteSession(
-        MapSession cached,
+        MapSession delegate,
         IndexResolver<Session> idxResolver,
         boolean isNew,
         SaveMode saveMode,
         Consumer<IgniteSession> flusher
     ) {
-        this.delegate = cached;
-        this.idxResolver = idxResolver;
+        this.delegate = delegate;
         this.isNew = isNew;
+
+        this.idxResolver = idxResolver;
         this.saveMode = saveMode;
         this.flusher = flusher;
 
-        principal = delegate.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
+        principal = this.delegate.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
 
-        if (isNew) {
-            if (saveMode == SaveMode.ALWAYS)
-                attrsChanged = true;
+        if (this.isNew || this.saveMode == SaveMode.ALWAYS)
+            getAttributeNames().forEach(attrName -> delta.put(attrName, this.delegate.getAttribute(attrName)));
 
-            flusher.accept(this);
-        }
+        if (isNew)
+            this.flusher.accept(this);
     }
 
     /** {@inheritDoc} */
@@ -137,8 +139,8 @@ public class IgniteSession implements Session {
     @Override public <T> T getAttribute(String attrName) {
         T attrVal = this.delegate.getAttribute(attrName);
 
-        if (attrVal != null && saveMode.equals(SaveMode.ON_GET_ATTRIBUTE))
-            attrsChanged = true;
+        if (attrVal != null && saveMode.equals(ON_GET_ATTRIBUTE))
+            delta.put(attrName, attrVal);
 
         return attrVal;
     }
@@ -151,14 +153,16 @@ public class IgniteSession implements Session {
     /** {@inheritDoc} */
     @Override public void setAttribute(String attrName, Object attrVal) {
         delegate.setAttribute(attrName, attrVal);
-        attrsChanged = true;
-        
+        delta.put(attrName, attrVal);
+
         if (SPRING_SECURITY_CONTEXT.equals(attrName)) {
             Map<String, String> indexes = idxResolver.resolveIndexesFor(this);
             String principal = (attrVal != null) ? indexes.get(PRINCIPAL_NAME_INDEX_NAME) : null;
 
             this.principal = principal;
+            
             delegate.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal);
+            delta.put(PRINCIPAL_NAME_INDEX_NAME, principal);
         }
 
         flusher.accept(this);
@@ -186,15 +190,25 @@ public class IgniteSession implements Session {
     /**
      * @return {@code True} if session is changed.
      */
-    public boolean hasChanges() {
-        return lastAccessedTimeChanged || maxInactiveIntervalChanged || attrsChanged;
+    public Map<String, Object> getAttributesChanges() {
+        return new HashMap<>(delta);
     }
 
     /**
-     * @return {@code True} if session ID is changed.
+     * Get the original session id.
+     * @return the original session id.
+     * @see #changeSessionId()
      */
-    public boolean hasChangedSessionId() {
-        return !delegate.getId().equals(delegate.getOriginalId());
+    public String getOriginalId() {
+        return delegate.getOriginalId();
+    }
+
+    /**
+     * Reset the original session id.
+     * @see #changeSessionId()
+     */
+    public void resetOriginalId() {
+        delegate = new MapSession(delegate);
     }
 
     /** Reset the change flags. */
@@ -202,10 +216,21 @@ public class IgniteSession implements Session {
         isNew = false;
         lastAccessedTimeChanged = false;
         maxInactiveIntervalChanged = false;
-        attrsChanged = false;
+        delta.clear();
+    }
 
-        if (hasChangedSessionId())
-            delegate = new MapSession(delegate);
+    /**
+     * @return Last accessed time changed.
+     */
+    public boolean isLastAccessedTimeChanged() {
+        return lastAccessedTimeChanged;
+    }
+
+    /**
+     * @return Session changed.
+     */
+    public boolean hasChanges() {
+        return lastAccessedTimeChanged || maxInactiveIntervalChanged || !delta.isEmpty();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java
index f8f6a6ce..bcde5858 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java
@@ -77,6 +77,11 @@ public class ClientSessionProxy implements SessionProxy {
         return cache.replace(key, val);
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean replace(String key, IgniteSession oldVal, IgniteSession newVal) {
+        return cache.replace(key, oldVal, newVal);
+    }
+
     /** {@inheritDoc} */
     @Override public <R> QueryCursor<R> query(Query<R> qry) {
         return cache.query(qry);
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java
index 8734192a..6f41918e 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java
@@ -77,6 +77,11 @@ public class IgniteSessionProxy implements SessionProxy {
         return cache.replace(key, val);
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean replace(String key, IgniteSession oldVal, IgniteSession newVal) {
+        return cache.replace(key, oldVal, newVal);
+    }
+
     /** {@inheritDoc} */
     @Override public <R> QueryCursor<R> query(Query<R> qry) {
         return cache.query(qry);
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java
index 12b44466..f31d4433 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java
@@ -23,6 +23,7 @@ import javax.cache.configuration.CacheEntryListenerConfiguration;
 import javax.cache.event.CacheEntryListener;
 import javax.cache.expiry.ExpiryPolicy;
 import javax.cache.integration.CacheWriter;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.spring.sessions.IgniteSession;
@@ -108,6 +109,14 @@ public interface SessionProxy {
      */
     public boolean replace(String key, IgniteSession val);
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * For {@link CacheAtomicityMode#ATOMIC} return
+     * value on primary node crash may be incorrect because of the automatic retries.
+     */
+    public boolean replace(String key, IgniteSession oldVal, IgniteSession newVal);
+
     /**
      * Execute SQL query and get cursor to iterate over results.
      *


[ignite-extensions] 01/02: IGNITE-18302 IgniteSession serialization drags its parent class.

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

anovikov pushed a commit to branch ignite-18302
in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git

commit 8cc4550fcc4f7092459053cc9e73142caa024b71
Author: Andrey Novikov <an...@gridgain.com>
AuthorDate: Thu Aug 31 13:06:35 2023 +0700

    IGNITE-18302 IgniteSession serialization drags its parent class.
---
 .../sessions/IgniteHttpSessionConfiguration.java   |   2 +-
 .../sessions/IgniteIndexedSessionRepository.java   | 325 +++++----------------
 .../ignite/spring/sessions/IgniteSession.java      | 228 +++++++++++++++
 .../spring/sessions/proxy/ClientSessionProxy.java  |   2 +-
 .../spring/sessions/proxy/IgniteSessionProxy.java  |   2 +-
 .../ignite/spring/sessions/proxy/SessionProxy.java |  20 +-
 ...AbstractIgniteIndexedSessionRepositoryTest.java |   5 +-
 ...EmbeddedIgniteIndexedSessionRepositoryTest.java |   1 -
 .../IgniteClientIndexedSessionRepositoryTest.java  |   1 -
 .../IgniteHttpSessionConfigurationTest.java        |  13 +-
 .../IgniteIndexedSessionRepositoryTest.java        |  19 +-
 11 files changed, 334 insertions(+), 284 deletions(-)

diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfiguration.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfiguration.java
index f77a211e..61f1fa37 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfiguration.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfiguration.java
@@ -185,7 +185,7 @@ public class IgniteHttpSessionConfiguration extends SpringHttpSessionConfigurati
                 " delegate OTHER," +
                 " principal VARCHAR" +
                 ") WITH \"template=replicated,atomicity=atomic," +
-                "value_type=org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository$IgniteSession," +
+                "value_type=org.apache.ignite.spring.sessions.IgniteSession," +
                 "cache_name=" + sesMapName + "\""),
             new SqlFieldsQuery("CREATE INDEX IF NOT EXISTS ignitesession_principal_idx ON IgniteSession (principal);")
         );
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java
index 4ca6868d..4d83f0b5 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepository.java
@@ -18,14 +18,10 @@
 package org.apache.ignite.spring.sessions;
 
 import java.time.Duration;
-import java.time.Instant;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 import javax.annotation.PreDestroy;
 import javax.cache.configuration.CacheEntryListenerConfiguration;
 import javax.cache.configuration.Factory;
@@ -57,6 +53,8 @@ import org.springframework.session.events.SessionDeletedEvent;
 import org.springframework.session.events.SessionExpiredEvent;
 import org.springframework.util.Assert;
 
+import static java.util.Collections.emptyMap;
+
 /**
  * A {@link org.springframework.session.SessionRepository} implementation that stores
  * sessions in Apache Ignite distributed {@link SessionProxy}.
@@ -86,45 +84,41 @@ import org.springframework.util.Assert;
  *
  */
 public class IgniteIndexedSessionRepository
-        implements FindByIndexNameSessionRepository<IgniteIndexedSessionRepository.IgniteSession>,
-        CacheEntryCreatedListener<String, IgniteIndexedSessionRepository.IgniteSession>,
-        CacheEntryRemovedListener<String, IgniteIndexedSessionRepository.IgniteSession>,
-        CacheEntryExpiredListener<String, IgniteIndexedSessionRepository.IgniteSession> {
+        implements FindByIndexNameSessionRepository<IgniteSession>,
+        CacheEntryCreatedListener<String, IgniteSession>,
+        CacheEntryRemovedListener<String, IgniteSession>,
+        CacheEntryExpiredListener<String, IgniteSession> {
     /**
      * The default name of map used by Spring Session to store sessions.
      */
     public static final String DEFAULT_SESSION_MAP_NAME = "spring:session:sessions";
 
-    /** */
-    private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
-
     /** */
     private static final Log logger = LogFactory.getLog(IgniteIndexedSessionRepository.class);
 
     /** */
-    private ApplicationEventPublisher eventPublisher = (event) -> {
-    };
+    private ApplicationEventPublisher evtPublisher = (event) -> {};
 
     /**
      * If non-null, this value is used to override
      * {@link MapSession#setMaxInactiveInterval(Duration)}.
      */
-    private Integer defaultMaxInactiveInterval;
-
-    /** */
-    private IndexResolver<Session> indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
+    private Integer dfltMaxInactiveInterval;
 
     /** */
     private FlushMode flushMode = FlushMode.ON_SAVE;
 
-    /** */
+    /** The save mode. */
     private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;
 
-    /** */
+    /** The index resolver. */
+    private IndexResolver<Session> idxResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>());
+
+    /** Sessions cache proxy. */
     private final SessionProxy sessions;
 
     /** */
-    private CacheEntryListenerConfiguration<String, IgniteSession> listenerConfiguration;
+    private final CacheEntryListenerConfiguration<String, IgniteSession> listenerConfiguration;
 
     /**
      * Create a new {@link IgniteIndexedSessionRepository} instance.
@@ -169,31 +163,32 @@ public class IgniteIndexedSessionRepository
      * Sets the {@link ApplicationEventPublisher} that is used to publish
      * {@link AbstractSessionEvent session events}. The default is to not publish session
      * events.
-     * @param applicationEventPublisher the {@link ApplicationEventPublisher} that is used
+     * @param applicationEvtPublisher the {@link ApplicationEventPublisher} that is used
      * to publish session events. Cannot be null.
      */
-    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
-        Assert.notNull(applicationEventPublisher, "ApplicationEventPublisher cannot be null");
-        this.eventPublisher = applicationEventPublisher;
+    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEvtPublisher) {
+        Assert.notNull(applicationEvtPublisher, "ApplicationEventPublisher cannot be null");
+        evtPublisher = applicationEvtPublisher;
     }
 
     /**
      * Set the maximum inactive interval in seconds between requests before newly created
      * sessions will be invalidated. A negative time indicates that the session will never
      * timeout. The default is 1800 (30 minutes).
-     * @param defaultMaxInactiveInterval the maximum inactive interval in seconds
+     * @param dfltMaxInactiveInterval the maximum inactive interval in seconds
      */
-    public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) {
-        this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
+    public void setDefaultMaxInactiveInterval(Integer dfltMaxInactiveInterval) {
+        this.dfltMaxInactiveInterval = dfltMaxInactiveInterval;
     }
 
     /**
      * Set the {@link IndexResolver} to use.
-     * @param indexResolver the index resolver
+     * @param idxResolver the index resolver
      */
-    public void setIndexResolver(IndexResolver<Session> indexResolver) {
-        Assert.notNull(indexResolver, "indexResolver cannot be null");
-        this.indexResolver = indexResolver;
+    public void setIndexResolver(IndexResolver<Session> idxResolver) {
+        Assert.notNull(idxResolver, "indexResolver cannot be null");
+        
+        this.idxResolver = idxResolver;
     }
 
     /**
@@ -217,45 +212,43 @@ public class IgniteIndexedSessionRepository
     /** {@inheritDoc} */
     @Override public IgniteSession createSession() {
         MapSession cached = new MapSession();
-        if (this.defaultMaxInactiveInterval != null)
-            cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
+        
+        if (this.dfltMaxInactiveInterval != null)
+            cached.setMaxInactiveInterval(Duration.ofSeconds(this.dfltMaxInactiveInterval));
 
-        IgniteSession session = new IgniteSession(cached, true);
-        session.flushImmediateIfNecessary();
-        return session;
+        return new IgniteSession(cached, idxResolver, true, saveMode, this::flushImmediateIfNecessary);
     }
 
     /** {@inheritDoc} */
-    @Override public void save(IgniteSession session) {
-        if (session.isNew)
-            ttlSessions(session.getMaxInactiveInterval()).put(session.getId(), session);
-
-        else if (session.sessionIdChanged) {
-            this.sessions.remove(session.originalId);
-            session.originalId = session.getId();
-            ttlSessions(session.getMaxInactiveInterval()).put(session.getId(), session);
-        }
-        else if (session.hasChanges()) {
-            if (session.maxInactiveIntervalChanged)
-                ttlSessions(session.getMaxInactiveInterval()).replace(session.getId(), session);
-            else
-                this.sessions.replace(session.getId(), session);
+    @Override public void save(IgniteSession ses) {
+        if (ses.isNew())
+            ttlSessions(ses.getMaxInactiveInterval()).put(ses.getId(), ses);
+        else if (ses.hasChangedSessionId()) {
+            String originalId = ses.getDelegate().getOriginalId();
+
+            sessions.remove(originalId);
+            ttlSessions(ses.getMaxInactiveInterval()).put(ses.getId(), ses);
         }
-        session.clearChangeFlags();
+        else if (ses.hasChanges())
+            ttlSessions(ses.getMaxInactiveInterval()).replace(ses.getId(), ses);
+        
+        ses.clearChangeFlags();
     }
 
     /** {@inheritDoc} */
     @Override public IgniteSession findById(String id) {
-        IgniteSession saved = this.sessions.get(id);
+        IgniteSession saved = sessions.get(id);
+        
         if (saved == null)
             return null;
 
         if (saved.isExpired()) {
             deleteById(saved.getId());
+            
             return null;
         }
-        saved.isNew = false;
-        return saved;
+
+        return new IgniteSession(saved.getDelegate(), idxResolver, false, saveMode, this::flushImmediateIfNecessary);
     }
 
     /** {@inheritDoc} */
@@ -264,40 +257,36 @@ public class IgniteIndexedSessionRepository
     }
 
     /** {@inheritDoc} */
-    @Override public Map<String, IgniteSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
-        if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName))
-            return Collections.emptyMap();
+    @Override public Map<String, IgniteSession> findByIndexNameAndIndexValue(String idxName, String idxVal) {
+        if (!PRINCIPAL_NAME_INDEX_NAME.equals(idxName))
+            return emptyMap();
 
-        final QueryCursor<List<?>> cursor = this.sessions
-                .query(new SqlFieldsQuery("SELECT * FROM IgniteSession WHERE principal='" + indexValue + "'"));
+        QueryCursor<List<?>> cursor = sessions.query(
+            new SqlFieldsQuery("SELECT * FROM IgniteSession WHERE principal = ?").setArgs(idxVal)
+        );
 
         if (cursor == null)
-            return Collections.emptyMap();
-
-        final List<List<?>> sessions = cursor.getAll();
-
-        Map<String, IgniteSession> sessionMap = new HashMap<>(sessions.size());
-
-        sessions.forEach((List<?> res) -> {
-            final MapSession session = (MapSession)res.get(1);
-            final IgniteSession value = new IgniteSession(session, false);
-            value.principal = (String)res.get(2);
-            sessionMap.put(session.getId(), value);
-        });
-
-        return sessionMap;
+            return emptyMap();
+
+        return cursor.getAll().stream()
+            .map(res -> (MapSession)res.get(1))
+            .collect(Collectors.toMap(
+                MapSession::getId,
+                ses -> new IgniteSession(ses, idxResolver, false, saveMode, this::flushImmediateIfNecessary)
+            ));
     }
 
     /** {@inheritDoc} */
     @Override public void onCreated(Iterable<CacheEntryEvent<? extends String, ? extends IgniteSession>> events)
             throws CacheEntryListenerException {
         events.forEach((event) -> {
-            IgniteSession session = event.getValue();
-            if (session.getId().equals(session.getDelegate().getOriginalId())) {
+            IgniteSession ses = event.getValue();
+            
+            if (ses.getId().equals(ses.getDelegate().getOriginalId())) {
                 if (logger.isDebugEnabled())
-                    logger.debug("Session created with id: " + session.getId());
+                    logger.debug("Session created with id: " + ses.getId());
 
-                this.eventPublisher.publishEvent(new SessionCreatedEvent(this, session));
+                evtPublisher.publishEvent(new SessionCreatedEvent(this, ses));
             }
         });
     }
@@ -309,7 +298,7 @@ public class IgniteIndexedSessionRepository
             if (logger.isDebugEnabled())
                 logger.debug("Session expired with id: " + event.getOldValue().getId());
 
-            this.eventPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue()));
+            evtPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue()));
         });
     }
 
@@ -317,12 +306,13 @@ public class IgniteIndexedSessionRepository
     @Override public void onRemoved(Iterable<CacheEntryEvent<? extends String, ? extends IgniteSession>> events)
             throws CacheEntryListenerException {
         events.forEach((event) -> {
-            IgniteSession session = event.getOldValue();
-            if (session != null) {
+            IgniteSession ses = event.getOldValue();
+            
+            if (ses != null) {
                 if (logger.isDebugEnabled())
-                    logger.debug("Session deleted with id: " + session.getId());
+                    logger.debug("Session deleted with id: " + ses.getId());
 
-                this.eventPublisher.publishEvent(new SessionDeletedEvent(this, session));
+                evtPublisher.publishEvent(new SessionDeletedEvent(this, ses));
             }
         });
     }
@@ -333,7 +323,7 @@ public class IgniteIndexedSessionRepository
      * @return cache with custom duration expiry policy.
      */
     private SessionProxy ttlSessions(Duration duration) {
-        return this.sessions.withExpiryPolicy(createPolicy(duration));
+        return sessions.withExpiryPolicy(createPolicy(duration));
     }
 
     /**
@@ -346,167 +336,12 @@ public class IgniteIndexedSessionRepository
     }
 
     /**
-     * A custom implementation of {@link Session} that uses a {@link MapSession} as the
-     * basis for its mapping. It keeps track if changes have been made since last save.
+     * Creates a new Session that is capable of being persisted by this SessionRepository.
+     * 
+     * @param ses Session.
      */
-    public class IgniteSession implements Session {
-        /** */
-        private final MapSession delegate;
-
-        /** */
-        private boolean isNew;
-
-        /** */
-        private boolean sessionIdChanged;
-
-        /** */
-        private boolean lastAccessedTimeChanged;
-
-        /** */
-        private boolean maxInactiveIntervalChanged;
-
-        /** */
-        private String originalId;
-
-        /** */
-        private Map<String, Object> delta = new HashMap<>();
-
-        /** */
-        private String principal;
-
-        /**
-         * @param cached Map session.
-         * @param isNew Is new flag.
-         */
-        IgniteSession(MapSession cached, boolean isNew) {
-            this.delegate = cached;
-            this.isNew = isNew;
-            this.originalId = cached.getId();
-            if (this.isNew || (IgniteIndexedSessionRepository.this.saveMode == SaveMode.ALWAYS))
-                getAttributeNames()
-                    .forEach((attributeName) -> this.delta.put(attributeName, cached.getAttribute(attributeName)));
-
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setLastAccessedTime(Instant lastAccessedTime) {
-            this.delegate.setLastAccessedTime(lastAccessedTime);
-            this.lastAccessedTimeChanged = true;
-            flushImmediateIfNecessary();
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean isExpired() {
-            return this.delegate.isExpired();
-        }
-
-        /** {@inheritDoc} */
-        @Override public Instant getCreationTime() {
-            return this.delegate.getCreationTime();
-        }
-
-        /** {@inheritDoc} */
-        @Override public String getId() {
-            return this.delegate.getId();
-        }
-
-        /** {@inheritDoc} */
-        @Override public String changeSessionId() {
-            String newSessionId = this.delegate.changeSessionId();
-            this.sessionIdChanged = true;
-            return newSessionId;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Instant getLastAccessedTime() {
-            return this.delegate.getLastAccessedTime();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setMaxInactiveInterval(Duration interval) {
-            this.delegate.setMaxInactiveInterval(interval);
-            this.maxInactiveIntervalChanged = true;
-            flushImmediateIfNecessary();
-        }
-
-        /** {@inheritDoc} */
-        @Override public Duration getMaxInactiveInterval() {
-            return this.delegate.getMaxInactiveInterval();
-        }
-
-        /** {@inheritDoc} */
-        @Override public <T> T getAttribute(String attributeName) {
-            T attributeValue = this.delegate.getAttribute(attributeName);
-            if (attributeValue != null
-                    && IgniteIndexedSessionRepository.this.saveMode.equals(SaveMode.ON_GET_ATTRIBUTE))
-                this.delta.put(attributeName, attributeValue);
-
-            return attributeValue;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Set<String> getAttributeNames() {
-            return this.delegate.getAttributeNames();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setAttribute(String attributeName, Object attributeValue) {
-            this.delegate.setAttribute(attributeName, attributeValue);
-            this.delta.put(attributeName, attributeValue);
-            if (SPRING_SECURITY_CONTEXT.equals(attributeName)) {
-                Map<String, String> indexes = IgniteIndexedSessionRepository.this.indexResolver.resolveIndexesFor(this);
-                String principal = (attributeValue != null) ? indexes.get(PRINCIPAL_NAME_INDEX_NAME) : null;
-                this.delegate.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal);
-                this.principal = principal;
-            }
-            flushImmediateIfNecessary();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void removeAttribute(String attributeName) {
-            setAttribute(attributeName, null);
-        }
-
-        /** */
-        MapSession getDelegate() {
-            return this.delegate;
-        }
-
-        /** */
-        boolean hasChanges() {
-            return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged || !this.delta.isEmpty());
-        }
-
-        /** */
-        void clearChangeFlags() {
-            this.isNew = false;
-            this.lastAccessedTimeChanged = false;
-            this.sessionIdChanged = false;
-            this.maxInactiveIntervalChanged = false;
-            this.delta.clear();
-        }
-
-        /** */
-        private void flushImmediateIfNecessary() {
-            if (IgniteIndexedSessionRepository.this.flushMode == FlushMode.IMMEDIATE)
-                IgniteIndexedSessionRepository.this.save(this);
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean equals(Object o) {
-            if (this == o)
-                return true;
-
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            IgniteSession session = (IgniteSession)o;
-            return this.delegate.equals(session.delegate);
-        }
-
-        /** {@inheritDoc} */
-        @Override public int hashCode() {
-            return Objects.hash(this.delegate);
-        }
+    private void flushImmediateIfNecessary(IgniteSession ses) {
+        if (flushMode == FlushMode.IMMEDIATE)
+            save(ses);
     }
 }
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java
new file mode 100644
index 00000000..1d0ce5bc
--- /dev/null
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/IgniteSession.java
@@ -0,0 +1,228 @@
+package org.apache.ignite.spring.sessions;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+import org.apache.ignite.internal.GridDirectTransient;
+import org.springframework.session.IndexResolver;
+import org.springframework.session.MapSession;
+import org.springframework.session.SaveMode;
+import org.springframework.session.Session;
+
+import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
+
+/**
+ * A custom implementation of {@link Session} that uses a {@link MapSession} as the basis for its mapping. It keeps
+ * track if changes have been made since last save.
+ */
+public class IgniteSession implements Session {
+    /** */
+    public static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
+
+    /** The map session. */
+    private MapSession delegate;
+
+    /** Cached principal name for query. */
+    @SuppressWarnings("unused")
+    private String principal;
+
+    /** */
+    @GridDirectTransient
+    private transient boolean isNew;
+
+    /** */
+    @GridDirectTransient
+    private transient boolean lastAccessedTimeChanged;
+
+    /** */
+    @GridDirectTransient
+    private transient boolean maxInactiveIntervalChanged;
+
+    /** */
+    @GridDirectTransient
+    private transient boolean attrsChanged;
+
+    /** The index resolver. */
+    @GridDirectTransient
+    private final transient IndexResolver<Session> idxResolver;
+
+    /** Session save mode. */
+    @GridDirectTransient
+    private final transient SaveMode saveMode;
+
+    /** */
+    @GridDirectTransient
+    private final transient Consumer<IgniteSession> flusher;
+
+    /**
+     * @param cached The map session.
+     * @param idxResolver The index resolver.
+     * @param isNew Is new flag.
+     * @param saveMode Mode of tracking and saving session changes to session store.
+     * @param flusher Flusher for session store.
+     */
+    IgniteSession(
+        MapSession cached,
+        IndexResolver<Session> idxResolver,
+        boolean isNew,
+        SaveMode saveMode,
+        Consumer<IgniteSession> flusher
+    ) {
+        this.delegate = cached;
+        this.idxResolver = idxResolver;
+        this.isNew = isNew;
+        this.saveMode = saveMode;
+        this.flusher = flusher;
+
+        principal = delegate.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
+
+        if (isNew) {
+            if (saveMode == SaveMode.ALWAYS)
+                attrsChanged = true;
+
+            flusher.accept(this);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setLastAccessedTime(Instant lastAccessedTime) {
+        delegate.setLastAccessedTime(lastAccessedTime);
+        lastAccessedTimeChanged = true;
+
+        flusher.accept(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isExpired() {
+        return delegate.isExpired();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Instant getCreationTime() {
+        return delegate.getCreationTime();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getId() {
+        return delegate.getId();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String changeSessionId() {
+        return delegate.changeSessionId();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Instant getLastAccessedTime() {
+        return delegate.getLastAccessedTime();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setMaxInactiveInterval(Duration interval) {
+        delegate.setMaxInactiveInterval(interval);
+        maxInactiveIntervalChanged = true;
+
+        flusher.accept(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Duration getMaxInactiveInterval() {
+        return delegate.getMaxInactiveInterval();
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T getAttribute(String attrName) {
+        T attrVal = this.delegate.getAttribute(attrName);
+
+        if (attrVal != null && saveMode.equals(SaveMode.ON_GET_ATTRIBUTE))
+            attrsChanged = true;
+
+        return attrVal;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Set<String> getAttributeNames() {
+        return this.delegate.getAttributeNames();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAttribute(String attrName, Object attrVal) {
+        delegate.setAttribute(attrName, attrVal);
+        attrsChanged = true;
+        
+        if (SPRING_SECURITY_CONTEXT.equals(attrName)) {
+            Map<String, String> indexes = idxResolver.resolveIndexesFor(this);
+            String principal = (attrVal != null) ? indexes.get(PRINCIPAL_NAME_INDEX_NAME) : null;
+
+            this.principal = principal;
+            delegate.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal);
+        }
+
+        flusher.accept(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void removeAttribute(String attrName) {
+        setAttribute(attrName, null);
+    }
+
+    /**
+     * @return Is new session.
+     */
+    public boolean isNew() {
+        return isNew;
+    }
+
+    /**
+     * @return Internal session object.
+     */
+    public MapSession getDelegate() {
+        return delegate;
+    }
+
+    /**
+     * @return {@code True} if session is changed.
+     */
+    public boolean hasChanges() {
+        return lastAccessedTimeChanged || maxInactiveIntervalChanged || attrsChanged;
+    }
+
+    /**
+     * @return {@code True} if session ID is changed.
+     */
+    public boolean hasChangedSessionId() {
+        return !delegate.getId().equals(delegate.getOriginalId());
+    }
+
+    /** Reset the change flags. */
+    public void clearChangeFlags() {
+        isNew = false;
+        lastAccessedTimeChanged = false;
+        maxInactiveIntervalChanged = false;
+        attrsChanged = false;
+
+        if (hasChangedSessionId())
+            delegate = new MapSession(delegate);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        IgniteSession ses = (IgniteSession)o;
+        
+        return delegate.equals(ses.delegate);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return Objects.hash(delegate);
+    }
+}
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java
index 1cb88c13..f8f6a6ce 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/ClientSessionProxy.java
@@ -22,7 +22,7 @@ import javax.cache.expiry.ExpiryPolicy;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.client.ClientCache;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository.IgniteSession;
+import org.apache.ignite.spring.sessions.IgniteSession;
 
 /**
  * Represents {@link SessionProxy} implementation that uses {@link ClientCache} to perform session operations.
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java
index f19baf1b..8734192a 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/IgniteSessionProxy.java
@@ -22,7 +22,7 @@ import javax.cache.expiry.ExpiryPolicy;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository.IgniteSession;
+import org.apache.ignite.spring.sessions.IgniteSession;
 
 /**
  * Represents {@link SessionProxy} implementation that uses {@link IgniteCache} to perform session operations.
diff --git a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java
index a2779b14..12b44466 100644
--- a/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java
+++ b/modules/spring-session-ext/src/main/java/org/apache/ignite/spring/sessions/proxy/SessionProxy.java
@@ -25,7 +25,7 @@ import javax.cache.expiry.ExpiryPolicy;
 import javax.cache.integration.CacheWriter;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository;
+import org.apache.ignite.spring.sessions.IgniteSession;
 
 /** Represents Ignite client-independent session operations. */
 public interface SessionProxy {
@@ -33,24 +33,20 @@ public interface SessionProxy {
      * Registers a {@link CacheEntryListener}. The supplied {@link CacheEntryListenerConfiguration} is used to
      * instantiate a listener and apply it to those events specified in the configuration.
      *
-     * @param lsnrCfg a factory and related configuration for creating the listener.
+     * @param cacheEntryListenerConfiguration a factory and related configuration for creating the listener.
      * @throws IllegalArgumentException is the same CacheEntryListenerConfiguration is used more than once or
      *          if some unsupported by thin client properties are set.
      * @see CacheEntryListener
      */
-    public void registerCacheEntryListener(
-        CacheEntryListenerConfiguration<String, IgniteIndexedSessionRepository.IgniteSession> lsnrCfg
-    );
+    public void registerCacheEntryListener(CacheEntryListenerConfiguration<String, IgniteSession> cacheEntryListenerConfiguration);
 
     /**
      * Deregisters a listener, using the {@link CacheEntryListenerConfiguration} that was used to register it.
      *
-     * @param lsnrCfg the factory and related configuration that was used to create the
+     * @param cacheEntryListenerConfiguration the factory and related configuration that was used to create the
      *         listener.
      */
-    public void deregisterCacheEntryListener(
-        CacheEntryListenerConfiguration<String, IgniteIndexedSessionRepository.IgniteSession> lsnrCfg
-    );
+    public void deregisterCacheEntryListener(CacheEntryListenerConfiguration<String, IgniteSession> cacheEntryListenerConfiguration);
 
     /**
      * Returns cache with the specified expired policy set. This policy will be used for each operation invoked on
@@ -67,7 +63,7 @@ public interface SessionProxy {
      * @param key the key whose associated value is to be returned
      * @return the element, or null, if it does not exist.
      */
-    public IgniteIndexedSessionRepository.IgniteSession get(String key);
+    public IgniteSession get(String key);
 
     /**
      * Associates the specified value with the specified key in the cache.
@@ -75,7 +71,7 @@ public interface SessionProxy {
      * @param key key with which the specified value is to be associated
      * @param val value to be associated with the specified key.
      */
-    public void put(String key, IgniteIndexedSessionRepository.IgniteSession val);
+    public void put(String key, IgniteSession val);
 
     /**
      * Removes the mapping for a key from this cache if it is present.
@@ -110,7 +106,7 @@ public interface SessionProxy {
      *                               configured for the {@link Cache}
      * @see CacheWriter#write
      */
-    public boolean replace(String key, IgniteIndexedSessionRepository.IgniteSession val);
+    public boolean replace(String key, IgniteSession val);
 
     /**
      * Execute SQL query and get cursor to iterate over results.
diff --git a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/AbstractIgniteIndexedSessionRepositoryTest.java b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/AbstractIgniteIndexedSessionRepositoryTest.java
index eb180d6d..62f83a3f 100644
--- a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/AbstractIgniteIndexedSessionRepositoryTest.java
+++ b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/AbstractIgniteIndexedSessionRepositoryTest.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.spring.sessions;
 
 import java.time.Duration;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository.IgniteSession;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -28,15 +27,13 @@ import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.session.FindByIndexNameSessionRepository;
 
+import static org.apache.ignite.spring.sessions.IgniteSession.SPRING_SECURITY_CONTEXT;
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * Base class for {@link IgniteIndexedSessionRepository} integration tests.
  */
 abstract class AbstractIgniteIndexedSessionRepositoryTest {
-    /** */
-    private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
-
     /** */
     @Autowired
     protected IgniteIndexedSessionRepository repo;
diff --git a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/EmbeddedIgniteIndexedSessionRepositoryTest.java b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/EmbeddedIgniteIndexedSessionRepositoryTest.java
index 530f7a9b..db62332a 100644
--- a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/EmbeddedIgniteIndexedSessionRepositoryTest.java
+++ b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/EmbeddedIgniteIndexedSessionRepositoryTest.java
@@ -20,7 +20,6 @@ package org.apache.ignite.spring.sessions;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository.IgniteSession;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteClientIndexedSessionRepositoryTest.java b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteClientIndexedSessionRepositoryTest.java
index 34231f9c..219969d0 100644
--- a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteClientIndexedSessionRepositoryTest.java
+++ b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteClientIndexedSessionRepositoryTest.java
@@ -21,7 +21,6 @@ import org.apache.ignite.Ignition;
 import org.apache.ignite.client.ClientCache;
 import org.apache.ignite.client.IgniteClient;
 import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository.IgniteSession;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfigurationTest.java b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfigurationTest.java
index 9b3969a0..a6b2f185 100644
--- a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfigurationTest.java
+++ b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteHttpSessionConfigurationTest.java
@@ -57,13 +57,12 @@ public class IgniteHttpSessionConfigurationTest {
     private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600;
 
     /** */
-    private AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
+    private final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
 
     /** */
     @AfterEach
     void closeContext() {
-        if (this.ctx != null)
-            this.ctx.close();
+        this.ctx.close();
     }
 
     /** */
@@ -110,7 +109,7 @@ public class IgniteHttpSessionConfigurationTest {
 
         IgniteIndexedSessionRepository repo = this.ctx.getBean(IgniteIndexedSessionRepository.class);
         assertThat(repo).isNotNull();
-        assertThat(getField(repo, "defaultMaxInactiveInterval"))
+        assertThat(getField(repo, "dfltMaxInactiveInterval"))
                 .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
     }
 
@@ -121,7 +120,7 @@ public class IgniteHttpSessionConfigurationTest {
 
         IgniteIndexedSessionRepository repo = this.ctx.getBean(IgniteIndexedSessionRepository.class);
         assertThat(repo).isNotNull();
-        assertThat(getField(repo, "defaultMaxInactiveInterval"))
+        assertThat(getField(repo, "dfltMaxInactiveInterval"))
                 .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
     }
 
@@ -230,7 +229,7 @@ public class IgniteHttpSessionConfigurationTest {
         IndexResolver<Session> idxResolver = this.ctx.getBean(IndexResolver.class);
         assertThat(repo).isNotNull();
         assertThat(idxResolver).isNotNull();
-        assertThat(repo).hasFieldOrPropertyWithValue("indexResolver", idxResolver);
+        assertThat(repo).hasFieldOrPropertyWithValue("idxResolver", idxResolver);
     }
 
     /** */
@@ -238,7 +237,7 @@ public class IgniteHttpSessionConfigurationTest {
     void sessionRepositoryCustomizer() {
         registerAndRefresh(SessionRepositoryCustomizerConfiguration.class);
         IgniteIndexedSessionRepository sesRepo = this.ctx.getBean(IgniteIndexedSessionRepository.class);
-        assertThat(sesRepo).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
+        assertThat(sesRepo).hasFieldOrPropertyWithValue("dfltMaxInactiveInterval",
                 MAX_INACTIVE_INTERVAL_IN_SECONDS);
     }
 
diff --git a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepositoryTest.java b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepositoryTest.java
index 05c7585d..342d901e 100644
--- a/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepositoryTest.java
+++ b/modules/spring-session-ext/src/test/java/org/apache/ignite/spring/sessions/IgniteIndexedSessionRepositoryTest.java
@@ -28,7 +28,6 @@ import java.util.concurrent.TimeUnit;
 import javax.cache.expiry.TouchedExpiryPolicy;
 import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryCursor;
-import org.apache.ignite.spring.sessions.IgniteIndexedSessionRepository.IgniteSession;
 import org.apache.ignite.spring.sessions.proxy.SessionProxy;
 import org.jetbrains.annotations.NotNull;
 import org.junit.jupiter.api.BeforeEach;
@@ -36,7 +35,6 @@ import org.junit.jupiter.api.Test;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.session.FindByIndexNameSessionRepository;
 import org.springframework.session.FlushMode;
 import org.springframework.session.MapSession;
 
@@ -50,6 +48,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
 
 /**
  * Tests for {@link IgniteIndexedSessionRepository}.
@@ -162,7 +161,7 @@ public class IgniteIndexedSessionRepositoryTest {
 
         IgniteSession ses = repo.createSession();
         ses.setAttribute("testName", "testValue");
-        verify(sessions, times(1)).withExpiryPolicy(eq(createExpiryPolicy(ses)));
+        verify(sessions, times(2)).withExpiryPolicy(eq(createExpiryPolicy(ses)));
         verify(sessions, times(1)).put(eq(ses.getId()), eq(ses));
         verify(sessions, times(1)).replace(eq(ses.getId()), eq(ses));
 
@@ -196,7 +195,7 @@ public class IgniteIndexedSessionRepositoryTest {
         ses.removeAttribute("testName");
         verify(sessions, times(1)).put(eq(ses.getId()), eq(ses));
         verify(sessions, times(1)).replace(eq(ses.getId()), eq(ses));
-        verify(sessions, times(1)).withExpiryPolicy(eq(createExpiryPolicy(ses)));
+        verify(sessions, times(2)).withExpiryPolicy(eq(createExpiryPolicy(ses)));
 
         repo.save(ses);
         verifyNoMoreInteractions(sessions);
@@ -228,7 +227,7 @@ public class IgniteIndexedSessionRepositoryTest {
         ses.setLastAccessedTime(Instant.now());
         verify(sessions, times(1)).put(eq(ses.getId()), eq(ses));
         verify(sessions, times(1)).replace(eq(ses.getId()), eq(ses));
-        verify(sessions, times(1)).withExpiryPolicy(eq(createExpiryPolicy(ses)));
+        verify(sessions, times(2)).withExpiryPolicy(eq(createExpiryPolicy(ses)));
 
         repo.save(ses);
         verifyNoMoreInteractions(sessions);
@@ -316,7 +315,7 @@ public class IgniteIndexedSessionRepositoryTest {
     void getSessionExpired() {
         verify(sessions, times(1)).registerCacheEntryListener(any());
 
-        IgniteSession expired = repo.new IgniteSession(new MapSession(), true);
+        IgniteSession expired = repo.createSession();
 
         expired.setLastAccessedTime(Instant.now().minusSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS + 1));
         given(sessions.get(eq(expired.getId()))).willReturn(expired);
@@ -334,7 +333,7 @@ public class IgniteIndexedSessionRepositoryTest {
     void getSessionFound() {
         verify(sessions, times(1)).registerCacheEntryListener(any());
 
-        IgniteSession saved = repo.new IgniteSession(new MapSession(), true);
+        IgniteSession saved = repo.createSession();
         saved.setAttribute("savedName", "savedValue");
         given(sessions.get(eq(saved.getId()))).willReturn(saved);
 
@@ -379,8 +378,7 @@ public class IgniteIndexedSessionRepositoryTest {
 
         String principal = "username";
 
-        Map<String, IgniteSession> sesMap = repo
-                .findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal);
+        Map<String, IgniteSession> sesMap = repo.findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principal);
 
         assertThat(sesMap).isEmpty();
 
@@ -424,8 +422,7 @@ public class IgniteIndexedSessionRepositoryTest {
             }
         });
 
-        Map<String, IgniteSession> sesMap = repo
-                .findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal);
+        Map<String, IgniteSession> sesMap = repo.findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principal);
 
         assertThat(sesMap).hasSize(2);
         verify(sessions, times(1)).query(any());