问题描述
项目中使用了自定义的Spring Listener配置,从网络获取配置KV,在SpringBoot启动过程中加载,然后再加载Druid环境。程序启动时-间歇性报错(三次启动可能有一次报错,其他两次可以正常启动):
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified and no embedded datasource could be auto-configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (the profiles de are currently active).
分析
根据日志显示,DruidDataSourceWrapper(implements InitializingBean )
类加载时,配置信息还没有就位。
Druid
没有读取到数据库配置,所以引发了上面的报错。
仔细看代码时发现,项目中有两个类继承了:SpringBootServletInitializer
,其中一个类并没有加载自定义的那个ApplicationListener
。既然有两个SpringBootServletInitializer
,这两个应该都加载ApplicationListener
,获取只保留一个。
- 需要确保Druid在读取配置时,自定义的Listener已经把配置信息加载好了。
解决
由于项目启动时,用的是外部Tomcat启动的方式。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
所以,在继承自SpringBootServletInitializer
的ServletInitializer
的configure
方法中,需要使用application.listeners()
,加载自定义的ApplicationListener
。
部分源码:
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// 自定义的ApplicationListener
application.listeners(buildListener("ServletInitializer"));
return application.sources(RabiesVaccineApplication.class);
}
ApplicationListener
在 InitializingBean
前被加载,保证Druid
可以读取到配置信息,问题解决。
环境
- spring-boot-starter-parent:2.0.4.RELEASE
- druid-spring-boot-starter:1.1.10
- druid:1.1.10
- jdk:1.8