本文主要是介绍Mybatis源码分析(二)---SqlSessionFactory获取,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
SqlSessionFactory和SqlSession的获取
- 一. SqlSessionFactory获取
- ①. SqlSessionFactoryBuilder类中的build()方法
- ②. 创建XML配置解析器---XMLConfigBuilder
- ③. XMLConfigBuilder类中的parse()方法
- ④. XMLConfigBuilder类中的parseConfiguration()方法
- ⑤. XMLConfigBuilder类中的mapperElement()方法
- ⑥. XMLMapperBuilder类中的parse()方法
- ⑦. XMLMapperBuilder类中的configurationElement()方法
- ⑧. XMLMapperBuilder类中的buildStatementFromContext()方法
- ⑨. XMLStatementBuilder类中的parseStatementNode()方法
- ⑩. MapperBuilderAssistant类中的addMappedStatement()方法
- 十一. 创建DefaultSqlSessionFactory对象
- 二. SqlSessionFactory构建流程图
- 三. XMLConfigBuilder构建流程图
- 四. XMLMapperBuilder构建流程图
- 五. Configuration构建流程图
- 六. XMLStatementBuilder构建流程图
Mybatis启动解析过程图
一. SqlSessionFactory获取
在测试类中找到SqlSessionFactory获取入口
①. SqlSessionFactoryBuilder类中的build()方法
public SqlSessionFactory build(InputStream inputStream) {return build(inputStream, null, null);}public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {// 1. 创建XML配置解析器XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);// 2.1. parser.parse(): 解析配置文件,创建配置类Configuration// 2.2. build(): 创建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) {}}}// 3. 创建DefaultSqlSessionFactory对象public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}
build()方法流程总结
- 创建XML配置解析器
- 解析配置文件
- 创建DefaultSqlSessionFactory对象
②. 创建XML配置解析器—XMLConfigBuilder
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);}public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {//1. 参数配置commonConstructor(validation, variables, entityResolver);//2. 将配置信息输入流封装为Document对象, 以便后面进行解析this.document = createDocument(new InputSource(inputStream));}
③. XMLConfigBuilder类中的parse()方法
public Configuration parse() {if (parsed) {throw new BuilderException("Each XMLConfigBuilder can only be used once.");}// mybatis配置文件解析的主流程:// 1. parser.evalNode("/configuration") --> 获取到根节点// 2. 根据根标签<configuration>开始解析parsed = true;// 解析配置文件中根标签下的所有子标签parseConfiguration(parser.evalNode("/configuration"));return configuration;}
④. XMLConfigBuilder类中的parseConfiguration()方法
private void parseConfiguration(XNode root) {try {// 1. 解析properties节点propertiesElement(root.evalNode("properties"));// 2. 解析settings节点Properties settings = settingsAsProperties(root.evalNode("settings"));// 3. VFS主要用来加载容器内的各种资源,比如jar或者class文件loadCustomVfs(settings);loadCustomLogImpl(settings);// 4. 解析类型别名typeAliasesElementtypeAliasesElement(root.evalNode("typeAliases"));// 5. 加载插件pluginElement// 比如: 分页插件PageHelper,再比如druid连接池提供的各种监控、拦截、预发检查功能,pluginElement(root.evalNode("plugins"));// 6. 加载对象工厂objectFactoryElementobjectFactoryElement(root.evalNode("objectFactory"));// 7. 创建对象包装器工厂objectWrapperFactoryElementobjectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));// 8. 加载反射工厂reflectorFactoryElementreflectorFactoryElement(root.evalNode("reflectorFactory"));// 到setting之后,调用settingsElement(Properties props)将各值赋值给configuration,settingsElement(settings);// 9. 加载环境配置environmentsElementenvironmentsElement(root.evalNode("environments"));// 10. 数据库厂商标识加载databaseIdProviderElement(了解即可)databaseIdProviderElement(root.evalNode("databaseIdProvider"));// 11. 加载类型处理器typeHandlerElementtypeHandlerElement(root.evalNode("typeHandlers"));// 12. 加载mapper文件 或 mapperElement ---> (重点)mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}
⑤. XMLConfigBuilder类中的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");//解析包信息, 注册该包下的Mappersconfiguration.addMappers(mapperPackage);} else {//获取resource,url,mapperClass属性的值String resource = child.getStringAttribute("resource");String url = child.getStringAttribute("url");String mapperClass = child.getStringAttribute("class");//resource属性解析if (resource != null && url == null && mapperClass == null) {ErrorContext.instance().resource(resource);try(InputStream inputStream = Resources.getResourceAsStream(resource)) {XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());mapperParser.parse();}} else if (resource == null && url != null && mapperClass == null) {//url属性解析ErrorContext.instance().resource(url);try(InputStream inputStream = Resources.getUrlAsStream(url)){XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());mapperParser.parse();}} else if (resource == null && url == null && mapperClass != null) {//mapperClass属性解析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.");}}}}}
⑥. XMLMapperBuilder类中的parse()方法
public void parse() {if (!configuration.isResourceLoaded(resource)) {// 解析mapper.xml中的<mapper></mapper>标签configurationElement(parser.evalNode("/mapper"));configuration.addLoadedResource(resource);// 根据接口创建MapperProxyFactory工厂bindMapperForNamespace();}parsePendingResultMaps();parsePendingCacheRefs();parsePendingStatements();}
⑦. XMLMapperBuilder类中的configurationElement()方法
private void configurationElement(XNode context) {try {String namespace = context.getStringAttribute("namespace");if (namespace == null || namespace.isEmpty()) {throw new BuilderException("Mapper's namespace cannot be empty");}//设置名称空间builderAssistant.setCurrentNamespace(namespace);//开始对mapper.xml中各个标签进行解析// 1. 解析缓存映射<cache-ref></cache-ref>cacheRefElement(context.evalNode("cache-ref"));// 2. 解析缓存<cache></cache>cacheElement(context.evalNode("cache"));// 3. 解析参数映射<parameterMap></parameterMap>parameterMapElement(context.evalNodes("/mapper/parameterMap"));// 4. 解析结果集映射<resultMap></resultMap>resultMapElements(context.evalNodes("/mapper/resultMap"));// 5. 解析<sql></sql>sqlElement(context.evalNodes("/mapper/sql"));// 6. 解析CRUD语句<select></select> |<insert></insert> |<update></update> |<delete></delete> (重点)buildStatementFromContext(context.evalNodes("select|insert|update|delete"));} catch (Exception e) {throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);}}
⑧. XMLMapperBuilder类中的buildStatementFromContext()方法
private void buildStatementFromContext(List<XNode> list) {if (configuration.getDatabaseId() != null) {buildStatementFromContext(list, configuration.getDatabaseId());}buildStatementFromContext(list, null);}private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {//遍历解析每条sql语句for (XNode context : list) {//用每个sql标签的上下文对象创建statementParser解析器final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);try {//解析SQL节点statementParser.parseStatementNode();} catch (IncompleteElementException e) {configuration.addIncompleteStatement(statementParser);}}}
⑨. XMLStatementBuilder类中的parseStatementNode()方法
创建statementParser解析器, 调用parseStatementNode()对标签进行解析
public void parseStatementNode() {/*** <!--配置查询所有-->* <select id="getUserList" resultType="com.xizi.pojo.User">* select * from user* </select>**/String id = context.getStringAttribute("id");String databaseId = context.getStringAttribute("databaseId");if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {return;}..........................................................................................// 将解析内容封装到MappedStatement中builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,resultSetTypeEnum, flushCache, useCache, resultOrdered,keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);}
parseStatementNode()方法解析步骤
- 对之前解析好的各种属性进行解析配置
- 将所有的sql配置进行封装
⑩. MapperBuilderAssistant类中的addMappedStatement()方法
public MappedStatement addMappedStatement(String id,SqlSource sqlSource,StatementType statementType,SqlCommandType sqlCommandType,Integer fetchSize,Integer timeout,String parameterMap,Class<?> parameterType,String resultMap,Class<?> resultType,ResultSetType resultSetType,boolean flushCache,boolean useCache,boolean resultOrdered,KeyGenerator keyGenerator,String keyProperty,String keyColumn,String databaseId,LanguageDriver lang,String resultSets) {if (unresolvedCacheRef) {throw new IncompleteElementException("Cache-ref not yet resolved");}//接口路径 + 方法名称id = applyCurrentNamespace(id, false);boolean isSelect = sqlCommandType == SqlCommandType.SELECT;MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType).resource(resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(valueOrDefault(flushCache, !isSelect)).useCache(valueOrDefault(useCache, isSelect)).cache(currentCache); //二级缓存配置ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);if (statementParameterMap != null) {statementBuilder.parameterMap(statementParameterMap);}MappedStatement statement = statementBuilder.build();// 将解析好的statement实例加入mappedStatements集合中configuration.addMappedStatement(statement);return statement;
十一. 创建DefaultSqlSessionFactory对象
// 3. 创建DefaultSqlSessionFactory对象public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}
二. SqlSessionFactory构建流程图
三. XMLConfigBuilder构建流程图
四. XMLMapperBuilder构建流程图
五. Configuration构建流程图
六. XMLStatementBuilder构建流程图
这篇关于Mybatis源码分析(二)---SqlSessionFactory获取的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!