diff --git a/spring-session-core/src/main/java/org/springframework/session/MapSession.java b/spring-session-core/src/main/java/org/springframework/session/MapSession.java
index bd2413575..3536b8e0d 100644
--- a/spring-session-core/src/main/java/org/springframework/session/MapSession.java
+++ b/spring-session-core/src/main/java/org/springframework/session/MapSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2022 the original author or authors.
+ * Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,9 +21,10 @@
import java.time.Instant;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
+import java.util.ServiceLoader;
import java.util.Set;
-import java.util.UUID;
/**
*
@@ -44,6 +45,7 @@
*
* @author Rob Winch
* @author Vedran Pavic
+ * @author Yanming Zhou
* @since 1.0
*/
public final class MapSession implements Session, Serializable {
@@ -229,7 +231,14 @@ public int hashCode() {
}
private static String generateId() {
- return UUID.randomUUID().toString();
+ return sessionIdGenerator.generateId();
+ }
+
+ private static final SessionIdGenerator sessionIdGenerator;
+
+ static {
+ Iterator generators = ServiceLoader.load(SessionIdGenerator.class).iterator();
+ sessionIdGenerator = generators.hasNext() ? generators.next() : SessionIdGenerator.DEFAULT;
}
private static final long serialVersionUID = 7160779239673823561L;
diff --git a/spring-session-core/src/main/java/org/springframework/session/SessionIdGenerator.java b/spring-session-core/src/main/java/org/springframework/session/SessionIdGenerator.java
new file mode 100644
index 000000000..399eb36bf
--- /dev/null
+++ b/spring-session-core/src/main/java/org/springframework/session/SessionIdGenerator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.session;
+
+import java.util.UUID;
+
+/**
+ *
+ * Id generator for creating new session.
+ *
+ *
+ * @author Yanming Zhou
+ */
+@FunctionalInterface
+public interface SessionIdGenerator {
+
+ /**
+ * Using random UUID as default id generator.
+ */
+ SessionIdGenerator DEFAULT = () -> UUID.randomUUID().toString();
+
+ /**
+ * Generate and return a new session identifier.
+ * @return the newly generated session id
+ */
+ String generateId();
+
+}
diff --git a/spring-session-core/src/test/java/org/springframework/session/SessionIdGeneratorTests.java b/spring-session-core/src/test/java/org/springframework/session/SessionIdGeneratorTests.java
new file mode 100644
index 000000000..313276f2d
--- /dev/null
+++ b/spring-session-core/src/test/java/org/springframework/session/SessionIdGeneratorTests.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.session;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Yanming Zhou
+ */
+class SessionIdGeneratorTests {
+
+ static final String prefix = "sessionid-";
+
+ @Test
+ void sessionIdShouldStartsWithCustomizedPrefix() {
+ MapSession session = new MapSession();
+ assertThat(session.getId()).startsWith(prefix);
+ session.changeSessionId();
+ assertThat(session.getId()).startsWith(prefix);
+ }
+
+ public static class MySessionIdGenerator implements SessionIdGenerator {
+
+ private final AtomicLong counter = new AtomicLong();
+
+ @Override
+ public String generateId() {
+ return prefix + this.counter.incrementAndGet();
+ }
+
+ }
+
+}
diff --git a/spring-session-core/src/test/resources/META-INF/services/org.springframework.session.SessionIdGenerator b/spring-session-core/src/test/resources/META-INF/services/org.springframework.session.SessionIdGenerator
new file mode 100644
index 000000000..4a8fd337c
--- /dev/null
+++ b/spring-session-core/src/test/resources/META-INF/services/org.springframework.session.SessionIdGenerator
@@ -0,0 +1 @@
+org.springframework.session.SessionIdGeneratorTests$MySessionIdGenerator
\ No newline at end of file