learn and grow up

hikari中用到的SPI思想

字数统计: 545阅读时长: 2 min
2020/08/23 Share

写在前面

​ 之前文章也说到了SPI最常见的就是JDBC,刚好现在用的就是springboot中的hikari,来看看他是怎么运用SPI思想加载特定的数据库驱动的。

正文

第一次看hikari源码,可以有这么个思路来跟踪源码:

​ ①,找到我们最熟悉的配置中心里配置的DataSourceType,一步找到数据源,②然后找到数据源里的getConnection方法。③并且找到类里的driveClass属性,④找到它的set方法,打上断点,⑤启动项目,开始跟踪吧~,如下图

DataSourceType

debug

继续:

断点启动,跟踪调用栈可以看到springboot初始化配置hikari的地方

debug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Hikari
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
static class Hikari extends DataSourceConfiguration {

@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
//根据配置创建数据源,即HikariDataSource
HikariDataSource dataSource = createDataSource(properties,
HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}

}
//一步步走,最终走到我们需要的地方
//com.zaxxer.hikari.HikariConfig#setDriverClassName
//可以看到,这里并没有用spi组件,而是借用了spi的思想
public void setDriverClassName(String driverClassName) {
if (this.sealed) {
throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
} else {
Class<?> driverClass = null;
//获取当前的ClassLoader
ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader();

try {
if (threadContextClassLoader != null) {
try {
driverClass = threadContextClassLoader.loadClass(driverClassName);
LOGGER.debug("Driver class {} found in Thread context class loader {}", driverClassName, threadContextClassLoader);
} catch (ClassNotFoundException var6) {
LOGGER.debug("Driver class {} not found in Thread context class loader {}, trying classloader {}", new Object[]{driverClassName, threadContextClassLoader, this.getClass().getClassLoader()});
}
}

if (driverClass == null) {
driverClass = this.getClass().getClassLoader().loadClass(driverClassName);
LOGGER.debug("Driver class {} found in the HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
}
} catch (ClassNotFoundException var7) {
LOGGER.error("Failed to load driver class {} from HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
}

if (driverClass == null) {
throw new RuntimeException("Failed to load driver class " + driverClassName + " in either of HikariConfig class loader or Thread context classloader");
} else {
try {
driverClass.newInstance();
this.driverClassName = driverClassName;
} catch (Exception var5) {
throw new RuntimeException("Failed to instantiate class " + driverClassName, var5);
}
}
}
}

classLoader

最终可以看到hikariDatasource借用spi的思想,load的配合的driveClass,进而向jdbc的driveManager注册了driver,供后续使用,也就是在后面DataSource获取getConnection的时候,向DataSource提供需要的driver。

getConnection

CATALOG
  1. 1. 写在前面
  2. 2. 正文