springboot启动报错java.lang.ClassNotFoundException: com.zaxxer.hikari.metrics.MetricsTrackerFactory
)
springboot启动报错java.lang.ClassNotFoundException: com.zaxxer.hikari.metrics.MetricsTrackerFactory
Caused by: java.lang.ClassNotFoundException: com.zaxxer.hikari.metrics.MetricsTrackerFactory
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
… 27 common frames omitted
项目本地运行没问题,打包到服务器上报了这个错,啥原因?
以下是问题解决后个人认为比较正确的问题定位思路。
springboot项目版本号为2.2.2。
解决过程
我们知道Hikari是一款连接池,在springboot2.0之后采用的默认的数据库连接池就是Hikari。但是我目前的项目用的数据库连接池是druid,莫非是初始化还是加载了hikari?
查了资料发现hikari是在spring-boot-starter-jdbc和spring-boot-starter-data-jpa包下默认解析HikariCP依赖,项目里并没有引用到hakari。于是我查看了一下目前的maven引用情况:
于是我把该引用去除:
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc</artifactId>
<version>3.0.0.M3</version>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP-java6</artifactId>
</exclusion>
</exclusions>
</dependency>
重新部署该项目,发现项目成功启动了。
但是这个时候有个疑问,为什么把hikari依赖去除了,反而“加载成功了呢”?
到这里,应该去了解一下springboot,它是如何默认初始化Hikari连接池的。
在这之前,我们需要了解一个知识,即springboot的配置项依赖是如何实现的:
大家应该都知道,我们的springboot启动类上要添加一个注解@SpringBootApplication
,
下面展示一些该注解的内部。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication
里面关键的是
@SpringBootConfiguration
@EnableAutoConfiguration
@SpringBootConfiguration
这个注解,只是@Configuration注解的派生注解,跟@Configuration注解的功能一致,标注这个类是一个配置类,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。这个不是本文重点,先不展开。
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
这里导入了AutoConfigurationImportSelector类:
接下来看该类的selectImports方法:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
先看下去,loadMetadata方法:
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
private AutoConfigurationMetadataLoader() {
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
}
可以看到,它通过PATH加载了需要自动装配的元数据:
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration=
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.