你写在mapper.xml文件中的SQL语句最后是怎么执行的?我们写的mapper接口最终是如何生成代理对象并被调用执行的呢?这部分内容应该是Mybatis框架中最为关键和复杂的部分。今天这篇文章的主要目的是搞清楚:mybatis框架中的mapper.xml文件是如何初始化的?mapper接口生成动态代理对象的过程。mapper接口动态代理对象的执行过程。掌握了以上三个问题,我们就掌握了Mybatis的核心。Mapper初始化过程参考mapper.xml文件的解析过程。此操作在创建SqlSessionFactory期间或在构建SqlSessionFactory之前同步完成。XMLMapperBuilder负责解析mapper.xml文件,SqlSessionFactorBean的buildSqlSessionFactory()方法会针对不同的配置情况进行解析。最常用的是在配置文件中指定mapper.xml文件的路径(即源码中的mapperLocations):if(this.mapperLocations!=null){if(this.mapperLocations.length==0){记录器。warn(()->“指定了属性‘mapperLocations’,但未找到匹配的资源。”);}else{for(ResourcemapperLocation:this.mapperLocations){if(mapperLocation==null){继续;}try{XMLMapperBuilderxmlMapperBuilder=newXMLMapperBuilder(mapperLocation.getInputStream(),targetConfiguration,mapperLocation.toString(),targetConfiguration.getSqlFragments());xmlMapperBuilder.parse();}catch(Exceptione){thrownewNestedIOException("解析映射资源失败:'"+mapperLocation+"'",e);}最后{ErrorContext.instance().reset();}LOGGER.debug(()->"已解析的映射器文件:'"+mapperLocation+"'");}}}else{LOGGER.debug(()->“未指定属性‘mapperLocations’。”);}返回this.sqlSessionFactoryBuilder.build(targetConfiguration);创建一个XMLMapperBuilder对象并调用parse()方法完成解析XMLMapperBuilder#configurationElement()parse方法会调用configurationElement()方法,而解析mapper.xml的关键部分在configurationElement方法中。今天重点分析mapper.xml文件中的SQL语句,即insert、update、delete、select等标签的分析。privatevoidconfigurationElement(XNodecontext){try{//获取命名空间Stringnamespace=context.getStringAttribute("namespace");if(namespace==null||namespace.isEmpty()){thrownewBuilderException("Mapper的命名空间不能为空");}builderAssistant.setCurrentNamespace(命名空间);//解析二级缓存RefcacheRefElement(context.evalNode("cache-ref"));//解析二级缓存配置cacheElement(context.evalNode("cache"));//解析parameterMap标签parameterMapElement(context.evalNodes("/mapper/parameterMap"));//解析resultMap标签resultMapElements(context.evalNodes("/mapper/resultMap"));//sql标签解析sqlElement(context.evalNodes("/mapper/sql"));//关键部分:sql语句的解析buildStatementFromContext(context.evalNodes("select|insert|update|delete"));}catch(Exceptione){thrownewBuilderException("解析MapperXML时出错。XMLl位置是“”+资源+“”。Cause:"+e,e);}}如果继续跟踪sql语句的解析部分,会发现在sql语句最后解析完成后,会创建一个MappedStatement保存在配置对象中(以xml文件的形式,在id为key值的Map中):MappedStatementstatement=statementBuilder.build();configuration.addMappedStatement(statement);returnstatement;这样我们就可以理解在sql语句写完之后mapper.xml被解析,最后保存在配置对象的mappedStatements中,mappedStatements实际上是以mapper文件中相关tag的id值作为key值,由hashMapper接口生成的动态代理过程。我们都知道说明Mapper对象是通过SqlSession的getMapper方法获取的,其实Mapper接口的代理对象也是在这个调用过程中生成的:@Overridepublic
