parent
2b970f9efc
commit
a251ea8bc7
|
@ -21,8 +21,10 @@ import javax.sql.DataSource;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration;
|
||||
|
||||
|
@ -31,6 +33,7 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi
|
|||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
|
@ -38,6 +41,14 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi
|
|||
@Conditional(SessionCondition.class)
|
||||
class JdbcSessionConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public JdbcSessionDatabaseInitializer jdbcSessionDatabaseInitializer(
|
||||
SessionProperties properties, DataSource dataSource,
|
||||
ResourceLoader resourceLoader) {
|
||||
return new JdbcSessionDatabaseInitializer(properties, dataSource, resourceLoader);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class SpringBootJdbcHttpSessionConfiguration
|
||||
extends JdbcHttpSessionConfiguration {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.boot.autoconfigure.session;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Initializer for Spring Session schema.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class JdbcSessionDatabaseInitializer {
|
||||
|
||||
private SessionProperties properties;
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
public JdbcSessionDatabaseInitializer(SessionProperties properties,
|
||||
DataSource dataSource, ResourceLoader resourceLoader) {
|
||||
Assert.notNull(properties, "SessionProperties must not be null");
|
||||
Assert.notNull(dataSource, "DataSource must not be null");
|
||||
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
|
||||
this.properties = properties;
|
||||
this.dataSource = dataSource;
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void initialize() {
|
||||
if (!this.properties.getJdbc().getInitializer().isEnabled()) {
|
||||
return;
|
||||
}
|
||||
String platform = getDatabaseType();
|
||||
if ("hsql".equals(platform)) {
|
||||
platform = "hsqldb";
|
||||
}
|
||||
if ("postgres".equals(platform)) {
|
||||
platform = "postgresql";
|
||||
}
|
||||
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
String schemaLocation = this.properties.getJdbc().getSchema();
|
||||
schemaLocation = schemaLocation.replace("@@platform@@", platform);
|
||||
populator.addScript(this.resourceLoader.getResource(schemaLocation));
|
||||
populator.setContinueOnError(true);
|
||||
DatabasePopulatorUtils.execute(populator, this.dataSource);
|
||||
}
|
||||
|
||||
private String getDatabaseType() {
|
||||
try {
|
||||
String databaseProductName = JdbcUtils.extractDatabaseMetaData(
|
||||
this.dataSource, "getDatabaseProductName").toString();
|
||||
return JdbcUtils.commonDatabaseName(databaseProductName).toLowerCase();
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
throw new IllegalStateException("Unable to detect database type", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.springframework.session.data.redis.RedisFlushMode;
|
|||
*
|
||||
* @author Tommy Ludwig
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.session")
|
||||
|
@ -103,11 +104,29 @@ public class SessionProperties {
|
|||
|
||||
public static class Jdbc {
|
||||
|
||||
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
|
||||
+ "session/jdbc/schema-@@platform@@.sql";
|
||||
|
||||
/**
|
||||
* Path to the SQL file to use to initialize the database schema.
|
||||
*/
|
||||
private String schema = DEFAULT_SCHEMA_LOCATION;
|
||||
|
||||
/**
|
||||
* Name of database table used to store sessions.
|
||||
*/
|
||||
private String tableName = "SPRING_SESSION";
|
||||
|
||||
private final Initializer initializer = new Initializer();
|
||||
|
||||
public String getSchema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
public void setSchema(String schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return this.tableName;
|
||||
}
|
||||
|
@ -116,6 +135,27 @@ public class SessionProperties {
|
|||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public Initializer getInitializer() {
|
||||
return initializer;
|
||||
}
|
||||
|
||||
public static class Initializer {
|
||||
|
||||
/**
|
||||
* Create the required session tables on startup if necessary.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Mongo {
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.boot.autoconfigure.session;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* JDBC specific tests for {@link SessionAutoConfiguration}.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
public class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void defaultConfig() {
|
||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class),
|
||||
"spring.session.store-type=jdbc");
|
||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||
JdbcOperationsSessionRepository.class);
|
||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||
.isEqualTo("SPRING_SESSION");
|
||||
assertThat(this.context.getBean(JdbcOperations.class)
|
||||
.queryForList("select * from SPRING_SESSION")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usingJpa() {
|
||||
load(Arrays.<Class<?>>asList(EmbeddedDataSourceConfiguration.class,
|
||||
HibernateJpaAutoConfiguration.class),
|
||||
"spring.session.store-type=jdbc");
|
||||
PlatformTransactionManager transactionManager = this.context
|
||||
.getBean(PlatformTransactionManager.class);
|
||||
assertThat(transactionManager.toString().contains("JpaTransactionManager"))
|
||||
.isTrue();
|
||||
assertThat(this.context.getBean(EntityManagerFactory.class)).isNotNull();
|
||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||
JdbcOperationsSessionRepository.class);
|
||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||
.isEqualTo("SPRING_SESSION");
|
||||
assertThat(this.context.getBean(JdbcOperations.class)
|
||||
.queryForList("select * from SPRING_SESSION")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableDatabaseInitializer() {
|
||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class),
|
||||
"spring.session.store-type=jdbc",
|
||||
"spring.session.jdbc.initializer.enabled=false");
|
||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||
JdbcOperationsSessionRepository.class);
|
||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||
.isEqualTo("SPRING_SESSION");
|
||||
this.expected.expect(BadSqlGrammarException.class);
|
||||
assertThat(this.context.getBean(JdbcOperations.class)
|
||||
.queryForList("select * from SPRING_SESSION")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customTableName() {
|
||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class),
|
||||
"spring.session.store-type=jdbc",
|
||||
"spring.session.jdbc.table-name=FOO_BAR",
|
||||
"spring.session.jdbc.schema=classpath:session/custom-schema-h2.sql");
|
||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||
JdbcOperationsSessionRepository.class);
|
||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||
.isEqualTo("FOO_BAR");
|
||||
assertThat(this.context.getBean(JdbcOperations.class)
|
||||
.queryForList("select * from FOO_BAR")).isEmpty();
|
||||
}
|
||||
|
||||
}
|
|
@ -29,8 +29,6 @@ import org.junit.rules.ExpectedException;
|
|||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -39,7 +37,6 @@ import org.springframework.session.ExpiringSession;
|
|||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
|
||||
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
@ -106,29 +103,6 @@ public class SessionAutoConfigurationTests extends AbstractSessionAutoConfigurat
|
|||
assertThat(getSessionTimeout(repository)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jdbcSessionStore() {
|
||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class),
|
||||
"spring.session.store-type=jdbc");
|
||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||
JdbcOperationsSessionRepository.class);
|
||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||
.isEqualTo("SPRING_SESSION");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jdbcSessionStoreCustomTableName() {
|
||||
load(Arrays.asList(EmbeddedDataSourceConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class),
|
||||
"spring.session.store-type=jdbc",
|
||||
"spring.session.jdbc.table-name=FOO_BAR");
|
||||
JdbcOperationsSessionRepository repository = validateSessionRepository(
|
||||
JdbcOperationsSessionRepository.class);
|
||||
assertThat(new DirectFieldAccessor(repository).getPropertyValue("tableName"))
|
||||
.isEqualTo("FOO_BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hazelcastSessionStore() {
|
||||
load(Collections.<Class<?>>singletonList(HazelcastConfiguration.class),
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE FOO_BAR (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
CONSTRAINT FOO_BAR_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX FOO_BAR_IX1 ON FOO_BAR (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE FOO_BAR_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES LONGVARBINARY,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES FOO_BAR(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX FOO_BAR_ATTRIBUTES_IX1 ON FOO_BAR_ATTRIBUTES (SESSION_ID);
|
|
@ -367,6 +367,8 @@ content into your application; rather pick only the properties that you need.
|
|||
|
||||
# SPRING SESSION ({sc-spring-boot-autoconfigure}/session/SessionProperties.{sc-ext}[SessionProperties])
|
||||
spring.session.hazelcast.map-name=spring:session:sessions # Name of the map used to store sessions.
|
||||
spring.session.jdbc.initializer.enabled=true # Create the required session tables on startup if necessary.
|
||||
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
|
||||
spring.session.jdbc.table-name=SPRING_SESSION # Name of database table used to store sessions.
|
||||
spring.session.mongo.collection-name=sessions # Collection name used to store sessions.
|
||||
spring.session.redis.flush-mode= # Flush mode for the Redis sessions.
|
||||
|
|
Loading…
Reference in New Issue