diff --git a/src/main/java/org/springframework/session/sticky/StickySessionCache.java b/src/main/java/org/springframework/session/sticky/StickySessionCache.java index 6eb6965..49c7ae6 100644 --- a/src/main/java/org/springframework/session/sticky/StickySessionCache.java +++ b/src/main/java/org/springframework/session/sticky/StickySessionCache.java @@ -15,8 +15,6 @@ */ package org.springframework.session.sticky; -import static java.util.Comparator.comparing; - import java.lang.ref.WeakReference; import java.time.Duration; import java.time.Instant; @@ -27,7 +25,10 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.lang.Nullable; +import org.springframework.session.Session; +import org.springframework.session.events.SessionDestroyedEvent; import org.springframework.session.sticky.StickySessionRepository.CacheEntry; import org.springframework.util.Assert; @@ -46,10 +47,17 @@ public class StickySessionCache { protected Duration cleanupAfter = Duration.ofMinutes(DEFAULT_CLEANUP_AFTER_MINUTES); + private ApplicationEventPublisher eventPublisher = event -> { + }; + public StickySessionCache(int cacheConcurrency) { this.sessions = new ConcurrentHashMap<>(16, 0.75F, cacheConcurrency); } + public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } + /** * Cached session entries that have not been accessed for {@linkplain #cleanupAfter the configured period} will * be removed from the cache (but not the remote store) when {@link #cleanupOutdatedCacheEntries()} is called. @@ -76,9 +84,11 @@ public void put(CacheEntry entry) { @Nullable public void remove(String id) { - sessions.remove(id); + final CacheEntry cacheEntry = sessions.remove(id); // We don't remove from cleanup cache here, because that would require a separate mapping of session ids. // The weak reference will be cleared, and the cleanup entry will simply be skipped when it's due. + + eventPublisher.publishEvent(new LocalSessionDestroyedEvent(this, cacheEntry.createView())); } /** @@ -142,7 +152,7 @@ void cleanup() { if (session.getLastAccessedTime().isBefore(maxLastAccessed)) { if (logger.isDebugEnabled()) logger.debug("Cached session " + session.getId() + " is scheduled for cleanup, removing from cache."); - sessions.remove(session.getId()); + StickySessionCache.this.remove(session.getId()); } else { schedule(session); } @@ -150,4 +160,9 @@ void cleanup() { } } + public static class LocalSessionDestroyedEvent extends SessionDestroyedEvent { + private LocalSessionDestroyedEvent(Object source, Session session) { + super(source, session); + } + } } diff --git a/src/main/java/org/springframework/session/sticky/StickySessionRepository.java b/src/main/java/org/springframework/session/sticky/StickySessionRepository.java index b6c00bc..5277f9c 100644 --- a/src/main/java/org/springframework/session/sticky/StickySessionRepository.java +++ b/src/main/java/org/springframework/session/sticky/StickySessionRepository.java @@ -15,8 +15,6 @@ */ package org.springframework.session.sticky; -import static java.util.Comparator.comparing; - import java.time.Duration; import java.time.Instant; import java.util.HashMap; @@ -339,7 +337,7 @@ private synchronized void saveDelegate() { delegateAwaitsSave = false; } - private synchronized StickySession createView() { + synchronized StickySession createView() { if (logger.isTraceEnabled()) logger.trace("Creating new session view for " + getId()); return new StickySession(this, new MapSession(cached)); diff --git a/src/main/java/org/springframework/session/sticky/config/annotation/web/http/StickyHttpSessionConfiguration.java b/src/main/java/org/springframework/session/sticky/config/annotation/web/http/StickyHttpSessionConfiguration.java index a887891..8dbd99e 100644 --- a/src/main/java/org/springframework/session/sticky/config/annotation/web/http/StickyHttpSessionConfiguration.java +++ b/src/main/java/org/springframework/session/sticky/config/annotation/web/http/StickyHttpSessionConfiguration.java @@ -20,8 +20,6 @@ import java.time.Duration; import java.util.Map; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; @@ -140,6 +138,7 @@ public DelegateSaveStrategy stickySessionDelegateSaveStrategy() { public StickySessionCache stickySessionCache() { StickySessionCache cache = new StickySessionCache(this.sessionConcurrency); cache.setCleanupAfter(this.cleanupAfter); + cache.setApplicationEventPublisher(this.eventPublisher); return cache; }