[bs-98] Add support for Tomcat database pool

* If Tomcat jdbc is available and the driverClassName and url
are provided or can be guessed (e.g. for HSQL) it is used.
Properties spring.database.{driverClassName,url} are consulted.

* If Commons DBCP is available it is used (if Tomcat is not)

* Otherwise an EmbeddedDatabase is created if all the bits are
available

* A JdbcOperations and a NamedParameterJdbcOperations are
available by default if a DataSource is created

* The data source is initialized from spring.database.schema (csv
of resource patterns)

[Fixes #49393511]
This commit is contained in:
Dave Syer 2013-05-17 11:57:02 +01:00
parent 74fffeba73
commit 2dc296caa9
16 changed files with 762 additions and 347 deletions

View File

@ -0,0 +1,86 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.util.StringUtils;
/**
* Base class for configuration of a database pool.
*
* @author Dave Syer
*
*/
public class AbstractDataSourceConfiguration {
// TODO: add pool parameters
@Value("${spring.database.driverClassName:}")
private String driverClassName;
@Value("${spring.database.url:}")
private String url;
@Value("${spring.database.username:sa}")
private String username;
@Value("${spring.database.password:}")
private String password;
protected String getDriverClassName() {
if (StringUtils.hasText(this.driverClassName)) {
return this.driverClassName;
}
EmbeddedDatabaseType embeddedDatabaseType = EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseType();
this.driverClassName = EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseDriverClass(embeddedDatabaseType);
if (!StringUtils.hasText(this.driverClassName)) {
throw new BeanCreationException(
"Cannot determine embedded database driver class for database type "
+ embeddedDatabaseType
+ ". If you want an embedded database please put a supoprted one on the classpath.");
}
return this.driverClassName;
}
protected String getUrl() {
if (StringUtils.hasText(this.url)) {
return this.url;
}
EmbeddedDatabaseType embeddedDatabaseType = EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseType();
this.url = EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseUrl(embeddedDatabaseType);
if (!StringUtils.hasText(this.driverClassName)) {
throw new BeanCreationException(
"Cannot determine embedded database url for database type "
+ embeddedDatabaseType
+ ". If you want an embedded database please put a supported on on the classpath.");
}
return this.url;
}
protected String getUsername() {
return this.username;
}
protected String getPassword() {
return this.password;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration for a Commons DBCP database pool. The DBCP pool is popular but not
* recommended in high volume environments.
*
* @author Dave Syer
*
*/
@Configuration
public class BasicDataSourceConfiguration extends AbstractDataSourceConfiguration {
@Bean
public DataSource dataSource() {
BasicDataSource pool = new BasicDataSource();
pool.setDriverClassName(getDriverClassName());
pool.setUrl(getUrl());
pool.setUsername(getUsername());
pool.setPassword(getPassword());
return pool;
}
}

View File

@ -0,0 +1,266 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* @author Dave Syer
*
*/
@Configuration
@ConditionalOnClass(EmbeddedDatabaseType.class /* Spring JDBC */)
// @ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration {
private static Log logger = LogFactory.getLog(DataSourceAutoConfiguration.class);
@Autowired(required = false)
private DataSource dataSource;
@Autowired
private ApplicationContext applicationContext;
@Conditional(DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class)
@Import(EmbeddedDatabaseConfiguration.class)
protected static class EmbeddedConfiguration {
}
@Conditional(DataSourceAutoConfiguration.TomcatDatabaseCondition.class)
@Import(TomcatDataSourceConfiguration.class)
protected static class TomcatConfiguration {
}
@Conditional(DataSourceAutoConfiguration.BasicDatabaseCondition.class)
@Import(BasicDataSourceConfiguration.class)
protected static class DbcpConfiguration {
}
@Configuration
@Conditional(DataSourceAutoConfiguration.SomeDatabaseCondition.class)
// FIXME: make this @ConditionalOnBean(DataSorce.class)
protected static class JdbcTemplateConfiguration {
@Autowired(required = false)
private DataSource dataSource;
@Bean
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcOperations jdbcTemplate() {
return new JdbcTemplate(this.dataSource);
}
@Bean
@ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
public NamedParameterJdbcOperations namedParameterJdbcTemplate() {
return new NamedParameterJdbcTemplate(this.dataSource);
}
}
// FIXME: DB platform
@Value("${spring.database.schema:classpath*:schema.sql}")
private String schemaLocations = "";
@PostConstruct
protected void initialize() throws Exception {
if (this.dataSource == null) {
logger.debug("No DataSource found so not initializing");
return;
}
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
boolean exists = false;
List<Resource> resources = new ArrayList<Resource>();
for (String location : StringUtils
.commaDelimitedListToStringArray(this.schemaLocations)) {
resources
.addAll(Arrays.asList(this.applicationContext.getResources(location)));
}
for (Resource resource : resources) {
if (resource.exists()) {
exists = true;
populator.addScript(resource);
populator.setContinueOnError(true);
}
}
if (exists) {
DatabasePopulatorUtils.execute(populator, this.dataSource);
}
}
static class SomeDatabaseCondition implements Condition {
protected Log logger = LogFactory.getLog(getClass());
private Condition tomcatCondition = new TomcatDatabaseCondition();
private Condition dbcpCondition = new BasicDatabaseCondition();
private Condition embeddedCondition = new EmbeddedDatabaseCondition();
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (this.tomcatCondition.matches(context, metadata)
|| this.dbcpCondition.matches(context, metadata)
|| this.embeddedCondition.matches(context, metadata)) {
if (this.logger.isDebugEnabled()) {
this.logger
.debug("Existing auto database detected: match result true");
}
return true;
}
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
context.getBeanFactory(), DataSource.class, true, false).length > 0) {
if (this.logger.isDebugEnabled()) {
this.logger
.debug("Existing bean configured database detected: match result true");
}
return true;
}
return false;
}
}
static class TomcatDatabaseCondition extends NonEmbeddedDatabaseCondition {
@Override
protected String getDataSourecClassName() {
return "org.apache.tomcat.jdbc.pool.DataSource";
}
}
static class BasicDatabaseCondition extends NonEmbeddedDatabaseCondition {
private Condition condition = new TomcatDatabaseCondition();
@Override
protected String getDataSourecClassName() {
return "org.apache.commons.dbcp.BasicDataSource";
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (this.condition.matches(context, metadata)) {
return false; // prefer Tomcat pool
}
return super.matches(context, metadata);
}
}
static abstract class NonEmbeddedDatabaseCondition implements Condition {
protected Log logger = LogFactory.getLog(getClass());
protected abstract String getDataSourecClassName();
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (!ClassUtils.isPresent(getDataSourecClassName(), null)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Tomcat DataSource pool not found");
}
return false;
}
String driverClassName = context.getEnvironment().getProperty(
"spring.database.driverClassName");
String url = context.getEnvironment().getProperty("spring.database.url");
if (this.logger.isDebugEnabled()) {
this.logger.debug("Spring JDBC detected (embedded database type is "
+ EmbeddedDatabaseConfiguration.getEmbeddedDatabaseType() + ").");
}
if (driverClassName == null) {
driverClassName = EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseDriverClass(EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseType());
}
if (url == null) {
url = EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseUrl(EmbeddedDatabaseConfiguration
.getEmbeddedDatabaseType());
}
if (driverClassName != null && url != null
&& ClassUtils.isPresent(driverClassName, null)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Driver class " + driverClassName + " found");
}
return true;
}
return false;
}
}
static class EmbeddedDatabaseCondition implements Condition {
protected Log logger = LogFactory.getLog(getClass());
private Condition tomcatCondition = new TomcatDatabaseCondition();
private Condition dbcpCondition = new BasicDatabaseCondition();
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (this.tomcatCondition.matches(context, metadata)
|| this.dbcpCondition.matches(context, metadata)) {
if (this.logger.isDebugEnabled()) {
this.logger
.debug("Existing non-embedded database detected: match result false");
}
return false;
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Spring JDBC detected (embedded database type is "
+ EmbeddedDatabaseConfiguration.getEmbeddedDatabaseType() + ").");
}
return EmbeddedDatabaseConfiguration.getEmbeddedDatabaseType() != null;
}
}
}

View File

@ -1,119 +0,0 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.ClassUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for embedded databases.
*
* @author Phillip Webb
*/
@Configuration
@Conditional(EmbeddedDatabaseAutoConfiguration.EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean(DataSource.class)
public class EmbeddedDatabaseAutoConfiguration {
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_TYPE_CLASSES;
static {
EMBEDDED_DATABASE_TYPE_CLASSES = new LinkedHashMap<EmbeddedDatabaseType, String>();
EMBEDDED_DATABASE_TYPE_CLASSES.put(EmbeddedDatabaseType.HSQL,
"org.hsqldb.Database");
}
// FIXME: DB platform
@Value("${spring.jdbc.schema:classpath*:schema.sql}")
private Resource[] schemaLocations = new Resource[0];
@PostConstruct
protected void initialize() throws Exception {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
boolean exists = false;
for (Resource resource : this.schemaLocations) {
if (resource.exists()) {
exists = true;
populator.addScript(resource);
populator.setContinueOnError(true);
}
}
if (exists) {
DatabasePopulatorUtils.execute(populator, dataSource());
}
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(getEmbeddedDatabaseType());
return builder.build();
}
public static EmbeddedDatabaseType getEmbeddedDatabaseType() {
for (Map.Entry<EmbeddedDatabaseType, String> entry : EMBEDDED_DATABASE_TYPE_CLASSES
.entrySet()) {
if (ClassUtils.isPresent(entry.getValue(),
EmbeddedDatabaseAutoConfiguration.class.getClassLoader())) {
return entry.getKey();
}
}
return null;
}
static class EmbeddedDatabaseCondition implements Condition {
private static Log logger = LogFactory.getLog(EmbeddedDatabaseCondition.class);
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (!ClassUtils.isPresent(
"org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType",
context.getClassLoader())) {
if (logger.isDebugEnabled()) {
logger.debug("Spring JDBC not detected (EmbeddedDatabaseCondition evaluated false).");
}
return false;
}
if (logger.isDebugEnabled()) {
logger.debug("Spring JDBC detected (embedded database type is "
+ getEmbeddedDatabaseType() + ").");
}
return getEmbeddedDatabaseType() != null;
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.util.ClassUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for embedded databases.
*
* @author Phillip Webb
*/
@Configuration
public class EmbeddedDatabaseConfiguration {
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_TYPE_CLASSES;
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_DRIVER_CLASSES;
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_URLS;
static {
EMBEDDED_DATABASE_TYPE_CLASSES = new LinkedHashMap<EmbeddedDatabaseType, String>();
EMBEDDED_DATABASE_TYPE_CLASSES.put(EmbeddedDatabaseType.HSQL,
"org.hsqldb.Database");
EMBEDDED_DATABASE_DRIVER_CLASSES = new LinkedHashMap<EmbeddedDatabaseType, String>();
EMBEDDED_DATABASE_DRIVER_CLASSES.put(EmbeddedDatabaseType.HSQL,
"org.hsqldb.jdbcDriver");
EMBEDDED_DATABASE_URLS = new LinkedHashMap<EmbeddedDatabaseType, String>();
EMBEDDED_DATABASE_URLS.put(EmbeddedDatabaseType.HSQL, "jdbc:hsqldb:mem:testdb");
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(getEmbeddedDatabaseType());
return builder.build();
}
public static String getEmbeddedDatabaseDriverClass(
EmbeddedDatabaseType embeddedDatabaseType) {
return EMBEDDED_DATABASE_DRIVER_CLASSES.get(embeddedDatabaseType);
}
public static String getEmbeddedDatabaseUrl(EmbeddedDatabaseType embeddedDatabaseType) {
return EMBEDDED_DATABASE_URLS.get(embeddedDatabaseType);
}
public static EmbeddedDatabaseType getEmbeddedDatabaseType() {
for (Map.Entry<EmbeddedDatabaseType, String> entry : EMBEDDED_DATABASE_TYPE_CLASSES
.entrySet()) {
if (ClassUtils.isPresent(entry.getValue(),
EmbeddedDatabaseConfiguration.class.getClassLoader())) {
return entry.getKey();
}
}
return null;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration for a Tomcat database pool. The Tomcat pool provides superior performance
* and tends not to deadlock in high volume environments.
*
* @author Dave Syer
*
*/
@Configuration
public class TomcatDataSourceConfiguration extends AbstractDataSourceConfiguration {
@Bean
public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource pool = new org.apache.tomcat.jdbc.pool.DataSource();
pool.setDriverClassName(getDriverClassName());
pool.setUrl(getUrl());
pool.setUsername(getUsername());
pool.setPassword(getPassword());
return pool;
}
}

View File

@ -20,7 +20,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import org.hibernate.ejb.HibernateEntityManager;
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration;
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseConfiguration;
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
@ -61,7 +61,7 @@ public class HibernateJpaAutoConfiguration extends JpaAutoConfiguration {
if (isAutoConfiguredDataSource()) {
properties.put("hibernate.hbm2ddl.auto", "create-drop");
String dialect = EMBEDDED_DATABASE_DIALECTS
.get(EmbeddedDatabaseAutoConfiguration.getEmbeddedDatabaseType());
.get(EmbeddedDatabaseConfiguration.getEmbeddedDatabaseType());
if (dialect != null) {
properties.put("hibernate.dialect", dialect);
}

View File

@ -27,7 +27,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration;
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseConfiguration;
import org.springframework.bootstrap.context.annotation.AutoConfigurationUtils;
import org.springframework.bootstrap.context.annotation.ConditionalOnBean;
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
@ -69,14 +69,14 @@ public abstract class JpaAutoConfiguration implements BeanFactoryAware {
/**
* Determines if the {@code dataSource} being used by Spring was created from
* {@link EmbeddedDatabaseAutoConfiguration}.
* {@link EmbeddedDatabaseConfiguration}.
* @return true if the data source was auto-configured.
*/
protected boolean isAutoConfiguredDataSource() {
try {
BeanDefinition beanDefinition = this.beanFactory
.getBeanDefinition("dataSource");
return EmbeddedDatabaseAutoConfiguration.class.getName().equals(
return EmbeddedDatabaseConfiguration.class.getName().equals(
beanDefinition.getFactoryBeanName());
} catch (NoSuchBeanDefinitionException e) {
return false;

View File

@ -18,9 +18,11 @@ package org.springframework.bootstrap.autoconfigure.web;
import javax.servlet.Servlet;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration.WebMvcConfiguration;
import org.springframework.bootstrap.context.annotation.ConditionalOnBean;
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
@ -31,13 +33,17 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebMvc Web MVC}.
@ -61,6 +67,23 @@ public class WebMvcAutoConfiguration {
@Autowired
private ListableBeanFactory beanFactory;
@ConditionalOnBean(View.class)
@Bean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(0);
return resolver;
}
@ConditionalOnBean(View.class)
@Bean
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(beanFactory
.getBean(ContentNegotiationManager.class));
return resolver;
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();

View File

@ -1,221 +0,0 @@
/*
* Copyright 2012-2013 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.bootstrap.context.initializer;
import java.lang.management.ManagementFactory;
import java.util.HashMap;
import java.util.Map;
import org.springframework.bootstrap.logging.JavaLoggerConfigurer;
import org.springframework.bootstrap.logging.LogbackConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ClassUtils;
import org.springframework.util.Log4jConfigurer;
/**
* An {@link ApplicationContextInitializer} that configures a logging framework depending
* on what it finds on the classpath and in the {@link Environment}. If the environment
* contains a property <code>logging.config</code> then that will be used to initialize
* the logging system, otherwise a default location is used. The classpath is probed for
* log4j and logback and if those are present they will be reconfigured, otherwise vanilla
* <code>java.util.logging</code> will be used. </p>
*
* <p>
* The default config locations are <code>classpath:log4j.properties</code> or
* <code>classpath:log4j.xml</code> for log4j; <code>classpath:logback.xml</code> for
* logback; and <code>classpath:logging.properties</code> for
* <code>java.util.logging</code>. If the correct one of those files is not found then
* some sensible defaults are adopted from files of the same name but in the package
* containing {@link LoggingInitializer}.
* </p>
*
* <p>
* Some system properties may be set as side effects, and these can be useful if the
* logging configuration supports placeholders (i.e. log4j or logback):
* <ul>
* <li><code>LOG_FILE</code> is set to the value of <code>logging.file</code> if found in
* the environment</li>
* <li><code>LOG_PATH</code> is set to the value of <code>logging.path</code> if found in
* the environment</li>
* <li><code>PID</code> is set to the value of the current process ID if it can be
* determined</li>
* </ul>
*
* @author Dave Syer
* @author Phillip Webb
*/
public class LoggingInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private static final Map<String, String> ENVIRONMENT_SYSTEM_PROPERTY_MAPPING;
static {
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING = new HashMap<String, String>();
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING.put("logging.file", "LOG_FILE");
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING.put("logging.path", "LOG_PATH");
ENVIRONMENT_SYSTEM_PROPERTY_MAPPING.put("PID", "PID");
}
private int order = Integer.MIN_VALUE + 1;
/**
* Initialize the logging system according to preferences expressed through the
* {@link Environment} and the classpath.
*/
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (Map.Entry<String, String> mapping : ENVIRONMENT_SYSTEM_PROPERTY_MAPPING
.entrySet()) {
if (environment.containsProperty(mapping.getKey())) {
System.setProperty(mapping.getValue(),
environment.getProperty(mapping.getKey()));
}
}
if (System.getProperty("PID") == null) {
System.setProperty("PID", getPid());
}
LoggingSystem system = LoggingSystem.get(applicationContext.getClassLoader());
system.init(applicationContext);
}
private String getPid() {
String name = ManagementFactory.getRuntimeMXBean().getName();
if (name != null) {
return name.split("@")[0];
}
return "????";
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
private static enum LoggingSystem {
/**
* Log4J
*/
LOG4J("org.apache.log4j.PropertyConfigurator", "log4j.xml", "log4j.properties") {
@Override
protected void doInit(ApplicationContext applicationContext,
String configLocation) throws Exception {
Log4jConfigurer.initLogging(configLocation);
}
},
/**
* Logback
*/
LOGBACK("ch.qos.logback.core.Appender", "logback.xml") {
@Override
protected void doInit(ApplicationContext applicationContext,
String configLocation) throws Exception {
LogbackConfigurer.initLogging(configLocation);
}
},
/**
* Java Util Logging
*/
JAVA(null, "logging.properties") {
@Override
protected void doInit(ApplicationContext applicationContext,
String configLocation) throws Exception {
JavaLoggerConfigurer.initLogging(configLocation);
}
};
private final String className;
private final String[] paths;
private LoggingSystem(String className, String... paths) {
this.className = className;
this.paths = paths;
}
public void init(ApplicationContext applicationContext) {
String configLocation = getConfigLocation(applicationContext);
try {
doInit(applicationContext, configLocation);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException("Cannot initialize logging from "
+ configLocation, ex);
}
}
protected abstract void doInit(ApplicationContext applicationContext,
String configLocation) throws Exception;
private String getConfigLocation(ApplicationContext applicationContext) {
Environment environment = applicationContext.getEnvironment();
ClassLoader classLoader = applicationContext.getClassLoader();
// User specified config
if (environment.containsProperty("logging.config")) {
return environment.getProperty("logging.config");
}
// Common patterns
for (String path : this.paths) {
ClassPathResource resource = new ClassPathResource(path, classLoader);
if (resource.exists()) {
return "classpath:" + path;
}
}
// Fallback to the default
String defaultPath = ClassUtils.getPackageName(JavaLoggerConfigurer.class);
defaultPath = defaultPath.replace(".", "/");
defaultPath = defaultPath + "/" + this.paths[this.paths.length - 1];
return "classpath:" + defaultPath;
}
public static LoggingSystem get(ClassLoader classLoader) {
for (LoggingSystem loggingSystem : values()) {
String className = loggingSystem.className;
if (className == null || ClassUtils.isPresent(className, classLoader)) {
return loggingSystem;
}
}
return JAVA;
}
}
}

View File

@ -19,7 +19,7 @@ import javax.persistence.EntityManagerFactory;
import org.junit.Test;
import org.springframework.bootstrap.autoconfigure.data.test.CityRepository;
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration;
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseConfiguration;
import org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ -40,7 +40,7 @@ public class JpaRepositoriesAutoConfigurationTests {
public void testDefaultRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfiguration.class,
EmbeddedDatabaseAutoConfiguration.class,
EmbeddedDatabaseConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
HibernateJpaAutoConfiguration.class);
this.context.refresh();

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.assertNotNull;
/**
* @author Dave Syer
*
*/
public class BasicDataSourceAutoConfigurationTests {
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Test
public void testDataSourceExists() throws Exception {
this.context.register(BasicDataSourceConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.ClassUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* @author Dave Syer
*
*/
public class DataSourceAutoConfigurationTests {
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Test
public void testDefaultDataSourceExists() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
@Test
public void testJdbcTemplateExists() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
JdbcTemplate jdbcTemplate = this.context.getBean(JdbcTemplate.class);
assertNotNull(jdbcTemplate);
assertNotNull(jdbcTemplate.getDataSource());
}
@Test
public void testNamedParameterJdbcTemplateExists() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(NamedParameterJdbcOperations.class));
}
@Test
public void testDataSourceInitialized() throws Exception {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("spring.database.schema",
ClassUtils.addResourcePathToPackagePath(getClass(), "schema.sql"));
this.context.getEnvironment().getPropertySources()
.addFirst(new MapPropertySource("test", map));
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertTrue(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource);
assertNotNull(dataSource);
JdbcOperations template = new JdbcTemplate(dataSource);
assertEquals(new Integer(0),
template.queryForObject("SELECT COUNT(*) from FOO", Integer.class));
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.assertNotNull;
/**
* @author Dave Syer
*
*/
public class EmbeddedDatabaseAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@Test
public void testDefaultEmbeddedDatabase() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(EmbeddedDatabaseConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012-2013 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.bootstrap.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.assertNotNull;
/**
* @author Dave Syer
*
*/
public class TomcatDataSourceAutoConfigurationTests {
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Test
public void testDataSourceExists() throws Exception {
this.context.register(TomcatDataSourceConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
}
}

View File

@ -0,0 +1,4 @@
CREATE TABLE FOO (
id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(30),
);