Improve JDBC configuration
This commit improves JDBC configuration by introducing `@SpringSessionDataSource` qualifier for explicitly declaring a `DataSource` to be used by Spring Session. This is in particular useful in scenarios with multiple `DataSource` beans present in the application context. As a consequence, JDBC configuration is simplified and no longer registers a Spring Session specific `JdbcTemplate` bean. Closes gh-863
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.session.jdbc.config.annotation.web.http;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -20,6 +21,7 @@ import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
@@ -33,14 +35,11 @@ import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
import org.springframework.core.serializer.support.SerializingConverter;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
|
||||
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
@@ -78,17 +77,17 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
@Bean
|
||||
public JdbcTemplate springSessionJdbcOperations(DataSource dataSource) {
|
||||
return new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdbcOperationsSessionRepository sessionRepository(
|
||||
@Qualifier("springSessionJdbcOperations") JdbcOperations jdbcOperations,
|
||||
@SpringSessionDataSource ObjectProvider<DataSource> springSessionDataSource,
|
||||
ObjectProvider<DataSource> dataSource,
|
||||
PlatformTransactionManager transactionManager) {
|
||||
JdbcOperationsSessionRepository sessionRepository =
|
||||
new JdbcOperationsSessionRepository(jdbcOperations, transactionManager);
|
||||
DataSource dataSourceToUse = springSessionDataSource.getIfAvailable();
|
||||
if (dataSourceToUse == null) {
|
||||
dataSourceToUse = dataSource.getObject();
|
||||
}
|
||||
JdbcOperationsSessionRepository sessionRepository = new JdbcOperationsSessionRepository(
|
||||
dataSourceToUse, transactionManager);
|
||||
String tableName = getTableName();
|
||||
if (StringUtils.hasText(tableName)) {
|
||||
sessionRepository.setTableName(tableName);
|
||||
@@ -104,7 +103,7 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
else if (this.conversionService != null) {
|
||||
sessionRepository.setConversionService(this.conversionService);
|
||||
}
|
||||
else if (deserializingConverterSupportsCustomClassLoader()) {
|
||||
else {
|
||||
GenericConversionService conversionService = createConversionServiceWithBeanClassLoader();
|
||||
sessionRepository.setConversionService(conversionService);
|
||||
}
|
||||
@@ -115,7 +114,7 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
* This must be a separate method because some ClassLoaders load the entire method
|
||||
* definition even if an if statement guards against it loading. This means that older
|
||||
* versions of Spring would cause a NoSuchMethodError if this were defined in
|
||||
* {@link #sessionRepository(JdbcOperations, PlatformTransactionManager)}.
|
||||
* {@link #sessionRepository(ObjectProvider, ObjectProvider, PlatformTransactionManager)}.
|
||||
*
|
||||
* @return the default {@link ConversionService}
|
||||
*/
|
||||
@@ -163,10 +162,6 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
return this.tableName;
|
||||
}
|
||||
|
||||
private boolean deserializingConverterSupportsCustomClassLoader() {
|
||||
return ClassUtils.hasConstructor(DeserializingConverter.class, ClassLoader.class);
|
||||
}
|
||||
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> enableAttrMap = importMetadata
|
||||
.getAnnotationAttributes(EnableJdbcHttpSession.class.getName());
|
||||
@@ -192,4 +187,5 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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
|
||||
*
|
||||
* http://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.jdbc.config.annotation.web.http;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for a {@link DataSource} to be injected in
|
||||
* {@link JdbcOperationsSessionRepository}.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,
|
||||
ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Qualifier
|
||||
public @interface SpringSessionDataSource {
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -23,12 +23,14 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
||||
@@ -67,10 +69,10 @@ public class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void noDataSourceConfiguration() {
|
||||
this.thrown.expect(UnsatisfiedDependencyException.class);
|
||||
this.thrown.expectMessage("springSessionJdbcOperations");
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("sessionRepository");
|
||||
|
||||
registerAndRefresh(EmptyConfiguration.class);
|
||||
registerAndRefresh(NoDataSourceConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -145,6 +147,78 @@ public class JdbcHttpSessionConfigurationTests {
|
||||
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifiedDataSourceConfiguration() {
|
||||
registerAndRefresh(QualifiedDataSourceConfiguration.class);
|
||||
|
||||
JdbcOperationsSessionRepository repository = this.context
|
||||
.getBean(JdbcOperationsSessionRepository.class);
|
||||
DataSource dataSource = this.context.getBean("qualifiedDataSource", DataSource.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(dataSource).isNotNull();
|
||||
JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils
|
||||
.getField(repository, "jdbcOperations");
|
||||
assertThat(jdbcOperations).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource"))
|
||||
.isEqualTo(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void primaryDataSourceConfiguration() {
|
||||
registerAndRefresh(PrimaryDataSourceConfiguration.class);
|
||||
|
||||
JdbcOperationsSessionRepository repository = this.context
|
||||
.getBean(JdbcOperationsSessionRepository.class);
|
||||
DataSource dataSource = this.context.getBean("primaryDataSource", DataSource.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(dataSource).isNotNull();
|
||||
JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils
|
||||
.getField(repository, "jdbcOperations");
|
||||
assertThat(jdbcOperations).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource"))
|
||||
.isEqualTo(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifiedAndPrimaryDataSourceConfiguration() {
|
||||
registerAndRefresh(QualifiedAndPrimaryDataSourceConfiguration.class);
|
||||
|
||||
JdbcOperationsSessionRepository repository = this.context
|
||||
.getBean(JdbcOperationsSessionRepository.class);
|
||||
DataSource dataSource = this.context.getBean("qualifiedDataSource", DataSource.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(dataSource).isNotNull();
|
||||
JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils
|
||||
.getField(repository, "jdbcOperations");
|
||||
assertThat(jdbcOperations).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource"))
|
||||
.isEqualTo(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namedDataSourceConfiguration() {
|
||||
registerAndRefresh(NamedDataSourceConfiguration.class);
|
||||
|
||||
JdbcOperationsSessionRepository repository = this.context
|
||||
.getBean(JdbcOperationsSessionRepository.class);
|
||||
DataSource dataSource = this.context.getBean("dataSource", DataSource.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(dataSource).isNotNull();
|
||||
JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils
|
||||
.getField(repository, "jdbcOperations");
|
||||
assertThat(jdbcOperations).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource"))
|
||||
.isEqualTo(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleDataSourceConfiguration() {
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("sessionRepository");
|
||||
|
||||
registerAndRefresh(MultipleDataSourceConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customLobHandlerConfiguration() {
|
||||
registerAndRefresh(CustomLobHandlerConfiguration.class);
|
||||
@@ -188,13 +262,13 @@ public class JdbcHttpSessionConfigurationTests {
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class EmptyConfiguration {
|
||||
static class NoDataSourceConfiguration {
|
||||
}
|
||||
|
||||
static class BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
public DataSource defaultDataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
@@ -239,6 +313,70 @@ public class JdbcHttpSessionConfigurationTests {
|
||||
extends BaseConfiguration {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class QualifiedDataSourceConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
@SpringSessionDataSource
|
||||
public DataSource qualifiedDataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class PrimaryDataSourceConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource primaryDataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class QualifiedAndPrimaryDataSourceConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
@SpringSessionDataSource
|
||||
public DataSource qualifiedDataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource primaryDataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class NamedDataSourceConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class MultipleDataSourceConfiguration extends BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSource secondaryDataSource() {
|
||||
return mock(DataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession
|
||||
static class CustomLobHandlerConfiguration extends BaseConfiguration {
|
||||
|
||||
Reference in New Issue
Block a user