当Mapper.xml的各个标签被解析后SqlNode,然后SqlSourceBuilder进一步处理,
public SqlSource parse(String originalSql, Class> parameterType, MapadditionalParameters) { ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); String sql; if (configuration.isShrinkWhitespacesInSql()) { sql = parser.parse(removeExtraWhitespaces(originalSql)); } else { sql = parser.parse(originalSql); } return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); }
SqlSource接口是用来创建被数据库执行的sql,它只有一个getBoundSql()方法
public interface SqlSource { BoundSql getBoundSql(Object parameterObject); }
实现类有DynamicSqlSource、StaticSqlSource、RawSqlSource、ProviderSqlSource、VelocitySqlSource,这里重点说一下前三个实现类
DynamicSqlSource是解析动态sql的类
public class DynamicSqlSource implements SqlSource { private final Configuration configuration; private final SqlNode rootSqlNode; public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) { this.configuration = configuration; this.rootSqlNode = rootSqlNode; } @Override public BoundSql getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(configuration, parameterObject); rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); context.getBindings().forEach(boundSql::setAdditionalParameter); return boundSql; } }
它的getBoundSql()方法中:
RawSqlSource是解析静态sql文件的,在程序启动的时候就解析了
public class RawSqlSource implements SqlSource { private final SqlSource sqlSource; public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class> parameterType) { this(configuration, getSql(configuration, rootSqlNode), parameterType); } public RawSqlSource(Configuration configuration, String sql, Class> parameterType) { SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class> clazz = parameterType == null ? Object.class : parameterType; sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>()); } private static String getSql(Configuration configuration, SqlNode rootSqlNode) { DynamicContext context = new DynamicContext(configuration, null); rootSqlNode.apply(context); return context.getSql(); } @Override public BoundSql getBoundSql(Object parameterObject) { return sqlSource.getBoundSql(parameterObject); } }
它的构造方法调用了getSql()方法,这个方法里调用SqlSource的apply()方法组装成完整sql,然后通过SqlSourceBuilder调用parse()方法处理#{}占位符,返回StaticSqlSource对象
StaticSqlSource类:
public class StaticSqlSource implements SqlSource { @Override public BoundSql getBoundSql(Object parameterObject) { return new BoundSql(configuration, sql, parameterMappings, parameterObject); } }
它的getBoundSql()方法就是创建BoundSql对象
这篇文章讲了SqlSource的接口和它的几个实现类,其中DynamicSqlSource类和RawSqlSource类最最终生成StaticSqlSource类,由StaticSqlSource类调用getBoundSql()方法来创建BoundSql类,DynamicSqlSource是解析动态sql的类,RawSqlSource是解析静态sql的类,在程序启动的时候就生成sql了