本篇文章将向大家介绍 MyBatis 内置数据源的实现逻辑。搞懂这些数据源的实现,可使大家对数据源有更深入的认识。同时在配置这些数据源时,也会更清楚每种属性的意义和用途。因此,如果大家想知其然,也知其所以然。那么接下来就让我们一起去探索 MyBatis 内置数据源的源码吧。
MyBatis 支持三种数据源配置,分别为 UNPOOLED、POOLED 和 JNDI。并提供了两种数据源实现,分别是 UnpooledDataSource 和 PooledDataSource。在三种数据源配置中,UNPOOLED 和 POOLED 是我们最常用的两种配置。至于 JNDI,MyBatis 提供这种数据源的目的是为了让其能够运行在 EJB 或应用服务器等容器中,这一点官方文档中有所说明。由于 JNDI 数据源在日常开发中使用甚少,因此,本篇文章不打算分析 JNDI 数据源相关实现。大家若有兴趣,可自行分析。接下来,本文将重点分析 UNPOOLED 和 POOLED 两种数据源。其他的就不多说了,进入正题吧。
2.内置数据源初始化过程在详细分析 UnpooledDataSource 和 PooledDataSource 两种数据源实现之前,我们先来了解一下数据源的配置与初始化过程。现在看数据源是如何配置的,如下:
<dataSource type="UNPOOLED|POOLED"> <property value="com.mysql.cj.jdbc.Driver"/> <property value="jdbc:mysql..."/> <property value="root"/> <property 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 this.dataSource = new PooledDataSource(); } }以上就是 PooledDataSource 类的所有源码,PooledDataSourceFactory 继承自 UnpooledDataSourceFactory,复用了父类的逻辑,因此它的实现很简单。
关于两种数据源的创建过程就先分析到这,接下来,我们去探究一下两种数据源是怎样实现的。
3.UnpooledDataSource