本系列的文章都是基于这个demo来分析的
Mybatis入门,一个简单的demo
在源码分析过程中,会使用到一些额外的知识点,比如
Mybatis中使用的spring接口
Mybatis中使用的设计模式
Mybatis初始化配置文件分为两个阶段,如下
- mybatis-config.xml解析
- mapper.xml文件解析
本篇分析的是第一阶段。
首先,看一下初始化入口
<!-- 配置Mybatis的文件 ,mapperLocations配置**Mapper.xml文件位置,configLocation配置mybatis-config文件位置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml" />
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
</bean>
接着,看一下SqlSessionFactoryBean
的afterPropertiesSet
方法,该方法最终生成一个SqlSessionFactory
对象,供后面执行sql时使用。
@Override
public void afterPropertiesSet() throws Exception {
this.sqlSessionFactory = buildSqlSessionFactory();
}
然后,再看看buildSqlSessionFactory
方法,方法中有一个Configuration configuration
对象,方法里做的所有事情都是为了初始化这个对象,然后通过SqlSessionFactoryBuilder.build(configuration);
返回一个SqlSessionFactory
的实例对象DefaultSqlSessionFactory
。
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
Configuration configuration;
//省略中间的解析代码
return this.sqlSessionFactoryBuilder.build(configuration);
}
接下来,看看是怎么一步一步解析配置文件初始化Configuration configuration
的吧。
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configuration != null) {
//省略
} else if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
} else {
//省略
}
这里走的是第二个if
分支,初始化一个XMLConfigBuilder
解析器,并同时初始化一个Configuration
。new XMLConfigBuilder()
如下
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
这里使用XPathParser
作为解析器,同时new Configuration()
,构造方法里主要是注册一些别名,如下
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);