调试排查 Cannot determine embedded database driver class for database type NONE 的错误
把工程导入IDE里,直接启动应用,抛出来的异常信息是:html
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled. 2017-11-29 14:26:34.478 ERROR 29736 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Cannot determine embedded database driver class for database type NONE Action: If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
其实这时有两个思路,直接google搜索Cannot determine embedded database driver class for database type NONE,就能够找到解决办法。java
第二种方式,仔细查看日志内容,能够发现有To display the auto-configuration report re-run your application with 'debug' enabled.。spring
搜索下这个,就能够在spring的官方网站上找到相关的信息:https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.htmlapache
就是用户只要配置了debug这个开关,就会把auto-configuration 相关的信息打印出来。tomcat
熟悉spring的环境变量注入的话,就能够知道有几种打开这个的方式:bash
在args里增长--debug
在application.properties里增长debug=true
经过-Ddebug=true
增长debug开关以后的信息
增长debug开关以后,能够看到打印出了错误堆栈:app
2017-11-29 14:33:08.776 DEBUG 29907 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : Application failed to start due to an exception org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active). at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.determineDriverClassName(DataSourceProperties.java:245) ~[spring-boot-autoconfigure-1.4.7.RELEASE.jar:1.4.7.RELEASE] at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.initializeDataSourceBuilder(DataSourceProperties.java:182) ~[spring-boot-autoconfigure-1.4.7.RELEASE.jar:1.4.7.RELEASE] at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.createDataSource(DataSourceConfiguration.java:42) ~[spring-boot-autoconfigure-1.4.7.RELEASE.jar:1.4.7.RELEASE] at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat.dataSource(DataSourceConfiguration.java:53) ~[spring-boot-autoconfigure-1.4.7.RELEASE.jar:1.4.7.RELEASE] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
抛出异常的代码是: maven
/** * Determine the driver to use based on this configuration and the environment. * @return the driver to use * @since 1.4.0 */ public String determineDriverClassName() { if (StringUtils.hasText(this.driverClassName)) { Assert.state(driverClassIsLoadable(), "Cannot load driver class: " + this.driverClassName); return this.driverClassName; } String driverClassName = null; if (StringUtils.hasText(this.url)) { driverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName(); } if (!StringUtils.hasText(driverClassName)) { driverClassName = this.embeddedDatabaseConnection.getDriverClassName(); } if (!StringUtils.hasText(driverClassName)) { throw new DataSourceBeanCreationException(this.embeddedDatabaseConnection, this.environment, "driver class"); } return driverClassName; }
能够看出来是没有找到 DataSource 的driver class,而后抛出了 DataSourceBeanCreationException。ide
那么一种解决办法是,在maven依赖里加入一些 DataSource driver class。函数
可是应用本身的代码里并无使用DataSource,哪里致使spring boot要建立一个DataSource对象?哪里致使spring boot要建立DataSource
从异常栈上,能够找到DataSourceConfiguration$Tomcat 这个类,那么查找下它的引用,能够发现它是被
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.PooledDataSourceConfiguration import引入的。 @Configuration @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class }) protected static class PooledDataSourceConfiguration { }
那么 PooledDataSourceConfiguration 是怎么生效的呢?从代码上能够看到@Conditional(PooledDataSourceCondition.class)。
那么再看PooledDataSourceCondition的具体实现:
/** * {@link AnyNestedCondition} that checks that either {@code spring.datasource.type} * is set or {@link PooledDataSourceAvailableCondition} applies. */ static class PooledDataSourceCondition extends AnyNestedCondition { PooledDataSourceCondition() { super(ConfigurationPhase.PARSE_CONFIGURATION); } @ConditionalOnProperty(prefix = "spring.datasource", name = "type") static class ExplicitType { } @Conditional(PooledDataSourceAvailableCondition.class) static class PooledDataSourceAvailable { } }
PooledDataSourceCondition引入了@Conditional(PooledDataSourceAvailableCondition.class) : /** * {@link Condition} to test if a supported connection pool is available. */ static class PooledDataSourceAvailableCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage .forCondition("PooledDataSource"); if (getDataSourceClassLoader(context) != null) { return ConditionOutcome .match(message.foundExactly("supported DataSource")); } return ConditionOutcome .noMatch(message.didNotFind("supported DataSource").atAll()); } /** * Returns the class loader for the {@link DataSource} class. Used to ensure that * the driver class can actually be loaded by the data source. * @param context the condition context * @return the class loader */ private ClassLoader getDataSourceClassLoader(ConditionContext context) { Class<?> dataSourceClass = new DataSourceBuilder(context.getClassLoader()) .findType(); return (dataSourceClass == null ? null : dataSourceClass.getClassLoader()); } }
从代码里,能够看到是尝试查找dataSourceClass,若是找到,条件就成立。那么debug下,能够发现查找到的dataSourceClass是:org.apache.tomcat.jdbc.pool.DataSource 。
那么再看下org.apache.tomcat.jdbc.pool.DataSource这个类是从哪里来的呢?
从maven依赖树能够看到,依赖是来自:spring-boot-starter-jdbc。因此是应用依赖了spring-boot-starter-jdbc,可是并无配置DataSource引发的问题。
问题解决办法
有两种:
没有使用到DataSource,则能够把spring-boot-starter-jdbc的依赖去掉,这样就不会触发spring boot相关的代码
把spring boot自动初始化DataSource相关的代码禁止掉
禁止的办法有两种:
在main函数上配置exclude
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
在application.properties里配置:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
总结
应用没有使用到DataSource,可是在pom.xml里引入了spring-boot-starter-jdbc
spring-boot-starter-jdbc带入了tomcat-jdbc,它里面有org.apache.tomcat.jdbc.pool.DataSource
spring boot里的PooledDataSourceConfiguration,判断classpath下面有DataSource的实现类,尝试去建立DataSource bean
在初始化DataSourceProperties时,尝试经过jdbc的url来探测driver class
由于应用并无配置url,因此最终在DataSourceProperties.determineDriverClassName()里抛出Cannot determine embedded database driver class for database type NONE
最后:
排查spring boot的AutoConfiguration问题时,能够按异常栈,一层层排查Configuration是怎么引入的,再排查Condition具体的判断代码。