当前位置: 首页 > 科技观察

Mybatis是如何解析配置文件的?看完终于明白了

时间:2023-03-12 02:37:42 科技观察

在上一篇文章中,我们梳理了阅读Mybatis源码的全过程。今天就来详细说说Mybatis是如何解析配置文件的。这是今天分析的流程图:还是从案例说起。演示案例)sqlSession=sqlSessionFactory.openSession();UserMapperuserMapper=sqlSession.getMapper(UserMapper.class);System.out.println(userMapper.selectById(1));}catch(Exceptione){e.printStackTrace();}最后{try{inputStream.close();}catch(IOExceptione){e.printStackTrace();}sqlSession.close();}}见证SqlSessionFactoryBuilder的奇迹。SqlSessionFactoryBuilder类org.apache.ibatis.session.SqlSessionFactoryBuilder充满了构建方法的各种重载。//这个方法什么都没做,environment,properties);returnbuild(parser.parse());}catch(Exceptione){throwExceptionFactory.wrapException("ErrorbuildingSqlSession.",e);}finally{ErrorContext.instance().reset();try{inputStream.close();}catch(IOExceptione){//Intentionallyignore.Preferpreviouserror.}}}XMLConfigBuilder类重载了该类的构造方法:首先进入:publicXMLConfigBuilder(InputStreaminputStream,Stringenvironment,Propertiesprops){this(newXPathParser(inputStream,true,props,newXMLMapperEntityResolver()),environment,props);}privateXMLConfigBuilder(XPathParserparser,Stringenvironment,Propertiesprops){super(newConfiguration());ErrorContext.instance().resource("SQLMapperConfiguration");this.configuration.setVariables(props);this.parsed=false;this.environment=environment;this.parser=parser;}build(parser.parse());mybatis-config.xml中的parser.parse()在哪里解析呢?请看下面的方法://该方法返回一个Configuration对象publicConfigurationparse(){if(parsed){thrownewBuilderException("EachXMLConfigBuildercanonlybeusedonce.");}parsed=true;//关键点parseConfiguration(parser.evalNode("/configuration"));returnconfiguration;}parseConfiguration(parser.evalNode("/configuration"));终于看到开始解析配置文件了:进入方法parseConfigurationprivatevoidparseConfiguration(XNoderoot){try{//issue#117readpropertiesfirstpropertiesElement(root.evalNode("properties"));Propertiessettings=settingsAsProperties(root.evalNode("settings"));loadCustomVfs(settings);loadCustomLogImpl(settings);typeAliasesElement(root).evalNode("typeAliases"));pluginElement(root.evalNode("plugins"));objectFactoryElement(root.evalNode("objectFactory"));objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));reflectorFactoryElement(root.evalNode("reflectorFactory"));settingsElement(settings);//在objectFactoryandobjectWrapperFactoryissue#631environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers")));mapperElement(root.evalNode("mappers"));}catch(Exceptione){thrownewBuilderException("ErrorparsingSQLMapperConfiguration.Cause:"+e,e);}}这里是解析mybatis-config.xml的内容,然后设置到Configuration对象中那么我们定义的Mapper.xml是在哪里解析的呢?我们的Mapper.xml在mybatis-config.xml中的配置如下:有四种使用方式://1使用类路径//2使用绝对url路径//3使用java类名//4自动扫描包下的所有mappers继续源码分析,我们在上面的mybatis-config.xml分析中可以看到:我们不妨进入这个方法看看:privatevoidmapperElement(XNodeparent)throwsException{if(parent!=null){for(XNodechild:parent.getChildren()){//自动扫描包下的所有mapperif("package".equals(child.getName())){StringmapperPackage=child.getStringAttribute("name");//配置.addMappers(mapperPackage);}else{Stringresource=child.getStringAttribute("resource");Stringurl=child.getStringAttribute("url");StringmapperClass=child.getStringAttribute("class");//使用java类名if(resource!=null&&url==null&&mapperClass==null){ErrorContext.instance().resource(resource);//根据文件存储读取XxxMapper.xmlInputStreaminputStreamdirectory=Resources.getResourceAsStream(resource);//mapper比较复杂,调用XMLMapperBuilder//注意在for循环中,每个mapper都renew一个新的XMLMapperBuilder来解析XMLMapperBuildermapperParser=newXMLMapperBuilder(inputStream,configuration,resource,configuration.getSqlFragments());mapperParser.parse();//使用绝对url路径}elseif(resource==null&&url!=null&&mapperClass==null){ErrorContext.instance().resource(url);InputStreaminputStream=Resources.getUrlAsStream(url);//mapper比较复杂,调用XMLMapperBuilderXMLMapperBuildermapperParser=newXMLMapperBuilder(inputStream,configuration,url,configuration.getSqlFragments());mapperParser.parse();//使用类路径}elseif(resource==null&&url==null&&mapperClass!=null){ClassmapperInterface=Resources.classForName(mapperClass);//直接在配置中添加这个映射configuration.addMapper(mapperInterface);}else{thrownewBuilderException("Amapperelementmayonlyspecifyaurl,resourceorclass,butnotmorethanone.");}}}}}这里使用的方法和我们上面说的完全一样。到这里,配置文件mybatis-config.xml和我们定义的映射文件XxxMapper.xml都分析完成了。回到SqlSessionFactoryBuilder类,我们讲到XMLConfigBuilder中的parse方法,返回一个Configuration对象。构建(解析器。解析());这个构建方法是传入一个Configuration对象,然后构建一个DefaultSqlSession对象。publicSqlSessionFactorybuild(Configurationconfig){returnnewDefaultSqlSessionFactory(config);}继续回到我们演示代码中的这一行代码:SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);这行代码相当于:SqlSessionFactoryFactorySqlSessionFactory=newhere,我们的整个过程就完成了。本文转载自微信公众号《Java后端技术全栈》,可通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。