MyBatis源码阅读——MyBatis初始化流程解析
前言
在之前的几篇文章中,我们在源码中看到到了很多类,比如mapperRegistry、mappedStatements等,虽然我们知道它们都是在MyBatis初始化的时候完成加载的,那么我们还是有必要去了解一下其加载过程。
还是跟之前一样,写一个demo,去边debug 边阅读源码。
public static void main(String[] args) throws IOException {
String resource = "mybatis/conf/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//从 XML 中构建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(1L);
System.out.println(blog);
blog = mapper.selectBlog(1L);
System.out.println(blog);
} finally {
session.close();
}
}
SqlSessionFactory的产生
我们直接debug进入org.apache.ibatis.session.SqlSessionFactoryBuilder
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//获取配置信息 mybatis-config.xml
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//解析配置并初始化建立SqlSessionFactory
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
进入parser.parse() -> parseConfiguration(parser.evalNode(“/configuration”)); 这里是分析配置并加载初始化类的入口。
private void parseConfiguration(XNode root) {
try {
//先加载properties。这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。
propertiesElement(root.evalNode("properties"));
//加载别名。类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余
typeAliasesElement(root.evalNode("typeAliases"));
//加载插件plugin
pluginElement(root.evalNode("plugins"));
//MyBatis 每次在创建结果对象的新实例时, 是使用 ObjectFactory (对象工厂)实例来完成的。如果有自定义,则读取配置中的自定义的类
objectFactoryElement(root.evalNode("objectFactory"));
//结果对象转换(驼峰法等)
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//ReflectorFactory
reflectionFactoryElement(root.evalNode("reflectionFactory"));
//一些settings
settingsElement(root.evalNode("settings"));
// read it after objectFactory and objectWrapperFactory issue #631
//数据库连接、事务管理器的配置
environmentsElement(root.evalNode("environments"));
//databaseIdProvider的配置,可以根据不用的id产生不同的sql语句
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//加载负责java数据类型和jdbc数据类型之间的映射和转换 javaType\jdbcType 这些
typeHandlerElement(root.evalNode("typeHandlers"));
//加载映射文件Mapper(划重点)
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
加载映射文件Mapper的过程解析->mapperElement()
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
这段代码的核心,Mapper的注册等操作都在此
XMLMapperBuilder mapperParser = new XMLMapperBuilder();
mapperParser.parse();
二级缓存相关
XMLMapperBuilder中关联了 MapperBuilderAssistant 对象,而MapperBuilderAssistant 中关联了Cache对象,Cache是二级缓存的核心,而它在映射文件Mapper初始化的时候附带,那说明它的生命周期是基于Mapper的。
还没有评论,来说两句吧...