1 解析配置
MyBatis通常配置如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
environment节点,会在XMLConfigBuilder中的parseConfiguration方法中执行:
environmentsElement(root.evalNode("environments"));
////
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
// 解析datasource节点,创建DataSourceFactory对象。
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
//从DataSourceFactory中获取DataSource
DataSource dataSource = dsFactory.getDataSource();
// DataSource放入 Configuration.environment.dataSource
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
2 创建DataSource
创建DataSourceFactory,在XMLConfigBuilder.dataSourceElement中:
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
// 根据上面的xml配置文件, type = "UNPOOLED"
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
// resolveClass方法,在TypeAliasRegistry中寻找别名对应的类。
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
// 用dataSource标签下的一系列property,设置DataSourceFactory的属性
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
根据org.apache.ibatis.session.Configuration类构造函数中的:
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
可知:
配置文件中为'UNPOOLED'时,dataSourceElement返回的是UnpooledDataSourceFactory这个类的对象。
TypeAliasRegitry默认值详情可查看MyBatis-初始化过程。
UnpooledDataSourceFactory创建的时候,直接创建了DataSource对象:
protected DataSource dataSource;
public UnpooledDataSourceFactory() {
this.dataSource = new UnpooledDataSource();
}
这里的UnpooledDataSource就是javax.sql.DataSource的实现类。
前面dataSourceElement方法中调用了setProperties,设置DataSource的属性,如driver/url/username/password等。
注:这里只是创建了DataSource对象,设置了属性,并没有做驱动注册等操作。
3 获取Connection
一般通过DataSource.getConnection获取Connection;
UnpooledDataSource中,getConnection最终调用doGetConnection获取Connection,并在这个过程中注册驱动:
private Connection doGetConnection(Properties properties) throws SQLException {
// 初始化驱动
initializeDriver();
// 获取Connection
Connection connection = DriverManager.getConnection(url, properties);
// 配置Connection:是否自动提交,事务隔离等级。
configureConnection(connection);
return connection;
}
private synchronized void initializeDriver() throws SQLException {
if (!registeredDrivers.containsKey(driver)) {
Class<?> driverType;
try {
// forName 加载类文件
if (driverClassLoader != null) {
driverType = Class.forName(driver, true, driverClassLoader);
} else {
driverType = Resources.classForName(driver);
}
// 创建驱动的实例
// DriverManager requires the driver to be loaded via the system ClassLoader.
// http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
Driver driverInstance = (Driver)driverType.newInstance();
// 使用代理的方式,注册驱动。
DriverManager.registerDriver(new DriverProxy(driverInstance));
registeredDrivers.put(driver, driverInstance);
} catch (Exception e) {
throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
}
}
}
4 总结
通过上面的分析,总结可知:
1)创建DataSource可以使用两种方式:
- 1 XML配置创建:type='UNPOOLED|POOLED',分别对应工
UnpooledDataSource和PooledDataSource; - 2 调用
Configuration.setEnvironment。
2)代码中获取DataSource:Configuration.getEnvironment().getDataSource()。