Remove session store type in favor of defined order
Closes gh-27756
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.context.properties.bind.BindException;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* Base class for Servlet and reactive session conditions.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Stephane Nicoll
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class AbstractSessionCondition extends SpringBootCondition {
|
||||
|
||||
private final WebApplicationType webApplicationType;
|
||||
|
||||
protected AbstractSessionCondition(WebApplicationType webApplicationType) {
|
||||
this.webApplicationType = webApplicationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("Session Condition");
|
||||
Environment environment = context.getEnvironment();
|
||||
StoreType required = SessionStoreMappings.getType(this.webApplicationType,
|
||||
((AnnotationMetadata) metadata).getClassName());
|
||||
if (!environment.containsProperty("spring.session.store-type")) {
|
||||
return ConditionOutcome.match(message.didNotFind("property", "properties")
|
||||
.items(ConditionMessage.Style.QUOTE, "spring.session.store-type"));
|
||||
}
|
||||
try {
|
||||
Binder binder = Binder.get(environment);
|
||||
return binder.bind("spring.session.store-type", StoreType.class)
|
||||
.map((t) -> new ConditionOutcome(t == required,
|
||||
message.found("spring.session.store-type property").items(t)))
|
||||
.orElseGet(() -> ConditionOutcome
|
||||
.noMatch(message.didNotFind("spring.session.store-type property").atAll()));
|
||||
}
|
||||
catch (BindException ex) {
|
||||
return ConditionOutcome.noMatch(message.found("invalid spring.session.store-type property").atAll());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
@@ -44,7 +43,6 @@ import org.springframework.session.hazelcast.config.annotation.web.http.Hazelcas
|
||||
@ConditionalOnClass(HazelcastIndexedSessionRepository.class)
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@ConditionalOnBean(HazelcastInstance.class)
|
||||
@Conditional(ServletSessionCondition.class)
|
||||
@EnableConfigurationProperties(HazelcastSessionProperties.class)
|
||||
class HazelcastSessionConfiguration {
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi
|
||||
@ConditionalOnClass({ JdbcTemplate.class, JdbcIndexedSessionRepository.class })
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
@Conditional(ServletSessionCondition.class)
|
||||
@EnableConfigurationProperties(JdbcSessionProperties.class)
|
||||
@Import(DatabaseInitializationDependencyConfigurer.class)
|
||||
class JdbcSessionConfiguration {
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
@@ -41,7 +40,6 @@ import org.springframework.session.data.mongo.config.annotation.web.reactive.Rea
|
||||
@ConditionalOnClass({ ReactiveMongoOperations.class, ReactiveMongoSessionRepository.class })
|
||||
@ConditionalOnMissingBean(ReactiveSessionRepository.class)
|
||||
@ConditionalOnBean(ReactiveMongoOperations.class)
|
||||
@Conditional(ReactiveSessionCondition.class)
|
||||
@EnableConfigurationProperties(MongoSessionProperties.class)
|
||||
class MongoReactiveSessionConfiguration {
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.session.SessionRepository;
|
||||
@@ -41,7 +40,6 @@ import org.springframework.session.data.mongo.config.annotation.web.http.MongoHt
|
||||
@ConditionalOnClass({ MongoOperations.class, MongoIndexedSessionRepository.class })
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@ConditionalOnBean(MongoOperations.class)
|
||||
@Conditional(ServletSessionCondition.class)
|
||||
@EnableConfigurationProperties(MongoSessionProperties.class)
|
||||
class MongoSessionConfiguration {
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
|
||||
/**
|
||||
* No-op session configuration used to disable Spring Session using the environment.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(ReactiveSessionRepository.class)
|
||||
@Conditional(ReactiveSessionCondition.class)
|
||||
class NoOpReactiveSessionConfiguration {
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.SessionRepository;
|
||||
|
||||
/**
|
||||
* No-op session configuration used to disable Spring Session using the environment.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@Conditional(ServletSessionCondition.class)
|
||||
class NoOpSessionConfiguration {
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Exception thrown when multiple {@link SessionRepository} implementations are available
|
||||
* with no way to know which implementation should be used.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class NonUniqueSessionRepositoryException extends RuntimeException {
|
||||
|
||||
private final List<Class<?>> availableCandidates;
|
||||
|
||||
public NonUniqueSessionRepositoryException(List<Class<?>> availableCandidates) {
|
||||
super("Multiple session repository candidates are available, set the "
|
||||
+ "'spring.session.store-type' property accordingly");
|
||||
this.availableCandidates = (!ObjectUtils.isEmpty(availableCandidates) ? availableCandidates
|
||||
: Collections.emptyList());
|
||||
}
|
||||
|
||||
public List<Class<?>> getAvailableCandidates() {
|
||||
return this.availableCandidates;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
|
||||
/**
|
||||
* An {@link AbstractFailureAnalyzer} for {@link NonUniqueSessionRepositoryException}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class NonUniqueSessionRepositoryFailureAnalyzer extends AbstractFailureAnalyzer<NonUniqueSessionRepositoryException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, NonUniqueSessionRepositoryException cause) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(
|
||||
String.format("Multiple Spring Session store implementations are available on the classpath:%n"));
|
||||
for (Class<?> candidate : cause.getAvailableCandidates()) {
|
||||
message.append(String.format(" - %s%n", candidate.getName()));
|
||||
}
|
||||
StringBuilder action = new StringBuilder();
|
||||
action.append(String.format("Consider any of the following:%n"));
|
||||
action.append(
|
||||
String.format(" - Define the 'spring.session.store-type' property to the store you want to use%n"));
|
||||
action.append(String.format(" - Review your classpath and remove the unwanted store implementation(s)%n"));
|
||||
return new FailureAnalysis(message.toString(), action.toString(), cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
|
||||
/**
|
||||
* General condition used with all reactive session configuration classes.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ReactiveSessionCondition extends AbstractSessionCondition {
|
||||
|
||||
ReactiveSessionCondition() {
|
||||
super(WebApplicationType.REACTIVE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
@@ -41,7 +40,6 @@ import org.springframework.session.data.redis.config.annotation.web.server.Redis
|
||||
@ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisSessionRepository.class })
|
||||
@ConditionalOnMissingBean(ReactiveSessionRepository.class)
|
||||
@ConditionalOnBean(ReactiveRedisConnectionFactory.class)
|
||||
@Conditional(ReactiveSessionCondition.class)
|
||||
@EnableConfigurationProperties(RedisSessionProperties.class)
|
||||
class RedisReactiveSessionConfiguration {
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@@ -48,7 +47,6 @@ import org.springframework.session.data.redis.config.annotation.web.http.RedisIn
|
||||
@ConditionalOnClass({ RedisTemplate.class, RedisIndexedSessionRepository.class })
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@ConditionalOnBean(RedisConnectionFactory.class)
|
||||
@Conditional(ServletSessionCondition.class)
|
||||
@EnableConfigurationProperties(RedisSessionProperties.class)
|
||||
class RedisSessionConfiguration {
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
|
||||
/**
|
||||
* General condition used with all servlet session configuration classes.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Stephane Nicoll
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ServletSessionCondition extends AbstractSessionCondition {
|
||||
|
||||
ServletSessionCondition() {
|
||||
super(WebApplicationType.SERVLET);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,14 +17,8 @@
|
||||
package org.springframework.boot.autoconfigure.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
@@ -49,13 +43,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.web.server.Cookie.SameSite;
|
||||
import org.springframework.boot.web.servlet.server.Session.Cookie;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.session.ReactiveSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
@@ -90,7 +81,7 @@ public class SessionAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@Import({ ServletSessionRepositoryValidator.class, SessionRepositoryFilterConfiguration.class })
|
||||
@Import(SessionRepositoryFilterConfiguration.class)
|
||||
static class ServletSessionConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -125,8 +116,8 @@ public class SessionAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@Import({ ServletSessionRepositoryImplementationValidator.class,
|
||||
ServletSessionConfigurationImportSelector.class })
|
||||
@Import({ RedisSessionConfiguration.class, MongoSessionConfiguration.class, HazelcastSessionConfiguration.class,
|
||||
JdbcSessionConfiguration.class })
|
||||
static class ServletSessionRepositoryConfiguration {
|
||||
|
||||
}
|
||||
@@ -135,17 +126,10 @@ public class SessionAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
@Import(ReactiveSessionRepositoryValidator.class)
|
||||
@ConditionalOnMissingBean(ReactiveSessionRepository.class)
|
||||
@Import({ RedisReactiveSessionConfiguration.class, MongoReactiveSessionConfiguration.class })
|
||||
static class ReactiveSessionConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(ReactiveSessionRepository.class)
|
||||
@Import({ ReactiveSessionRepositoryImplementationValidator.class,
|
||||
ReactiveSessionConfigurationImportSelector.class })
|
||||
static class ReactiveSessionRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,175 +157,4 @@ public class SessionAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ImportSelector} base class to add {@link StoreType} configuration classes.
|
||||
*/
|
||||
abstract static class SessionConfigurationImportSelector implements ImportSelector {
|
||||
|
||||
protected final String[] selectImports(WebApplicationType webApplicationType) {
|
||||
return Arrays.stream(StoreType.values())
|
||||
.map((type) -> SessionStoreMappings.getConfigurationClass(webApplicationType, type))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ImportSelector} to add {@link StoreType} configuration classes for reactive
|
||||
* web applications.
|
||||
*/
|
||||
static class ReactiveSessionConfigurationImportSelector extends SessionConfigurationImportSelector {
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
return super.selectImports(WebApplicationType.REACTIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ImportSelector} to add {@link StoreType} configuration classes for Servlet
|
||||
* web applications.
|
||||
*/
|
||||
static class ServletSessionConfigurationImportSelector extends SessionConfigurationImportSelector {
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
return super.selectImports(WebApplicationType.SERVLET);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for beans used to validate that only one supported implementation is
|
||||
* available in the classpath when the store-type property is not set.
|
||||
*/
|
||||
abstract static class AbstractSessionRepositoryImplementationValidator {
|
||||
|
||||
private final List<String> candidates;
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private final SessionProperties sessionProperties;
|
||||
|
||||
AbstractSessionRepositoryImplementationValidator(ApplicationContext applicationContext,
|
||||
SessionProperties sessionProperties, List<String> candidates) {
|
||||
this.classLoader = applicationContext.getClassLoader();
|
||||
this.sessionProperties = sessionProperties;
|
||||
this.candidates = candidates;
|
||||
checkAvailableImplementations();
|
||||
}
|
||||
|
||||
private void checkAvailableImplementations() {
|
||||
List<Class<?>> availableCandidates = new ArrayList<>();
|
||||
for (String candidate : this.candidates) {
|
||||
addCandidateIfAvailable(availableCandidates, candidate);
|
||||
}
|
||||
StoreType storeType = this.sessionProperties.getStoreType();
|
||||
if (availableCandidates.size() > 1 && storeType == null) {
|
||||
throw new NonUniqueSessionRepositoryException(availableCandidates);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCandidateIfAvailable(List<Class<?>> candidates, String type) {
|
||||
try {
|
||||
candidates.add(Class.forName(type, false, this.classLoader));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean used to validate that only one supported implementation is available in the
|
||||
* classpath when the store-type property is not set.
|
||||
*/
|
||||
static class ServletSessionRepositoryImplementationValidator
|
||||
extends AbstractSessionRepositoryImplementationValidator {
|
||||
|
||||
ServletSessionRepositoryImplementationValidator(ApplicationContext applicationContext,
|
||||
SessionProperties sessionProperties) {
|
||||
super(applicationContext, sessionProperties,
|
||||
Arrays.asList("org.springframework.session.hazelcast.HazelcastIndexedSessionRepository",
|
||||
"org.springframework.session.jdbc.JdbcIndexedSessionRepository",
|
||||
"org.springframework.session.data.mongo.MongoIndexedSessionRepository",
|
||||
"org.springframework.session.data.redis.RedisIndexedSessionRepository"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean used to validate that only one supported implementation is available in the
|
||||
* classpath when the store-type property is not set.
|
||||
*/
|
||||
static class ReactiveSessionRepositoryImplementationValidator
|
||||
extends AbstractSessionRepositoryImplementationValidator {
|
||||
|
||||
ReactiveSessionRepositoryImplementationValidator(ApplicationContext applicationContext,
|
||||
SessionProperties sessionProperties) {
|
||||
super(applicationContext, sessionProperties,
|
||||
Arrays.asList("org.springframework.session.data.redis.ReactiveRedisSessionRepository",
|
||||
"org.springframework.session.data.mongo.ReactiveMongoSessionRepository"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for validating that a (reactive) session repository bean exists.
|
||||
*/
|
||||
abstract static class AbstractSessionRepositoryValidator implements InitializingBean {
|
||||
|
||||
private final SessionProperties sessionProperties;
|
||||
|
||||
private final ObjectProvider<?> sessionRepositoryProvider;
|
||||
|
||||
protected AbstractSessionRepositoryValidator(SessionProperties sessionProperties,
|
||||
ObjectProvider<?> sessionRepositoryProvider) {
|
||||
this.sessionProperties = sessionProperties;
|
||||
this.sessionRepositoryProvider = sessionRepositoryProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
StoreType storeType = this.sessionProperties.getStoreType();
|
||||
if (storeType != StoreType.NONE && this.sessionRepositoryProvider.getIfAvailable() == null
|
||||
&& storeType != null) {
|
||||
throw new SessionRepositoryUnavailableException(
|
||||
"No session repository could be auto-configured, check your "
|
||||
+ "configuration (session store type is '"
|
||||
+ storeType.name().toLowerCase(Locale.ENGLISH) + "')",
|
||||
storeType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean used to validate that a {@link SessionRepository} exists and provide a
|
||||
* meaningful message if that's not the case.
|
||||
*/
|
||||
static class ServletSessionRepositoryValidator extends AbstractSessionRepositoryValidator {
|
||||
|
||||
ServletSessionRepositoryValidator(SessionProperties sessionProperties,
|
||||
ObjectProvider<SessionRepository<?>> sessionRepositoryProvider) {
|
||||
super(sessionProperties, sessionRepositoryProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean used to validate that a {@link ReactiveSessionRepository} exists and provide a
|
||||
* meaningful message if that's not the case.
|
||||
*/
|
||||
static class ReactiveSessionRepositoryValidator extends AbstractSessionRepositoryValidator {
|
||||
|
||||
ReactiveSessionRepositoryValidator(SessionProperties sessionProperties,
|
||||
ObjectProvider<ReactiveSessionRepository<?>> sessionRepositoryProvider) {
|
||||
super(sessionProperties, sessionRepositoryProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,11 +39,6 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
@ConfigurationProperties(prefix = "spring.session")
|
||||
public class SessionProperties {
|
||||
|
||||
/**
|
||||
* Session store type.
|
||||
*/
|
||||
private StoreType storeType;
|
||||
|
||||
/**
|
||||
* Session timeout. If a duration suffix is not specified, seconds will be used.
|
||||
*/
|
||||
@@ -52,14 +47,6 @@ public class SessionProperties {
|
||||
|
||||
private Servlet servlet = new Servlet();
|
||||
|
||||
public StoreType getStoreType() {
|
||||
return this.storeType;
|
||||
}
|
||||
|
||||
public void setStoreType(StoreType storeType) {
|
||||
this.storeType = storeType;
|
||||
}
|
||||
|
||||
public Duration getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.session.SessionRepository;
|
||||
|
||||
/**
|
||||
* Exception thrown when no {@link SessionRepository} is available.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class SessionRepositoryUnavailableException extends RuntimeException {
|
||||
|
||||
private final StoreType storeType;
|
||||
|
||||
public SessionRepositoryUnavailableException(String message, StoreType storeType) {
|
||||
super(message);
|
||||
this.storeType = storeType;
|
||||
}
|
||||
|
||||
public StoreType getStoreType() {
|
||||
return this.storeType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Mappings between {@link StoreType} and {@code @Configuration}.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
final class SessionStoreMappings {
|
||||
|
||||
private static final Map<StoreType, Configurations> MAPPINGS;
|
||||
|
||||
static {
|
||||
Map<StoreType, Configurations> mappings = new EnumMap<>(StoreType.class);
|
||||
mappings.put(StoreType.REDIS,
|
||||
new Configurations(RedisSessionConfiguration.class, RedisReactiveSessionConfiguration.class));
|
||||
mappings.put(StoreType.MONGODB,
|
||||
new Configurations(MongoSessionConfiguration.class, MongoReactiveSessionConfiguration.class));
|
||||
mappings.put(StoreType.JDBC, new Configurations(JdbcSessionConfiguration.class, null));
|
||||
mappings.put(StoreType.HAZELCAST, new Configurations(HazelcastSessionConfiguration.class, null));
|
||||
mappings.put(StoreType.NONE,
|
||||
new Configurations(NoOpSessionConfiguration.class, NoOpReactiveSessionConfiguration.class));
|
||||
MAPPINGS = Collections.unmodifiableMap(mappings);
|
||||
}
|
||||
|
||||
private SessionStoreMappings() {
|
||||
}
|
||||
|
||||
static String getConfigurationClass(WebApplicationType webApplicationType, StoreType sessionStoreType) {
|
||||
Configurations configurations = MAPPINGS.get(sessionStoreType);
|
||||
Assert.state(configurations != null, () -> "Unknown session store type " + sessionStoreType);
|
||||
return configurations.getConfiguration(webApplicationType);
|
||||
}
|
||||
|
||||
static StoreType getType(WebApplicationType webApplicationType, String configurationClass) {
|
||||
return MAPPINGS.entrySet().stream()
|
||||
.filter((entry) -> ObjectUtils.nullSafeEquals(configurationClass,
|
||||
entry.getValue().getConfiguration(webApplicationType)))
|
||||
.map(Map.Entry::getKey).findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Unknown configuration class " + configurationClass));
|
||||
}
|
||||
|
||||
private static class Configurations {
|
||||
|
||||
private final Class<?> servletConfiguration;
|
||||
|
||||
private final Class<?> reactiveConfiguration;
|
||||
|
||||
Configurations(Class<?> servletConfiguration, Class<?> reactiveConfiguration) {
|
||||
this.servletConfiguration = servletConfiguration;
|
||||
this.reactiveConfiguration = reactiveConfiguration;
|
||||
}
|
||||
|
||||
String getConfiguration(WebApplicationType webApplicationType) {
|
||||
switch (webApplicationType) {
|
||||
case SERVLET:
|
||||
return getName(this.servletConfiguration);
|
||||
case REACTIVE:
|
||||
return getName(this.reactiveConfiguration);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String getName(Class<?> configuration) {
|
||||
return (configuration != null) ? configuration.getName() : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.boot.autoconfigure.session;
|
||||
|
||||
/**
|
||||
* Supported Spring Session data store types.
|
||||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Eddú Meléndez
|
||||
* @author Vedran Pavic
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public enum StoreType {
|
||||
|
||||
/**
|
||||
* Redis backed sessions.
|
||||
*/
|
||||
REDIS,
|
||||
|
||||
/**
|
||||
* MongoDB backed sessions.
|
||||
*/
|
||||
MONGODB,
|
||||
|
||||
/**
|
||||
* JDBC backed sessions.
|
||||
*/
|
||||
JDBC,
|
||||
|
||||
/**
|
||||
* Hazelcast backed sessions.
|
||||
*/
|
||||
HAZELCAST,
|
||||
|
||||
/**
|
||||
* No session data-store.
|
||||
*/
|
||||
NONE
|
||||
|
||||
}
|
||||
@@ -32,8 +32,7 @@ org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalzyer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
|
||||
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer
|
||||
|
||||
# Template availability providers
|
||||
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.boot.autoconfigure.session;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.diagnostics.FailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link NonUniqueSessionRepositoryFailureAnalyzer}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class NonUniqueSessionRepositoryFailureAnalyzerTests {
|
||||
|
||||
private final FailureAnalyzer analyzer = new NonUniqueSessionRepositoryFailureAnalyzer();
|
||||
|
||||
@Test
|
||||
void failureAnalysisWithMultipleCandidates() {
|
||||
FailureAnalysis analysis = analyzeFailure(
|
||||
createFailure(JdbcIndexedSessionRepository.class, HazelcastIndexedSessionRepository.class));
|
||||
assertThat(analysis).isNotNull();
|
||||
assertThat(analysis.getDescription()).contains(JdbcIndexedSessionRepository.class.getName(),
|
||||
HazelcastIndexedSessionRepository.class.getName());
|
||||
assertThat(analysis.getAction()).contains("spring.session.store-type");
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
private final Exception createFailure(Class<? extends SessionRepository<?>>... candidates) {
|
||||
return new NonUniqueSessionRepositoryException(Arrays.asList(candidates));
|
||||
}
|
||||
|
||||
private FailureAnalysis analyzeFailure(Exception failure) {
|
||||
FailureAnalysis analysis = this.analyzer.analyze(failure);
|
||||
if (analysis != null) {
|
||||
new LoggingFailureAnalysisReporter().report(analysis);
|
||||
}
|
||||
return analysis;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,35 +55,21 @@ class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConf
|
||||
.withStartupTimeout(Duration.ofMinutes(5));
|
||||
|
||||
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));
|
||||
.withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class, MongoAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class,
|
||||
MongoReactiveDataAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=mongodb",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesMongo("sessions"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithUniqueStoreImplementation() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class))
|
||||
.withPropertyValues("spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class))
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run(validateSpringSessionUsesMongo("sessions"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=mongodb", "spring.session.timeout=1m",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()).run((context) -> {
|
||||
ReactiveMongoSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveMongoSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("maxInactiveIntervalInSeconds", 60);
|
||||
@@ -92,12 +78,8 @@ class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConf
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomSessionTimeout() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=mongodb", "server.reactive.session.timeout=1m",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
this.contextRunner.withPropertyValues("server.reactive.session.timeout=1m",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()).run((context) -> {
|
||||
ReactiveMongoSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveMongoSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("maxInactiveIntervalInSeconds", 60);
|
||||
@@ -107,24 +89,26 @@ class ReactiveSessionAutoConfigurationMongoTests extends AbstractSessionAutoConf
|
||||
@Test
|
||||
void mongoSessionStoreWithCustomizations() {
|
||||
this.contextRunner
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=mongodb", "spring.session.mongodb.collection-name=foo",
|
||||
.withPropertyValues("spring.session.mongodb.collection-name=foo",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run(validateSpringSessionUsesMongo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() {
|
||||
AutoConfigurations autoConfigurations = AutoConfigurations.of(MongoAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class,
|
||||
AutoConfigurations autoConfigurations = AutoConfigurations.of(SessionAutoConfiguration.class,
|
||||
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class,
|
||||
MongoReactiveDataAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class);
|
||||
this.contextRunner.withConfiguration(autoConfigurations).withUserConfiguration(Config.class).withPropertyValues(
|
||||
"spring.session.store-type=mongodb", "server.reactive.session.cookie.name:JSESSIONID",
|
||||
"server.reactive.session.cookie.domain:.example.com", "server.reactive.session.cookie.path:/example",
|
||||
"server.reactive.session.cookie.max-age:60", "server.reactive.session.cookie.http-only:false",
|
||||
"server.reactive.session.cookie.secure:false", "server.reactive.session.cookie.same-site:strict",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl()).run(assertExchangeWithSession((exchange) -> {
|
||||
new ReactiveWebApplicationContextRunner().withConfiguration(autoConfigurations)
|
||||
.withUserConfiguration(Config.class)
|
||||
.withClassLoader(new FilteredClassLoader(ReactiveRedisSessionRepository.class))
|
||||
.withPropertyValues("server.reactive.session.cookie.name:JSESSIONID",
|
||||
"server.reactive.session.cookie.domain:.example.com",
|
||||
"server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60",
|
||||
"server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false",
|
||||
"server.reactive.session.cookie.same-site:strict",
|
||||
"spring.data.mongodb.uri=" + mongoDb.getReplicaSetUrl())
|
||||
.run(assertExchangeWithSession((exchange) -> {
|
||||
List<ResponseCookie> cookies = exchange.getResponse().getCookies().get("JSESSIONID");
|
||||
assertThat(cookies).isNotEmpty();
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getDomain().equals(".example.com"));
|
||||
|
||||
@@ -56,73 +56,57 @@ class ReactiveSessionAutoConfigurationRedisTests extends AbstractSessionAutoConf
|
||||
.withStartupTimeout(Duration.ofMinutes(10));
|
||||
|
||||
protected final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class));
|
||||
.withClassLoader(new FilteredClassLoader(ReactiveMongoSessionRepository.class)).withConfiguration(
|
||||
AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=redis")
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
this.contextRunner.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithUniqueStoreImplementation() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(ReactiveMongoSessionRepository.class))
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
void redisTakesPrecedenceMultipleImplementations() {
|
||||
ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(SessionAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class));
|
||||
contextRunner.run(validateSpringSessionUsesRedis("spring:session:", SaveMode.ON_SET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=redis", "spring.session.timeout=1m")
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomWebFluxTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=redis", "server.reactive.session.timeout=1m")
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("server.reactive.session.timeout=1m").run((context) -> {
|
||||
ReactiveRedisSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveRedisSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void redisSessionStoreWithCustomizations() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.session.redis.namespace=foo",
|
||||
.withPropertyValues("spring.session.redis.namespace=foo",
|
||||
"spring.session.redis.save-mode=on-get-attribute")
|
||||
.run(validateSpringSessionUsesRedis("foo:", SaveMode.ON_GET_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() {
|
||||
this.contextRunner
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class))
|
||||
.withUserConfiguration(Config.class)
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort(), "spring.session.store-type=redis",
|
||||
"server.reactive.session.cookie.name:JSESSIONID",
|
||||
"server.reactive.session.cookie.domain:.example.com",
|
||||
"server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60",
|
||||
"server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false",
|
||||
"server.reactive.session.cookie.same-site:strict")
|
||||
.run(assertExchangeWithSession((exchange) -> {
|
||||
this.contextRunner.withUserConfiguration(Config.class).withPropertyValues(
|
||||
"spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort(),
|
||||
"server.reactive.session.cookie.name:JSESSIONID", "server.reactive.session.cookie.domain:.example.com",
|
||||
"server.reactive.session.cookie.path:/example", "server.reactive.session.cookie.max-age:60",
|
||||
"server.reactive.session.cookie.http-only:false", "server.reactive.session.cookie.secure:false",
|
||||
"server.reactive.session.cookie.same-site:strict").run(assertExchangeWithSession((exchange) -> {
|
||||
List<ResponseCookie> cookies = exchange.getResponse().getCookies().get("JSESSIONID");
|
||||
assertThat(cookies).isNotEmpty();
|
||||
assertThat(cookies).allMatch((cookie) -> cookie.getDomain().equals(".example.com"));
|
||||
|
||||
@@ -47,30 +47,30 @@ import static org.mockito.Mockito.mock;
|
||||
class SessionAutoConfigurationHazelcastTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(JdbcIndexedSessionRepository.class,
|
||||
RedisIndexedSessionRepository.class, MongoIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class))
|
||||
.withUserConfiguration(HazelcastConfiguration.class);
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast").run(this::validateDefaultConfig);
|
||||
this.contextRunner.run(this::validateDefaultConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithUniqueStoreImplementation() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(JdbcIndexedSessionRepository.class,
|
||||
RedisIndexedSessionRepository.class, MongoIndexedSessionRepository.class))
|
||||
void hazelcastTakesPrecedenceOverJdbc() {
|
||||
this.contextRunner.withClassLoader(
|
||||
new FilteredClassLoader(RedisIndexedSessionRepository.class, MongoIndexedSessionRepository.class))
|
||||
.run(this::validateDefaultConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast", "spring.session.timeout=1m")
|
||||
.run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
}
|
||||
|
||||
private void validateDefaultConfig(AssertableWebApplicationContext context) {
|
||||
@@ -84,32 +84,29 @@ class SessionAutoConfigurationHazelcastTests extends AbstractSessionAutoConfigur
|
||||
|
||||
@Test
|
||||
void customMapName() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast",
|
||||
"spring.session.hazelcast.map-name=foo:bar:biz").run((context) -> {
|
||||
validateSessionRepository(context, HazelcastIndexedSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);
|
||||
then(hazelcastInstance).should().getMap("foo:bar:biz");
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.hazelcast.map-name=foo:bar:biz").run((context) -> {
|
||||
validateSessionRepository(context, HazelcastIndexedSessionRepository.class);
|
||||
HazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);
|
||||
then(hazelcastInstance).should().getMap("foo:bar:biz");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customFlushMode() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast",
|
||||
"spring.session.hazelcast.flush-mode=immediate").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.hazelcast.flush-mode=immediate").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSaveMode() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=hazelcast",
|
||||
"spring.session.hazelcast.save-mode=on-get-attribute").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.hazelcast.save-mode=on-get-attribute").run((context) -> {
|
||||
HazelcastIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
HazelcastIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.boot.autoconfigure.session;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link SessionAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class SessionAutoConfigurationIntegrationTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class, SessionAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
||||
|
||||
@Test
|
||||
void severalCandidatesWithNoSessionStore() {
|
||||
this.contextRunner.withUserConfiguration(HazelcastConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().rootCause().isInstanceOf(NonUniqueSessionRepositoryException.class)
|
||||
.hasMessageContaining("Multiple session repository candidates are available")
|
||||
.hasMessageContaining("set the 'spring.session.store-type' property accordingly");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void severalCandidatesWithWrongSessionStore() {
|
||||
this.contextRunner.withUserConfiguration(HazelcastConfiguration.class)
|
||||
.withPropertyValues("spring.session.store-type=redis").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().hasCauseInstanceOf(SessionRepositoryUnavailableException.class);
|
||||
assertThat(context).getFailure()
|
||||
.hasMessageContaining("No session repository could be auto-configured");
|
||||
assertThat(context).getFailure().hasMessageContaining("session store type is 'redis'");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void severalCandidatesWithValidSessionStore() {
|
||||
this.contextRunner.withUserConfiguration(HazelcastConfiguration.class)
|
||||
.withPropertyValues("spring.session.store-type=jdbc")
|
||||
.run((context) -> validateSessionRepository(context, JdbcIndexedSessionRepository.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class HazelcastConfiguration {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
HazelcastInstance hazelcastInstance() {
|
||||
IMap<Object, Object> map = mock(IMap.class);
|
||||
HazelcastInstance mock = mock(HazelcastInstance.class);
|
||||
given(mock.getMap("spring:session:sessions")).willReturn(map);
|
||||
given(mock.getMap("foo:bar:biz")).willReturn(map);
|
||||
return mock;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,6 +62,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
MongoIndexedSessionRepository.class, RedisIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
|
||||
SessionAutoConfiguration.class))
|
||||
@@ -69,15 +71,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run(this::validateDefaultConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithUniqueStoreImplementation() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
MongoIndexedSessionRepository.class, RedisIndexedSessionRepository.class))
|
||||
.run(this::validateDefaultConfig);
|
||||
this.contextRunner.run(this::validateDefaultConfig);
|
||||
}
|
||||
|
||||
private void validateDefaultConfig(AssertableWebApplicationContext context) {
|
||||
@@ -96,46 +90,39 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
|
||||
@Test
|
||||
void filterOrderCanBeCustomized() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.servlet.filter-order=123")
|
||||
.run((context) -> {
|
||||
FilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);
|
||||
assertThat(registration.getOrder()).isEqualTo(123);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.servlet.filter-order=123").run((context) -> {
|
||||
FilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);
|
||||
assertThat(registration.getOrder()).isEqualTo(123);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void disableDataSourceInitializer() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never")
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class);
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION");
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
|
||||
.isEqualTo(DatabaseInitializationMode.NEVER);
|
||||
assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy(
|
||||
() -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION"));
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class);
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION");
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
|
||||
.isEqualTo(DatabaseInitializationMode.NEVER);
|
||||
assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy(
|
||||
() -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc", "spring.session.timeout=1m")
|
||||
.run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", 60);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTableName() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.table-name=FOO_BAR",
|
||||
"spring.session.jdbc.schema=classpath:session/custom-schema-h2.sql")
|
||||
.run((context) -> {
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.table-name=FOO_BAR",
|
||||
"spring.session.jdbc.schema=classpath:session/custom-schema-h2.sql").run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "FOO_BAR");
|
||||
@@ -147,60 +134,51 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
|
||||
@Test
|
||||
void customCleanupCron() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.cleanup-cron=0 0 12 * * *")
|
||||
.run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *");
|
||||
SpringBootJdbcHttpSessionConfiguration configuration = context
|
||||
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *");
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.cleanup-cron=0 0 12 * * *").run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *");
|
||||
SpringBootJdbcHttpSessionConfiguration configuration = context
|
||||
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customFlushMode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.flush-mode=immediate")
|
||||
.run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getFlushMode())
|
||||
.isEqualTo(FlushMode.IMMEDIATE);
|
||||
SpringBootJdbcHttpSessionConfiguration configuration = context
|
||||
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.flush-mode=immediate").run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getFlushMode()).isEqualTo(FlushMode.IMMEDIATE);
|
||||
SpringBootJdbcHttpSessionConfiguration configuration = context
|
||||
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSaveMode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.save-mode=on-get-attribute")
|
||||
.run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getSaveMode())
|
||||
.isEqualTo(SaveMode.ON_GET_ATTRIBUTE);
|
||||
SpringBootJdbcHttpSessionConfiguration configuration = context
|
||||
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.save-mode=on-get-attribute").run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getSaveMode()).isEqualTo(SaveMode.ON_GET_ATTRIBUTE);
|
||||
SpringBootJdbcHttpSessionConfiguration configuration = context
|
||||
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
|
||||
assertThat(configuration).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionDataSourceIsUsedWhenAvailable() {
|
||||
this.contextRunner.withUserConfiguration(SessionDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.session.store-type=jdbc").run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
DataSource sessionDataSource = context.getBean("sessionDataSource", DataSource.class);
|
||||
assertThat(repository).extracting("jdbcOperations.dataSource").isEqualTo(sessionDataSource);
|
||||
assertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class))
|
||||
.hasFieldOrPropertyWithValue("dataSource", sessionDataSource);
|
||||
assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy(
|
||||
() -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION"));
|
||||
});
|
||||
this.contextRunner.withUserConfiguration(SessionDataSourceConfiguration.class).run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
DataSource sessionDataSource = context.getBean("sessionDataSource", DataSource.class);
|
||||
assertThat(repository).extracting("jdbcOperations.dataSource").isEqualTo(sessionDataSource);
|
||||
assertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class))
|
||||
.hasFieldOrPropertyWithValue("dataSource", sessionDataSource);
|
||||
assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy(
|
||||
() -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionRepositoryBeansDependOnJdbcSessionDataSourceInitializer() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run((context) -> {
|
||||
this.contextRunner.run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
String[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class);
|
||||
assertThat(sessionRepositoryNames).isNotEmpty();
|
||||
@@ -214,8 +192,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
@Test
|
||||
void sessionRepositoryBeansDependOnFlyway() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never")
|
||||
.run((context) -> {
|
||||
.withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
String[] sessionRepositoryNames = beanFactory
|
||||
.getBeanNamesForType(JdbcIndexedSessionRepository.class);
|
||||
@@ -230,8 +207,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
@Test
|
||||
void sessionRepositoryBeansDependOnLiquibase() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never")
|
||||
.run((context) -> {
|
||||
.withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
String[] sessionRepositoryNames = beanFactory
|
||||
.getBeanNamesForType(JdbcIndexedSessionRepository.class);
|
||||
@@ -248,7 +224,6 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
this.contextRunner.withUserConfiguration(CustomJdbcSessionDatabaseInitializerConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=jdbc")
|
||||
.run((context) -> assertThat(context)
|
||||
.hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)
|
||||
.doesNotHaveBean("jdbcSessionDataSourceScriptDatabaseInitializer")
|
||||
@@ -260,7 +235,6 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
|
||||
this.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=jdbc")
|
||||
.run((context) -> assertThat(context)
|
||||
.hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)
|
||||
.hasBean("customInitializer"));
|
||||
|
||||
@@ -52,34 +52,32 @@ class SessionAutoConfigurationMongoTests extends AbstractSessionAutoConfiguratio
|
||||
.withStartupTimeout(Duration.ofMinutes(5));
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
JdbcIndexedSessionRepository.class, RedisIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
SessionAutoConfiguration.class))
|
||||
.withPropertyValues("spring.data.mongodb.uri=" + mongoDB.getReplicaSetUrl());
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=mongodb")
|
||||
.run(validateSpringSessionUsesMongo("sessions"));
|
||||
this.contextRunner.run(validateSpringSessionUsesMongo("sessions"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithUniqueStoreImplementation() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
JdbcIndexedSessionRepository.class, RedisIndexedSessionRepository.class))
|
||||
void mongoTakesPrecedenceOverJdbcAndHazelcast() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(RedisIndexedSessionRepository.class))
|
||||
.run(validateSpringSessionUsesMongo("sessions"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=mongodb", "spring.session.timeout=1m")
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m")
|
||||
.run(validateSpringSessionUsesMongo("sessions", Duration.ofMinutes(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mongoSessionStoreWithCustomizations() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=mongodb", "spring.session.mongodb.collection-name=foo")
|
||||
this.contextRunner.withPropertyValues("spring.session.mongodb.collection-name=foo")
|
||||
.run(validateSpringSessionUsesMongo("foo"));
|
||||
}
|
||||
|
||||
|
||||
@@ -60,12 +60,14 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
.withStartupTimeout(Duration.ofMinutes(10));
|
||||
|
||||
protected final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
JdbcIndexedSessionRepository.class, MongoIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(),
|
||||
.withPropertyValues("spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort())
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.run(validateSpringSessionUsesRedis("spring:session:event:0:created:", FlushMode.ON_SAVE,
|
||||
@@ -73,11 +75,8 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfigWithUniqueStoreImplementation() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(HazelcastIndexedSessionRepository.class,
|
||||
JdbcIndexedSessionRepository.class, MongoIndexedSessionRepository.class))
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
void redisTakesPrecedenceMultipleImplementations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateSpringSessionUsesRedis("spring:session:event:0:created:", FlushMode.ON_SAVE,
|
||||
@@ -87,7 +86,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
@Test
|
||||
void defaultConfigWithCustomTimeout() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(),
|
||||
.withPropertyValues("spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort(), "spring.session.timeout=1m")
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)).run((context) -> {
|
||||
RedisIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
@@ -99,8 +98,8 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
@Test
|
||||
void redisSessionStoreWithCustomizations() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.session.redis.namespace=foo",
|
||||
"spring.session.redis.flush-mode=immediate", "spring.session.redis.save-mode=on-get-attribute",
|
||||
.withPropertyValues("spring.session.redis.namespace=foo", "spring.session.redis.flush-mode=immediate",
|
||||
"spring.session.redis.save-mode=on-get-attribute",
|
||||
"spring.session.redis.cleanup-cron=0 0 12 * * *", "spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateSpringSessionUsesRedis("foo:event:0:created:", FlushMode.IMMEDIATE,
|
||||
@@ -110,7 +109,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
@Test
|
||||
void redisSessionWithConfigureActionNone() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.session.redis.configure-action=none",
|
||||
.withPropertyValues("spring.session.redis.configure-action=none",
|
||||
"spring.redis.host=" + redis.getHost(), "spring.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(ConfigureRedisAction.NO_OP.getClass()));
|
||||
}
|
||||
@@ -118,7 +117,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
@Test
|
||||
void redisSessionWithDefaultConfigureActionNone() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(),
|
||||
.withPropertyValues("spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(ConfigureNotifyKeyspaceEventsAction.class,
|
||||
entry("notify-keyspace-events", "gxE")));
|
||||
@@ -128,7 +127,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
|
||||
void redisSessionWithCustomConfigureRedisActionBean() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||
.withUserConfiguration(MaxEntriesRedisAction.class)
|
||||
.withPropertyValues("spring.session.store-type=redis", "spring.redis.host=" + redis.getHost(),
|
||||
.withPropertyValues("spring.redis.host=" + redis.getHost(),
|
||||
"spring.redis.port=" + redis.getFirstMappedPort())
|
||||
.run(validateStrategy(MaxEntriesRedisAction.class, entry("set-max-intset-entries", "1024")));
|
||||
|
||||
|
||||
@@ -26,14 +26,22 @@ import org.mockito.InOrder;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.ReactiveMapSessionRepository;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
|
||||
import org.springframework.session.config.annotation.web.server.EnableSpringWebSession;
|
||||
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
|
||||
import org.springframework.session.data.redis.RedisIndexedSessionRepository;
|
||||
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
|
||||
import org.springframework.session.web.http.CookieHttpSessionIdResolver;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
@@ -60,37 +68,31 @@ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTest
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void contextFailsIfMultipleStoresAreAvailable() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().rootCause().isInstanceOf(NonUniqueSessionRepositoryException.class)
|
||||
.hasMessageContaining("Multiple session repository candidates are available");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextFailsIfStoreTypeNotAvailable() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().hasCauseInstanceOf(SessionRepositoryUnavailableException.class);
|
||||
assertThat(context).getFailure().hasMessageContaining("No session repository could be auto-configured");
|
||||
assertThat(context).getFailure().hasMessageContaining("session store type is 'jdbc'");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationDisabledIfStoreTypeSetToNone() {
|
||||
this.contextRunner.withPropertyValues("spring.session.store-type=none")
|
||||
void autoConfigurationDisabledIfNoImplementationMatches() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(RedisIndexedSessionRepository.class,
|
||||
HazelcastIndexedSessionRepository.class, JdbcIndexedSessionRepository.class,
|
||||
MongoIndexedSessionRepository.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(SessionRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void backOffIfSessionRepositoryIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)
|
||||
.withPropertyValues("spring.session.store-type=redis").run((context) -> {
|
||||
MapSessionRepository repository = validateSessionRepository(context, MapSessionRepository.class);
|
||||
assertThat(context).getBean("mySessionRepository").isSameAs(repository);
|
||||
});
|
||||
this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class).run((context) -> {
|
||||
MapSessionRepository repository = validateSessionRepository(context, MapSessionRepository.class);
|
||||
assertThat(context).getBean("mySessionRepository").isSameAs(repository);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void backOffIfReactiveSessionRepositoryIsPresent() {
|
||||
ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));
|
||||
contextRunner.withUserConfiguration(ReactiveSessionRepositoryConfiguration.class).run((context) -> {
|
||||
ReactiveMapSessionRepository repository = validateSessionRepository(context,
|
||||
ReactiveMapSessionRepository.class);
|
||||
assertThat(context).getBean("mySessionRepository").isSameAs(repository);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -220,6 +222,17 @@ class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTest
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableSpringWebSession
|
||||
static class ReactiveSessionRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
ReactiveMapSessionRepository mySessionRepository() {
|
||||
return new ReactiveMapSessionRepository(Collections.emptyMap());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableConfigurationProperties(ServerProperties.class)
|
||||
static class ServerPropertiesConfiguration {
|
||||
|
||||
|
||||
@@ -3,15 +3,25 @@
|
||||
Spring Boot provides {spring-session}[Spring Session] auto-configuration for a wide range of data stores.
|
||||
When building a servlet web application, the following stores can be auto-configured:
|
||||
|
||||
* JDBC
|
||||
* Redis
|
||||
* Hazelcast
|
||||
* MongoDB
|
||||
* Hazelcast
|
||||
* JDBC
|
||||
|
||||
Additionally, {spring-boot-for-apache-geode}[Spring Boot for Apache Geode] provides {spring-boot-for-apache-geode-docs}#geode-session[auto-configuration for using Apache Geode as a session store].
|
||||
|
||||
The servlet auto-configuration replaces the need to use `@Enable*HttpSession`.
|
||||
|
||||
If a single Spring Session module is present on the classpath, Spring Boot uses that store implementation automatically.
|
||||
If you have more than one implementation, Spring Boot uses the following order for choosing a specific implementation:
|
||||
|
||||
. Redis
|
||||
. MongoDB
|
||||
. Hazelcast
|
||||
. JDBC
|
||||
. If none of Redis, MongoDB, Hazelcast and JDBC are available, we do not configure a `SessionRepository`.
|
||||
|
||||
|
||||
When building a reactive web application, the following stores can be auto-configured:
|
||||
|
||||
* Redis
|
||||
@@ -19,18 +29,12 @@ When building a reactive web application, the following stores can be auto-confi
|
||||
|
||||
The reactive auto-configuration replaces the need to use `@Enable*WebSession`.
|
||||
|
||||
If a single Spring Session module is present on the classpath, Spring Boot uses that store implementation automatically.
|
||||
If you have more than one implementation, you must choose the {spring-boot-autoconfigure-module-code}/session/StoreType.java[`StoreType`] that you wish to use to store the sessions.
|
||||
For instance, to use JDBC as the back-end store, you can configure your application as follows:
|
||||
Similar to the servlet configuration, if you have more than one implementation, Spring Boot uses the following order for choosing a specific implementation:
|
||||
|
||||
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
|
||||
----
|
||||
spring:
|
||||
session:
|
||||
store-type: "jdbc"
|
||||
----
|
||||
. Redis
|
||||
. MongoDB
|
||||
. If neither Redis nor MongoDB are available, we do not configure a `ReactiveSessionRepository`.
|
||||
|
||||
TIP: You can disable Spring Session by setting the `store-type` to `none`.
|
||||
|
||||
Each store has specific additional settings.
|
||||
For instance, it is possible to customize the name of the table for the JDBC store, as shown in the following example:
|
||||
|
||||
Reference in New Issue
Block a user