下面说说Mybatis的动态Sql的SqlSource构造SqlSource对象。当Mapper.xml的每一个标签被解析后,SqlNode就会被SqlSourceBuilder进一步处理。publicSqlSourceparse(StringoriginalSql,Class>parameterType,MapadditionalParameters){ParameterMappingTokenHandlerhandler=newParameterMappingTokenHandler(configuration,parameterType,additionalParameters);GenericTokenParser解析器=newGenericTokenParser("#{","}",handler);字符串sql;如果(配置。(originalSql));}else{sql=parser.parse(originalSql);}returnnewStaticSqlSource(configuration,sql,handler.getParameterMappings());}1.ParameterMappingTokenHandler是一个静态内部类,用来保存各个占位符2.创建一个识别#{}占位符的GenericTokenParser,解析sql,最后形成一个StaticSqlSource对象。SqlSource接口。SqlSource接口用于创建由数据库执行的sql。它只有一个getBoundSql()方法publicinterfaceSqlSource{BoundSqlgetBoundSql(ObjectparameterObject);}有DynamicSqlSource、StaticSqlSource、RawSqlSource、ProviderSqlSource、VelocitySqlSource,这里重点说一下前三个实例动态Sql类DynamicSqlSource是解析动态sql的类publicclassprivatefinalfinalDynamicSqlSourceimplementsConfiguration;私有最终SqlNoderootSqlNode;publicDynamicSqlSource(Configurationconfiguration,SqlNoderootSqlNode){this.configuration=configuration;this.rootSqlNode=rootSqlNode;}@OverridepublicBoundSqlgetBoundSql(ObjectparameterObject){DynamicContextcontext=newDynamicContext(configuration,parameterObject);rootSqlNode.apply(上下文);SqlSourceBuildersqlSourceParser=newSqlSourceBuilder(配置);类>parameterType=parameterObject==null?Object.class:parameterObject.getClass();SqlSourcesqlSource=sqlSourceParser.parse(context.getSql(),parameterType,context.getBindings());BoundSqlboundSql=sqlSource.getBoundSql(parameterObject);context.getBindings().forEach(boundSql::setAdditionalParameter);返回绑定SQL;}}在其getBoundSql()方法中:创建一个DynamicContext对象,调用SqlNode的apply()方法完成sql片段的解析创建一个SqlSourceBuilder对象,调用parse()方法解析#{},替换为?Placeholder,返回StaticSqlSource对象,调用StaticSqlSource的getBoundSql()方法,返回BoundSql对象,其中存放了sql语句的相关信息,返回BoundSql对象解析静态SQL类RawSqlSource用于解析静态sql文件,解析当程序启动时publicclassRawSqlSourceimplementsSqlSource{privatefinalSqlSourcesqlSource;publicRawSqlSource(Configurationconfiguration,SqlNoderootSqlNode,Class>parameterType){this(configuration,getSql(configuration,rootSqlNode),parameterSqlTypeconfig);}publicsql,Class>parameterType){SqlSourceBuildersqlSourceParser=newSqlSourceBuilder(configuration);类>clazz=parameterType==null?对象类:参数类型;sqlSource=sqlSourceParser.parse(sql,clazz,newHashMap<>());}privatestaticStringgetSql(Configurationconfiguration,SqlNoderootSqlNode){DynamicContextcontext=newDynamicContext(configuration,null);rootSqlNode.apply(上下文);返回context.getSql();}@OverridepublicBoundSqlgetBoundSql(ObjectparameterObject){returnsqlSource.getBoundSql(parameterObject);}}它的构造方法调用getSql()方法。该方法中调用SqlSource的apply()方法拼装出完整的sql,然后调用parse()方法通过SqlSourceBuilder处理#{}占位符,返回StaticSqlSource对象。StaticSqlSourceStaticSqlSource类:publicclassStaticSqlSourceimplementsSqlSource{@OverridepublicBoundSqlgetBoundSql(ObjectparameterObject){returnnewBoundSql(configuration,sql,parameterMappings,parameterObject);}}它的getBoundSql()方法是创建一个BoundSql对象总结本文讲了SqlSource的接口和它的几个实现类,其中DynamicSqlSource类和RawSqlSource类最后生成了StaticSqlSource类,getBoundSql()方法由StaticSqlSource类调用以创建BoundSql类。DynamicSqlSource是解析动态SQL的类,RawSqlSource是解析静态SQL的类。程序启动时会生成sql。欢迎关注我的公众号:打码老贾回复“领取”送《Java面试》信息,阿里、腾讯、字节、美团、饿了么等大厂