mytatis解析xml的过程01
来源:互联网 发布:淘宝客api接口 教程 编辑:程序博客网 时间:2024/06/05 00:39
###描述一下mybatis是怎么解析xml的?
1、Xml配置构建器,和它的parse方法
SqlSessionFactoryBuilder类中有build的具体代码。 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse());我们可以看到XMLConfigBuilder 对象。XMLConfigBuilder 这个对象获取了build方法传入的流,构造了一个XML配置文件解析器。并且在下一行调用了解析器的parse方法。让我们来猜一猜,这个解析器会做什么事情呢?它肯定是1)将xml封装成了dom对象,然后获取了xmlDOM中的各个属性,将其封装到了Configuration 中,别问我为什么,因为build的参数是Configuration。
2、parse方法里做了什么?
那么现在让我们来证实一下。
private void parseConfiguration(XNode root) { try { propertiesElement(root.evalNode("properties")); //issue #117 read properties first typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); settingsElement(root.evalNode("settings")); environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631 databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers"));
我们在XMLConfigBuilder们类中发现上面的代码被调用了。查看h核心配置文件的dtd约束文件可以发现,evalNode方法中的参数字符串,都是核心配置文件中可以被定义的元素。你可以去印证一下。
3、Mappers-mapperElement方法
我们发现了mappers这个字眼。它和我们配置在核心配置中的,指示mapper.xml文件位置的标签名是一样的。那mapperElement方法里面到底是什么呢?
一下是点进方法mapperElement方法里获取到的代码。
一下是点进方法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."); } } }可以发现,for循环遍历了mappers的子节点。当然,mappers的子节点可能是下面这样的
<mapper resource="com/iktz/mybatis/beans/UserMapper.xml" />当然也可能更丰满
String resource = child.getStringAttribute("resource");String url = child.getStringAttribute("url");String mapperClass = child.getStringAttribute("class");这3行代码,说明了mapper标签可以有这3个属性。
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."); }而上面的代码则说明,这3个属性,同时只能存在一个。
我们来看看他们的区别吧!
4、XMLMapperBuilder 类和它的parse方法
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(); }他们最让我好奇的是parse方法。我非常想知道他们里面是什么。
public void parse() { if (!configuration.isResourceLoaded(resource)) { configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); bindMapperForNamespace(); } parsePendingResultMaps(); parsePendingChacheRefs(); parsePendingStatements(); }Pend、、这个单词的意思是预备的意思。ChacheRef这个是什么鬼?
5、解析mapper.xml的关键部分
你肯定知道,我要看最后的3行代码。但是其实不是,真正关键的代码是这一行
configurationElement(parser.evalNode("/mapper"));
configurationElement方法中的代码才是对mapper文件的解析。
configurationElement(parser.evalNode("/mapper"));
configurationElement方法中的代码才是对mapper文件的解析。
private void configurationElement(XNode context) {try { String namespace = context.getStringAttribute("namespace"); if (namespace.equals("")) { throw new BuilderException("Mapper's namespace cannot be empty"); } builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode("cache-ref")); cacheElement(context.evalNode("cache")); parameterMapElement(context.evalNodes("/mapper/parameterMap")); resultMapElements(context.evalNodes("/mapper/resultMap")); sqlElement(context.evalNodes("/mapper/sql")); buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
我突然有一种感觉,这里的每一句话都很关键。
那就让我们一句一句来读吧
cacheRefElement(context.evalNode("cache-ref"));
这句应该是关于缓存的,你看方法名上都带有cache字眼。整个方法名仿佛在说,这个方法里要做的事情是缓存指向的元素。
算了,这里先不看了,给下次留点期待。而不能留给下次的,是这3个问题:parameterMapElement,resultMapElements,buildStatementFromContext。
6、解析Parameter,获取ParameterMapping
解析Parameter是由上面提到的parameterMapElement方法完成的。
以下是这个方法的代码。
以下是这个方法的代码。
private void parameterMapElement(List<XNode> list) throws Exception { for (XNode parameterMapNode : list) { String id = parameterMapNode.getStringAttribute("id"); String type = parameterMapNode.getStringAttribute("type"); Class<?> parameterClass = resolveClass(type); List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter"); List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>(); for (XNode parameterNode : parameterNodes) { String property = parameterNode.getStringAttribute("property"); String javaType = parameterNode.getStringAttribute("javaType"); String jdbcType = parameterNode.getStringAttribute("jdbcType"); String resultMap = parameterNode.getStringAttribute("resultMap"); String mode = parameterNode.getStringAttribute("mode"); String typeHandler = parameterNode.getStringAttribute("typeHandler"); Integer numericScale = parameterNode.getIntAttribute("numericScale"); ParameterMode modeEnum = resolveParameterMode(mode); Class<?> javaTypeClass = resolveClass(javaType); JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); @SuppressWarnings("unchecked") Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler); ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale); parameterMappings.add(parameterMapping); } builderAssistant.addParameterMap(id, parameterClass, parameterMappings); } }
7、parameterMapping——>configuration
生成了parameterMapping以后,放到了哪里呢,放到了configuration中
public ParameterMap addParameterMap(String id, Class<?> parameterClass, List<ParameterMapping> parameterMappings) { id = applyCurrentNamespace(id, false); ParameterMap.Builder parameterMapBuilder = new ParameterMap.Builder(configuration, id, parameterClass, parameterMappings); ParameterMap parameterMap = parameterMapBuilder.build(); configuration.addParameterMap(parameterMap); return parameterMap; }
8、总结
解析mapper,主要干了什么事呢?其实也没什么,就是把配置文件解析后,封装成了MappedStatement、ParameterMap、ResultMap这3个东西放到了Configuration中。
0 0
- mytatis解析xml的过程01
- xmlBeanDefinitionReader解析xml的过程
- XML编程的解析过程
- XML文件的解析过程
- xml的dom解析过程详解
- xml的SAX解析过程详解
- xml的Jdom解析过程详解
- xml的SAX解析过程详解
- XML解析具体过程
- Xml解析详细过程
- Spring XML解析过程
- spring xml解析过程
- XML类型的drawable图片的解析处理过程
- Android之DefaultHandler的生命周期(解析XML的过程)
- DOM将XML文件解析为文档的过程
- 一个XML解析失败排查过程的分享
- JBoss AS 6.1.0 Final bootstrap.xml的解析过程
- Xml文件解析过程中需要特别处理的字符串
- 南大软院大神养成第四天
- Android系统源码下载过程
- Spring MVC 里控制层返回JSONObject过滤null字段的方法
- 我的学习之路(一)
- 错排公式
- mytatis解析xml的过程01
- 初识字节流+实现缓冲字节流
- jquery ajax中data参数
- UML之初级篇
- mysql-5.7.9-linux-glibc2.5-x86_64 安装方法
- Uniform Generator
- CSS之float
- 欢迎使用CSDN-markdown编辑器
- CCF认证考试(java)---相反数