看下面SqlSessionFactory是怎么构建的
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
通过XMLConfigBuilder去解析,看看XMLConfigBuilder怎么初始化的
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
发现做了两件事情:
1.构建MyBatis DTD的离线实体解析器,就是XMLMapperEntityResolver
2.构建XPathParser
public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(reader));创建document
}
commonConstructor方法
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation; 是否开启验证默认是true
this.entityResolver = entityResolver;离线实体解析器
this.variables = variables;配置文件里面Properties节点的内容
XPathFactory factory = XPathFactory.newInstance();获取xpath工厂
this.xpath = factory.newXPath();实例化xpath
}
XMLConfigBuilder的重载方法
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());初始化父类的Configuration
ErrorContext.instance().resource("SQL Mapper Configuration");记录上下文
this.configuration.setVariables(props);//设置父类的Configuration的变量
this.parsed = false;设置变量为没解析
this.environment = environment;设置环境变量
this.parser = parser;设置XPathParser
}
初始化父类的Configuration都干了些什么
public Configuration() {
注册一些默认的类型别名
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
注册语言驱动 languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
至此XMLConfigBuilder初始化完毕,总结下
- 设置了是否解析变量为false
- 构建XPathParser(里面创建了xpath,还有document等等。。。)
- 设置了环境变量environment
- 构建localReflectorFactory
- 构建configuration
- 复制configuration内的typeAliasRegistry和typeHandlerRegistry到XMLConfigBuilder
XMLConfigBuilder的parse流程
public Configuration parse() {
//判断xml是否解析过解析过就抛异常
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
//设置xml已解析
parsed = true;
//解析xml下的configuration节点
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
// 读取 properties的属性
propertiesElement(root.evalNode("properties"));
// 读取 settings 属性
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 从settings指定 VFS 的实现
loadCustomVfs(settings);
// 从settings指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
loadCustomLogImpl(settings);
//解析 类型别名
typeAliasesElement(root.evalNode("typeAliases"));
// 解析 插件
pluginElement(root.evalNode("plugins"));
// 设置对象工厂
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
//设置 settings
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 环境配置
environmentsElement(root.evalNode("environments"));
// 数据库厂商标识
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 类型处理器
typeHandlerElement(root.evalNode("typeHandlers"));
// 映射器(mappers)
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
读取 properties的属性
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
// 获取所有子节点的name、value属性键值对
Properties defaults = context.getChildrenAsProperties();
//获取resource属性
String resource = context.getStringAttribute("resource");
//获取url属性
String url = context.getStringAttribute("url");
//如果两个都不为null 就抛出异常
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
//解析resource或者url放进Properties里面
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
//从configuration获取变量
Properties vars = configuration.getVariables();
//不为空就加入Properties里面
if (vars != null) {
defaults.putAll(vars);
}
//最后把Properties设置进XMLConfigBuilder和configuration
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
读取 settings 属性
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
//获取setting所有的 name 和 value转换为Properties
Properties props = context.getChildrenAsProperties();
// Check that all settings are known to the configuration class
//获取元类 初始化reflector(缓存的类定义信息)把reflector || PUT进reflectorMap里面key是Configuration.class value是reflector
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
//迭代props里面的value 检查reflector里面有没有 没有就抛异常
for (Object key : props.keySet()) {
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
指定 VFS 的实现
private void loadCustomVfs(Properties props) throws ClassNotFoundException {
//读取vfsImpl 字段
String value = props.getProperty("vfsImpl");
if (value != null) {
//逗号分割字符串为数组
String[] clazzes = value.split(",");
//遍历 加载CLASS 设置进configuration
for (String clazz : clazzes) {
if (!clazz.isEmpty()) {
@SuppressWarnings("unchecked")
Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
configuration.setVfsImpl(vfsImpl);
}
}
}
}
指定 MyBatis 所用日志的具体实现
private void loadCustomLogImpl(Properties props) {
//获取Log的子类CLASSS
Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));\
//设置configuration的日志的具体实现
configuration.setLogImpl(logImpl);
}
resolveClass方法判空操作调用resolveAlias
protected <T> Class<? extends T> resolveClass(String alias) {
if (alias == null) {
return null;
}
try {
return resolveAlias(alias);
} catch (Exception e) {
throw new BuilderException("Error resolving class. Cause: " + e, e);
}
}
resolveAlias调用typeAliasRegistry看是否已经有
protected <T> Class<? extends T> resolveAlias(String alias) {
return typeAliasRegistry.resolveAlias(alias);
}
解析逻辑
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
//转换为小写,
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
//判断 typeAliases容器里面存不存在
if (typeAliases.containsKey(key)) {
//如果有 就从容器获取
value = (Class<T>) typeAliases.get(key);
} else {
//没有 通过类加载构建 Class 没有传ClassLoader 代表使用默认
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
解析 类型别名
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//判断是否为package
if ("package".equals(child.getName())) {
//获取name 属性
String typeAliasPackage = child.getStringAttribute("name");
//注册到configuration的typeAliasRegistry里面
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
//获取alias type属性
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
//加载CLASS
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
//注册到typeAliasRegistry 如果alias为空使用 Bean 的首字母小写的非限定类名来作为它的别名
typeAliasRegistry.registerAlias(clazz);
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
public void registerAliases(String packageName) {
registerAliases(packageName, Object.class);
}
public void registerAliases(String packageName, Class<?> superType) {
//ResolverUtil用于查找在类路径可用并满足任意条件的类
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
//查找packageName包下所有Object的子类,也就是所有类。
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
//获取所有符合的CLASS
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for (Class<?> type : typeSet) {
//忽略内部类和接口(包括package-info.java)
// Ignore inner classes and interfaces (including package-info.java)
//也跳过内部类
// Skip also inner classes. See issue #6
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
//注册
registerAlias(type);
}
}
}
objectFactory objectWrapperFactory reflectorFactory settingsElement几个方法就不解析了就是设置到configuration里面
接下来看environmentsElement
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
//获取default属性
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
//获取Id属性
String id = child.getStringAttribute("id");
//判断default属性 和 id是否一样
if (isSpecifiedEnvironment(id)) {
//解析事务
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//解析数据源构建工厂
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
//Environment建造者模式 构建Environment
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
数据库厂商标识 databaseIdProviderElement
private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
//获取type属性
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
//兼容 VENDOR
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
//获取所有的子Properties
Properties properties = context.getChildrenAsProperties();
//实例化
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
//设置Properties
databaseIdProvider.setProperties(properties);
}
//获取环境配置
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
//获取databaseId 并设置
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId);
}
}
typeHandlerElement
private void typeHandlerElement(XNode parent) {
if (parent != null) {
//遍历
for (XNode child : parent.getChildren()) {
//如果是package 类型的
if ("package".equals(child.getName())) {
//获取包路径
String typeHandlerPackage = child.getStringAttribute("name");
//注册到typeHandlerRegistry 必须是实现了TypeHandler接口的
typeHandlerRegistry.register(typeHandlerPackage);
} else {
//获取java类型 jdbc类型 handler 注册到typeHandlerRegistry
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
mapperElement
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
//遍历子节点
for (XNode child : parent.getChildren()) {
//package子节点
if ("package".equals(child.getName())) {
//获取包路径
String mapperPackage = child.getStringAttribute("name");
//添加到knownMappers里面
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());
//解析mapper
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.");
}
}
}
}
}
使用的是xml主要看XMLMapperBuilder的parse方法
//判断mapper是否解析过
if (!configuration.isResourceLoaded(resource)) {
// 读取整个mapper文件。
configurationElement(parser.evalNode("/mapper"));
// 把这个已经加载的配置文件(资源,resource)放到configuration这个Set中。
configuration.addLoadedResource(resource);
//绑定命名空间和保存mapper Class
bindMapperForNamespace();
}
// 解析ResultMaps
parsePendingResultMaps();
// 解析缓存
parsePendingCacheRefs();
// 解析Statements
parsePendingStatements();
configurationElement
private void configurationElement(XNode context) {
try {
//获取namespace属性
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.isEmpty()) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//设置助手当前的命名空间
builderAssistant.setCurrentNamespace(namespace);
//命名空间 二级缓存
cacheRefElement(context.evalNode("cache-ref"));
//一级缓存
cacheElement(context.evalNode("cache"));
//parameterMap – 参数映射
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
resultMapElements(context.evalNodes("/mapper/resultMap"));
//sql 这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。
sqlElement(context.evalNodes("/mapper/sql"));
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
这里主要看下buildStatementFromContext(context.evalNodes(“select|insert|update|delete”))是怎么解析的
/**
* 如果DatabaseId这里不为null的情况会解析两遍
* 一遍是带DatabaseId的
* 一边是不带
* @param list
*/
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
//遍历解析所有的节点
for (XNode context : list) {
//创建一个XMLStatementBuilder去解析每个标签
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
//解析xml Statement
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
这里到了非常关键的点,statementParser.parseStatementNode()看看是怎么解析Statement的
public void parseStatementNode() {
//获取 id 属性
String id = context.getStringAttribute("id");
//获取 databaseId 属性
String databaseId = context.getStringAttribute("databaseId");
//做一些检查
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
//获取标签名称
String nodeName = context.getNode().getNodeName();
//通过标签名称构造SqlCommandType
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
//是否为查询语句
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
//获取flushCache 如果flushCache为null 就isSelect取反 不然就是用flushCache的值
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
//获取useCache 如果useCache为null 就isSelect
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
//获取resultOrdered 如果resultOrdered为null 就是false
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
// Include Fragments before parsing\
//创建Include标签解析
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
//获取 parameterType 属性
String parameterType = context.getStringAttribute("parameterType");
//通过typeAliases 获取class如果没有就加载过来
Class<?> parameterTypeClass = resolveClass(parameterType);
//获取 lang属性
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
// Parse selectKey after includes and remove them.
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
//解析xml节点,封装成SqlSource里面携带了是否为动态sql(通过SqlSource的实现类型),还有configuration和拆分成各种SqlNode的list
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
主要关注两个方法SqlSource是怎么创建的和最后的mappedStatement
这里如果没有指定langDriver默认使用的XMLLanguageDriver,可以看看逻辑是怎么实现的
langDriver.createSqlSource(configuration, context, parameterTypeClass)
@Override
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
/**
* 创建XML脚本构建器
*/
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
/***
* 当sql中包含有${}时,就认为是动态SQL
* 或者 当DML标签存在动态SQL标签名,如<if>,<trim>等,就认为是动态SQL
* ,如果是动态返回 {@link DynamicSqlSource} ,否则 {@link RawSqlSource}
*/
return builder.parseScriptNode();
}
public SqlSource parseScriptNode() {
//解析DML标签下的子节点,封装成MixedSqlNode(里面有一个list存各种SqlNode),解析是否为动态sql
MixedSqlNode rootSqlNode = parseDynamicTags(context);
SqlSource sqlSource;
//判断是否为动态sql
if (isDynamic) {
//只创建DynamicSqlSource对象。完整可执行的sql,需要在调用getBoundSql(Parameter)方法时才能组装完成。
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
/**
* 调用 SqlSourceBuilder类将"#{xxx}“ 替换为占位符”?",并绑定ParameterMapping,
* 最后返回的RawSqlSource中持有一个由SqlSourceBuilder构建的SqlSource对象。
*/
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
/**
* 解析动态SQL标签,node的子节点和文本节点进行解析,
* 这里会检测是否属于动态就会对isDynamic设置对应的值
*/
protected MixedSqlNode parseDynamicTags(XNode node) {
List<SqlNode> contents = new ArrayList<>();
NodeList children = node.getNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
/**
* XNode.newXNode(Node node):新建一个XNode,XNode只是mybatis对Node实例的封装,用于方便操作。
* 并不是添加node节点的功能
*/
XNode child = node.newXNode(children.item(i));
/**
* Node.CDATA_SECTION_NODE:代表文档中的 CDATA 部(不会由解析器解析的文本)
* Node.TEXT_NODE:代表元素或属性中的文本内容
*/
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
String data = child.getStringBody("");
TextSqlNode textSqlNode = new TextSqlNode(data);
if (textSqlNode.isDynamic()) {
contents.add(textSqlNode);
isDynamic = true;
} else {
contents.add(new StaticTextSqlNode(data));
}
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
String nodeName = child.getNode().getNodeName();
NodeHandler handler = nodeHandlerMap.get(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
handler.handleNode(child, contents);
isDynamic = true;
}
}
return new MixedSqlNode(contents);
}
下面就是mybatis建造者模式的案例
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
//这里做一些非空的判断完成建造者模式
MappedStatement statement = statementBuilder.build();
/**
* 把解析完成的MappedStatement装进mappedStatements的容器了
* key是xml上面的id
*/
configuration.addMappedStatement(statement);
return statement;
}
configuration.addLoadedResource(resource)
public void addLoadedResource(String resource) {
loadedResources.add(resource);
}
bindMapperForNamespace()
private void bindMapperForNamespace() {
/**
* 通过构建助手拿到命名空间
*/
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
// 绑定类型
Class<?> boundType = null;
try {
/**
* 通过类加载器加载class
*/
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
// ignore, bound type is not required
}
/**
* class不为空并且knownMappers里面没有这个key
*/
if (boundType != null && !configuration.hasMapper(boundType)) {
/**
* Spring可能不知道真实的资源名称,因此我们设置了一个标志
* 以防止再次从mapper接口加载此资源
* 查看MapperAnnotationBuilder#loadXmlResource
*/
/**
* 把命名空间添加进loadedResources里面开头是namespace:
*/
configuration.addLoadedResource("namespace:" + namespace);
/**
* 添加进knownMappers里面 kye是class value是MapperProxyFactory
*/
configuration.addMapper(boundType);
}
}
}
下面就是mapper的核心代码,怎么把mapper通过动态代理放到配置类的mapperRegistry里面的knownMappers里
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {
//判断是接口
if (type.isInterface()) {
//查看knownMappers里面是否有
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
//是否加载完成
boolean loadCompleted = false;
try {
//添加进knownMappers key是Class value是MapperProxyFactory里面的MapperProxyFactory是当前Class
knownMappers.put(type, new MapperProxyFactory<>(type));
/**
* 重要的是,必须在运行解析器之前添加类型,
* 否则映射器解析器可能会自动尝试绑定。
* 如果类型是已知的,则不会尝试。
*/
//构建MapperAnnotationBuilder
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
//解析
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
parser.parse()
public void parse() {
String resource = type.toString();
//判断configuration里面的loadedResources里面是否有当前的resource
if (!configuration.isResourceLoaded(resource)) {
//解析接口同名路径下的xml
loadXmlResource();
//把resource设置LoadedResource
configuration.addLoadedResource(resource);
//设置助手的当前命名空间为接口的包名
assistant.setCurrentNamespace(type.getName());
//设置二级缓存(基于注解@CacheNamespace)
parseCache();
//设置二级缓存引用(基于注解@CacheNamespaceRef)
parseCacheRef();
for (Method method : type.getMethods()) {
//判断是否为桥接方法和默认方法 是的话不处理
if (!canHaveStatement(method)) {
continue;
}
//检查构建annotationWrapper是否成功 方法上面有ResultMap注解 然后就 解析ResultMap
if (getAnnotationWrapper(method, false, Select.class, SelectProvider.class).isPresent()
&& method.getAnnotation(ResultMap.class) == null) {
parseResultMap(method);
}
try {
/**
* 解析(基于注解的方法)Statement 放入configuration
*/
parseStatement(method);
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
void parseStatement(Method method) {
//获取方法的参数
final Class<?> parameterTypeClass = getParameterType(method);
final LanguageDriver languageDriver = getLanguageDriver(method);
/**
* 构造AnnotationWrapper
* 解析方法上面的注解select.class, Update.class, Insert.class, Delete.class,
* SelectProvider.class, UpdateProvider.class,InsertProvider.class, DeleteProvider.class
*/
getAnnotationWrapper(method, true, statementAnnotationTypes).ifPresent(statementAnnotation -> {
//构建SqlSource
final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass, languageDriver, method);
final SqlCommandType sqlCommandType = statementAnnotation.getSqlCommandType();
final Options options = getAnnotationWrapper(method, false, Options.class).map(x -> (Options)x.getAnnotation()).orElse(null);
final String mappedStatementId = type.getName() + "." + method.getName();
final KeyGenerator keyGenerator;
String keyProperty = null;
String keyColumn = null;
//判断是否为INSERT UPDATE
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
// first check for SelectKey annotation - that overrides everything else
/**
* 首先检查SelectKey注释-覆盖其他所有内容
*/
SelectKey selectKey = getAnnotationWrapper(method, false, SelectKey.class).map(x -> (SelectKey)x.getAnnotation()).orElse(null);
if (selectKey != null) {
keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
keyProperty = selectKey.keyProperty();
} else if (options == null) {
keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
} else {
keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
keyProperty = options.keyProperty();
keyColumn = options.keyColumn();
}
} else {
keyGenerator = NoKeyGenerator.INSTANCE;
}
Integer fetchSize = null;
Integer timeout = null;
StatementType statementType = StatementType.PREPARED;
ResultSetType resultSetType = configuration.getDefaultResultSetType();
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = !isSelect;
boolean useCache = isSelect;
if (options != null) {
if (FlushCachePolicy.TRUE.equals(options.flushCache())) {
flushCache = true;
} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {
flushCache = false;
}
useCache = options.useCache();
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348
timeout = options.timeout() > -1 ? options.timeout() : null;
statementType = options.statementType();
if (options.resultSetType() != ResultSetType.DEFAULT) {
resultSetType = options.resultSetType();
}
}
String resultMapId = null;
//如果是查询就构建resultMapId返回参数
if (isSelect) {
//如果有@ResultMap就获取valer通过逗号,分割
ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
if (resultMapAnnotation != null) {
resultMapId = String.join(",", resultMapAnnotation.value());
} else {
/**
* 解析@Results通过接口的全路径名加上.加上@Results的id值
* 没有@Results注解就遍历方法的返回参数通过 -加上参数名
* 如果没有返回参数名就用-void
*/
resultMapId = generateResultMapName(method);
}
}
assistant.addMappedStatement(
mappedStatementId,
sqlSource,
statementType,
sqlCommandType,
fetchSize,
timeout,
// ParameterMapID
null,
parameterTypeClass,
resultMapId,
getReturnType(method),
resultSetType,
flushCache,
useCache,
// TODO gcode issue #577
false,
keyGenerator,
keyProperty,
keyColumn,
statementAnnotation.getDatabaseId(),
languageDriver,
// ResultSets
options != null ? nullOrEmpty(options.resultSets()) : null);
});
}
上面就是通过注解解为MappedStatement的流程