写在前面
这个demo来说明怎么一步步排查一个常见的spring boot AutoConfiguration的错误。
https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-database-type-NONE
调试排查 Cannot determine embedded database driver class for database type NONE 的错误
把工程导入IDE里,直接启动应用,抛出来的异常信息是:
1 |
|
其实这时有两个思路,直接google搜索Cannot determine embedded database driver class for database type NONE
,就可以找到解决办法。
第二种方式,仔细查看日志内容,可以发现有To display the auto-configuration report re-run your application with 'debug' enabled.
。
搜索下这个,就可以在spring的官方网站上找到相关的信息:https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html
就是用户只要配置了debug
这个开关,就会把auto-configuration
相关的信息打印出来。
熟悉spring的环境变量注入的话,就可以知道有几种打开这个的方式:
- 在
args
里增加--debug
- 在application.properties里增加
debug=true
- 通过
-Ddebug=true
增加debug
开关之后的信息
增加debug
开关之后,可以看到打印出了错误堆栈:
1 | 2017-11-29 14:33:08.776 DEBUG 29907 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : Application failed to start due to an exception |
抛出异常的代码是:
1 | /** |
可以看出来是没有找到 DataSource 的driver class,然后抛出了 DataSourceBeanCreationException
。
那么一种解决办法是,在maven依赖里加入一些 DataSource driver class。
但是应用自己的代码里并没有使用DataSource,哪里导致spring boot要创建一个DataSource对象?
哪里导致spring boot要创建DataSource
从异常栈上,可以找到DataSourceConfiguration$Tomcat
这个类,那么查找下它的引用,可以发现它是被org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.PooledDataSourceConfiguration
import引入的。
1 |
|
那么 PooledDataSourceConfiguration
是怎么生效的呢?从代码上可以看到@Conditional(PooledDataSourceCondition.class)
。
那么再看PooledDataSourceCondition
的具体实现:
1 | /** |
PooledDataSourceCondition
引入了@Conditional(PooledDataSourceAvailableCondition.class)
:
1 | /** |
从代码里,可以看到是尝试查找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
1
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
在application.properties里配置:
1
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
具体的判断代码。