目录
简介
本篇文章将向大家介绍 MyBatis 内置数据源的实现逻辑。搞懂这些数据源的实现,可使大家对数据源有更深入的认识。同时在配置这些数据源时,也会更清楚每种属性的意义和用途。因此,如果大家想知其然,也知其所以然。那么接下来就让我们一起去探索 MyBatis 内置数据源的源码吧。
MyBatis 支持三种数据源配置,分别为 UNPOOLED、POOLED 和 JNDI。并提供了两种数据源实现,分别是 UnpooledDataSource 和 PooledDataSource。在三种数据源配置中,UNPOOLED 和 POOLED 是我们最常用的两种配置。至于 JNDI,MyBatis 提供这种数据源的目的是为了让其能够运行在 EJB 或应用服务器等容器中,这一点官方文档中有所说明。由于 JNDI 数据源在日常开发中使用甚少,因此,本篇文章不打算分析 JNDI 数据源相关实现。大家若有兴趣,可自行分析。接下来,本文将重点分析 UNPOOLED 和 POOLED 两种数据源。其他的就不多说了,进入正题吧。
内置数据源初始化过程
在详细分析 UnpooledDataSource 和 PooledDataSource 两种数据源实现之前,我们先来了解一下数据源的配置与初始化过程。现在看数据源是如何配置的,如下:
<dataSource type="UNPOOLED|POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql..."/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
数据源的配置是内嵌在 <environment> 节点中的,MyBatis 在解析 <environment> 节点时,会一并解析数据源的配置。MyBatis 会根据具体的配置信息,为不同的数据源创建相应工厂类,通过工厂类即可创建数据源实例。关于数据源配置的解析以及数据源工厂类的创建过程,我在 MyBatis 配置文件解析过程一文中分析过,这里就不赘述了。下面我们来看一下数据源工厂类的实现逻辑。
public class UnpooledDataSourceFactory implements DataSourceFactory {
private static final String DRIVER_PROPERTY_PREFIX = "driver.";
private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();
protected DataSource dataSource;
public UnpooledDataSourceFactory() {
// 创建 UnpooledDataSource 对象
this.dataSource = new UnpooledDataSource();
}
@Override
public void setProperties(Properties properties) {
Properties driverProperties = new Properties();
// 为 dataSource 创建元信息对象
MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
// 遍历 properties 键列表,properties 由配置文件解析器传入
for (Object key : properties.keySet()) {
String propertyName = (String) key;
// 检测 propertyName 是否以 "driver." 开头
if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
String value = properties.getProperty(propertyName);
// 存储配置信息到 driverProperties 中
driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
} else if (metaDataSource.hasSetter(propertyName)) {
String value = (String) properties.get(propertyName);
// 按需转换 value 类型
Object convertedValue = convertValue(metaDataSource, propertyName, value);
// 设置转换后的值到 UnpooledDataSourceFactory 指定属性中
metaDataSource.setValue(propertyName, convertedValue);
} else {
throw new DataSourceException("Unknown DataSource property: " + propertyName);
}
}
if (driverProperties.size() > 0) {
// 设置 driverProperties 到 UnpooledDataSourceFactory 的 driverProperties 属性中
metaDataSource.setValue("driverProperties", driverProperties);
}
}
private Object convertValue(MetaObject metaDataSource, String propertyName, String value) {
Object convertedValue = value;
// 获取属性对应的 setter 方法的参数类型
Class<?> targetType = metaDataSource.getSetterType(propertyName);
// 按照 setter 方法的参数类型进行类型转换
if (targetType == Integer.class || targetType == int.class) {
convertedValue = Integer.valueOf(value);
} else if (targetType == Long.class || targetType == long.class) {
convertedValue = Long.valueOf(value);
} else if (targetType == Boolean.class || targetType == boolean.class) {
convertedValue = Boolean.valueOf(value);
}
return convertedValue;
}
@Override
public DataSource getDataSource() {
return dataSource;
}
}
以上是 UnpooledDataSourceFactory 的源码分析,除了 setProperties 方法稍复杂一点,其他的都比较简单,就不多说了。下面看看 PooledDataSourceFactory 的源码。
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {
public PooledDataSourceFactory() {
// 创建 PooledDataSource
t