mybatis源码流程图
2022-05-14 15:26:00   23  举报             
     
         
 mybatis源码解析
    作者其他创作
 大纲/内容
 节点id拼接namespace拿到一个新的idorg.example.mapper.UserMapper.selectById
  将子节点信息封装到ResultMapping中然后添加到List<ResultMapping>集合中
    判断textSqlNode.isDynamic()
  拿到select|insert...这些节点的属性值
  namespace:org.example.mapper.UserMapper
  是
  <include>节点进来(Node source就是<sql>)且当前节点Node source的节点类型是TEXT或CDATA_SECTION
  parseDynamicTags(XNode)解析动态节点拿到MixedSqlNode
  解析lang属性,如果自定义了sql脚本语言驱动,那么就拿自己定义的否则就拿默认的XMLLanguageDriver
  reflectorFactoryElement
  创建对应的SqlNode(MixedSqlNode)
  虽然不同的动态节点有不同的处理方式但其实套路是一样的。1. 都要先执行parseDynamicTags(XNode)递归解析得到MixedSqlNode。2. 创建对应的SqlNode。3. 添加到最开始的<select>节点的List<SqlNode>中。
  根据节点名称获取对应的NodeHandler
  子节点类型是CDATA_SECTION_NODE或者TEXT_NODE
  new SqlSessionFactoryBuilder().build(reader)
  resultMap解析子流程(构建ResultMap对象添加到Configuration中)
  这个也是在settings节点设置的属性value值:用别名设置了可以打印sql日志
  cacheElement解析<cache>(二级缓存)
  build创建一个DefaultSqlSessionFactory(Configuration)
  否
  parsed:mybatis.xml是否解析过的标记。parser:XPatheParser对象
  XmlMapperBuilder和Configuration共同指向同一个sqlFragments
  handleNode()子流程
  Node source当前节点类型是ELEMENT_NODE
  创建XPathPaser对象
  以这个新的id为key,<sql>节点(已经解析成XNode了)为value添加到sqlFragments这个Map中
  <select>select              <include />from </select>
  新建一个StaticTextSqlNode(sql文本)对象添加到List<SqlNode>
  递归,子节点传给source
  typeHandlerElement
  MapperRegistry.addMapper()子流程
  拼接keyStatementId
  namespace拼接上前缀添加到configuration的loadedResources中
  mybatis.xml会在创建该对象的时候解析为Document
  parseDynamicTags(XNode)子流程
  <mapper>节点使用url属性(不推荐)
  handler.handleNode()不同的子节点有不同的处理方式
  创建XMLStatementBuilder extends BaseBuilder对象
  拿到mapper.xml的namespace所对应的Class类型
  SqlSource
  mapper.xml中<mapper>是根节点
  替换Includes标签为对应的sql标签里面的值
  typealiases
  List<SqlNode> contents = new ArrayList<>();一开始会创建一个List用来存放SqlNode
  loadXmlResource
  new MixedSqlNode(List<SqlNode>)
  configurationElement
  创建静态SqlSourceRawSqlSource
  addMappedStatement创建MappedStatement并添加到Configuration
  settings
  resource资源是否加载过
  构建一个cache对象(这个Cache对象包装了很多层Cache)存入Configuration的caches属性以及MapperBuilderAssistant的currentCache对象。LruCache的LinkedHashMap数据结构要注意一下
  <mapper>节点使用class属性
  properties第一个解析
  logImpl
  解析select|insert|update|delete
  有时间再去补充吧核心应该就是找接口中有注解的方法,将注解的信息构建成MappedStatement对象
  sql脚本语言驱动是用来创建SqlSource的
  拿<mapper>节点的namespace属性设置到XmlMapperBuilder封装的MapperBuilderAssistant属性
  获取子节点的sql文本然后
  cacheRefElement解析<cache-ref>
  vfs(基本不用)
  遍历这些select|insert|update|delete节点
  子流程select|insert...节点的属性都会传进来
  子流程(构建MappedStatement对象并添加到Configuration中)
  pluginElement
  递归
  getStatementParameterMap
  设置XMLScriptBuilder的isDynamic属性为true
  objectWrapperFactoryElement
  sqlElement解析<sql>节点形成sql片段(sqlFragments)
  子流程
  静态
  parser.parse()XmlConfigBuilder的parsed属性会在该方法一开始就设置为true
  configuration.addMapper()
  创建一个MappedStatement的Builder对象
  resultMaps的key:当前mapper的namespace属性拼接<resultMap>节点的id属性(org.example.mapper.UserMapper.resultMapId)
  transactionManagerElementdataSourceElement最后构建一个Environment对象放入Configuration的environment属性中
  这个MixedSqlNode包了很多层。MixedSqlNode - select    StaticTextSqlNode - 文本    WhereSqlNode - where        MixedSqlNode - where            StaticTextSqlNode - 空文本            IfSqlNode - if                MixedSqlNode - if                StaticSqlNode - 文本            StaticSqlNode - 空文本    StaticTextSqlNode - 空文本
  解析注解子流程
  objectFactoryElement
  bindMapperForNamespace
  给XmlConfigBuilder属性赋值
  创建一个XMLScriptBuilder extends BaseBuilder对象
  是接口
  将包中的类解析到一个Setr<Class>集合中遍历
  parameterMapElement解析<parameterMap>该节点在3.5开始貌似不怎么推荐使用
  创建TextSqlNode对象
  mapper的namespace拼接该<sql>节点的id属性生成一个新的id
  mapper.xml之间的缓存引用,被引用的那个xml如果没设置cache则会报错
  mapper.xml没解析过的话就回去解析,前提是接口名和xml名相同且在同一个包下。UserMapper和UserMapper.xml在同一个包下。
  mybatis.xml的<mapper>节点使用resource属性
  parseStatementNode解析节点
  递归,传给source的是节点
  databaseIdProviderElement
  package优先级高resource、url、class三个属性只能有一个
  所以注册class和package的方式其实走的是注解的路子。但是走注解的路子也是会去先加载mappder.xml的,前提是接口名和xml名相同且在同一个包下,否则mapper.xml就没法解析到。UserMapper和UserMapper.xml在同一个包下。
  最后构建ResultMap对象并将它添加到Configuration的resultMaps属性中
  处理我们的parameterMap(该方式基本不用了)和parameterType
  <include>解析子流程
  ResultMapResolver.addResultMap()
  子节点类型是ELEMENT_NODE
  trimwheresetforeachifchoosewhenotherwisebind
  将settings节点的key-value设置进Configuration
  整个<select>是否是动态sql
  TextSqlNode对象添加到List<SqlNode>
  替换sql片段中的 ${<properties解析到的内容>}
  <include>父节点将<include>替换为<sql>节点的firstChildNode(第一个节点肯定是#Text)
  XMLScriptBuilder.parseScriptNode()真正去解析SqlNode了
  <select id=\"selectById\" resultMap=\"result\
  这几个基本不用对象工厂:用于反射实例化对象对象包装工厂反射工厂:用于属性和setter/getter的获取
  Configuration设置databaseId(environment和databaseIdProvider都存在的情况下)
  Node source当前节点是<include>
  加载资源构建XMLMapperBuilder对象mapperParser
  拿到一个主键生成器
  namespace所对应的类型是否是接口
  获取当前XNode的所有子节点遍历
  创建XMLIncludeTransformer对象解析<include>
  动态
  拿到<select>|<insert>...节点的name来判断SqlCommandType值
  将这个resource资源放到Configuration的loadedResources属性中,下次再加载这个资源的时候就不需要再去解析了
  SqlNode添加到<select>节点的List<SqlNode>
  构建MappedStatement对象-> 添加到Configuration的mappedStatements属性中
  <mapper>节点使用package属性
  遍历source的子节点
  解析mapper.xml子流程
  调XmlConfigBuilder的抽象父类BaseBuilder的构造函数进行属性赋值
  environmentsElement
  1. packages包下的类注册别名:别名为简单类型名。2. typealiastype:类型全名alias:别名,没设置的话会默认是简单类型名。3. if(packages){...} else{...}两种方式都有,packages优先级高
  解析parameterType拿到Class
  遍历所有resultMap节点
  子节点的各个属性都会封装进去,像property、column、javaType、jdbcType、typeHandler ...,如果是<id>子节点,还会设置一个ID标记进来说明是一个主键。
  settingsElement
  创建动态SqlSourceDynamicSqlSource
  如果在mybatis.xml中配置了databaseprovider这个节点且<property>设置了数据库厂商,那么在增删改查这几个节点需要设置databaseId的属性一致。如果没配置数据库厂商那么增删改查这几个节点也不要去设置databaseId属性
  resultMapElements解析<resultMap>
  XmlLanguageDriver.createSqlSource()创建SqlSource
  解析属性type拿到类全名
  sql文本中有没有${},有的话就是动态,没有就是静态
  遍历resultMap的子节点(id、result ...)
  configurationtypeAliasRegistrytypeHandlerRegistryBaseBuilder这个抽象类属性是protected 
  如果设置了extends属性,那么会从Configuration中拿它对应的ResultMap对象 -> 拿到父ResultMap中的List<ResultMappings> -> 合并到当前子resultMap的List<ResultMapping>中 (extendResutMappings.removeAll(resultMappings) -> resultMappings.addAll(extendResultMappings) )
  mybatis是这样实现的:1. 父节点的<include>替换为<sql>2. <sql>节点前插入<sql>的第一个子节点(#text)3. 删除<sql>节点4. 最终<include>实际就是转成了<sql>的文本信息(#text)
  获取子节点name
  主要是用来解析注解的构建一个MappedStatement对象添加到Configuration中
  构建ResultMapResolver对象
  会将<resultMap>节点的属性(id、type、extendsautoMapping)都封装进来
  parseScriptNode子流程
  这个也是在settings节点设置的属性访问一些虚拟文件系统的把(ftp之类的)
  解析StatementNode
  TextSqlNode textSqlNode = new TextSqlNode(data);将sql文本传进该对象
  mapperElement
  删除因异常没有完成解析的数据
  XMLConfigBuilderXMLMapperBuilderMapperBuilderAssistantXMLStatementBuilderXMLScriptBuilderSqlSourceBuilder
  1. <property>节点的key-value添加到Properties defaults。2. <properties>的属性resource或url进行资源加载成Properties,最后添加到defaults中。3. 加上Configuration的variables属性值。4. defaults设置到Configuration和XPathPaser的variables属性中。
  XMLMapperBuilder extentds BaseBuilder是用来解析mapper.xml文件的,构建该对象的时候会new XPathParser将mapper.xml解析到document。XmlMapperBuilder构建的时候会把Configuration的sqlFragments属性传进来,也就是XmlMapperBuilder和Configuration共同引用同一个sqlFragments。
  解析我们<insert 语句的的selectKey节点
  创建MapperAnnotationBuilder对象
  拿到所有的<sql>节点遍历
  org.example.mapper.UserMapper.selectById!selectKey
  创建XMLConfigBuilder extends BaseBuilder parser用来解析全局配置文件
  创建SqlSource子流程
  去Configuration的sqlFragement属性中根据refid找到<sql>节点数据
  就是mapper.xml有没有解析过
  buildStatementFromContext
  解析xml的信息都放在了Configuration对象中了
  mapperParser.parse()解析mapper.xml
  setting节点的name属性看XmlConfigBuilder的settingElements方法(这里有大部分的属性),只要是Configuration中的set方法其实都行
   
 
 
 
 
  0 条评论
 下一页
  
   
   
   
   
  
  
  
  
  
  
  
  
 