Mybatis工作机制源码分析—初始化—config配置文件解析

     本文通过源码分析的形式讲解Mybatis config配置文件是如何解析的。

时序图


相关源码

/** XMLConfigBuilder解析 */
/** XMLConfigBuilder.java */
public Configuration parse() {
	if (parsed) {
	  throw new BuilderException("Each XMLConfigBuilder can only be used once.");
	}
	parsed = true;
	parseConfiguration(parser.evalNode("/configuration"));
	return configuration;
}

/** XMLConfigBuilder.java */
// 全面解析<configuration>配置,解析到Configuration configuration
private void parseConfiguration(XNode root) {
	try {
	  //issue #117 read properties first
	  // 解析"configuration\properties"元素
	  propertiesElement(root.evalNode("properties"));
	  // 解析"configuration\typeAliases"元素
	  typeAliasesElement(root.evalNode("typeAliases"));
	  // 解析"configuration\plugins"元素
	  pluginElement(root.evalNode("plugins"));
	  // 解析"configuration\objectFactory"元素
	  objectFactoryElement(root.evalNode("objectFactory"));
	  // 解析"configuration\objectWrapperFactory"元素
	  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
	  // 解析"configuration\reflectionFactory"元素
	  reflectionFactoryElement(root.evalNode("reflectionFactory"));
	  // 解析"configuration\settings"元素
	  settingsElement(root.evalNode("settings"));
	  // read it after objectFactory and objectWrapperFactory issue #631
	  // 解析"configuration\environments"元素
	  environmentsElement(root.evalNode("environments"));
	  // 解析"configuration\databaseIdProvider"元素
	  databaseIdProviderElement(root.evalNode("databaseIdProvider"));
	  // 解析"configuration\typeHandlers"元素
	  typeHandlerElement(root.evalNode("typeHandlers"));
	  // 解析"configuration\mappers"元素
	  mapperElement(root.evalNode("mappers"));
	} catch (Exception e) {
	  throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
	}
}

private void propertiesElement(XNode context) throws Exception {
	if (context != null) {
	  // 获取"configuration\properties"下的property键值对
	  Properties defaults = context.getChildrenAsProperties();
	  String resource = context.getStringAttribute("resource");
	  String url = context.getStringAttribute("url");
	  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.");
	  }
	  if (resource != null) {
		// 获取"configuration\properties"元素"resource"属性对应的Properties
		defaults.putAll(Resources.getResourceAsProperties(resource));
	  } else if (url != null) {
		// 获取"configuration\properties"元素"url"属性对应的Properties
		defaults.putAll(Resources.getUrlAsProperties(url));
	  }
	  // 获取configuration下的variables Properties
	  Properties vars = configuration.getVariables();
	  if (vars != null) {
		defaults.putAll(vars);
	  }
	  // XPathParser设置defaults Properties
	  parser.setVariables(defaults);
	  // configuration设置defaults Properties
	  configuration.setVariables(defaults);
	}
}

private void typeAliasesElement(XNode parent) {
	if (parent != null) {
	  for (XNode child : parent.getChildren()) {
		if ("package".equals(child.getName())) {
		  String typeAliasPackage = child.getStringAttribute("name");
		  configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
		} else {
		  String alias = child.getStringAttribute("alias");
		  String type = child.getStringAttribute("type");
		  try {
			Class<?> clazz = Resources.classForName(type);
			if (alias == null) {
			  typeAliasRegistry.registerAlias(clazz);
			} else {
			  // 注册alias、clazz键值对
			  typeAliasRegistry.registerAlias(alias, clazz);
			}
		  } catch (ClassNotFoundException e) {
			throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
		  }
		}
	  }
	}
}

//MyBatis使用Interceptor拦截器的方式实现插件
private void pluginElement(XNode parent) throws Exception {
	if (parent != null) {
	  for (XNode child : parent.getChildren()) {
		String interceptor = child.getStringAttribute("interceptor");
		Properties properties = child.getChildrenAsProperties();
		Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
		interceptorInstance.setProperties(properties);
		configuration.addInterceptor(interceptorInstance);
	  }
	}
}

private void objectFactoryElement(XNode context) throws Exception {
	if (context != null) {
	  String type = context.getStringAttribute("type");
	  Properties properties = context.getChildrenAsProperties();
	  ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
	  factory.setProperties(properties);
	  configuration.setObjectFactory(factory);
	}
}

private void objectWrapperFactoryElement(XNode context) throws Exception {
	if (context != null) {
	  String type = context.getStringAttribute("type");
	  ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
	  configuration.setObjectWrapperFactory(factory);
	}
}

private void reflectionFactoryElement(XNode context) throws Exception {
	if (context != null) {
	   String type = context.getStringAttribute("type");
	   ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
	   configuration.setReflectorFactory(factory);
	}
}

private void settingsElement(XNode context) throws Exception {
	if (context != null) {
	  Properties props = context.getChildrenAsProperties();
	  // Check that all settings are known to the configuration class
	  MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
	  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).");
		}
	  }
	  configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
	  configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
	  configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
	  configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
	  configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
	  configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
	  configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
	  configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
	  configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
	  configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
	  configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
	  configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
	  configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
	  configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
	  configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
	  configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
	  configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
	  configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
	  configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
	  configuration.setLogPrefix(props.getProperty("logPrefix"));
	  configuration.setLogImpl(resolveClass(props.getProperty("logImpl")));
	  configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
	}
}

private void environmentsElement(XNode context) throws Exception {
	if (context != null) {
	  if (environment == null) {
		// 获取"configuration\environments"的default属性值,设置为默认的environment
		environment = context.getStringAttribute("default");
	  }
	  // 遍历"configuration\environments\environment"
	  for (XNode child : context.getChildren()) {
		String id = child.getStringAttribute("id");
		if (isSpecifiedEnvironment(id)) { // 默认的environment		  
		  TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
		  DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
		  DataSource dataSource = dsFactory.getDataSource();
		  Environment.Builder environmentBuilder = new Environment.Builder(id)
			  .transactionFactory(txFactory)
			  .dataSource(dataSource);
		  configuration.setEnvironment(environmentBuilder.build());
		}
	  }
	}
}

private void databaseIdProviderElement(XNode context) throws Exception {
	DatabaseIdProvider databaseIdProvider = null;
	if (context != null) {
	  // 获取"configuration\databaseIdProvider"的default属性值
	  String type = context.getStringAttribute("type");
	  // awful patch to keep backward compatibility
	  if ("VENDOR".equals(type)) {
		  type = "DB_VENDOR";
	  }
	  // 解析获取databaseIdProvider
	  Properties properties = context.getChildrenAsProperties();
	  databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
	  databaseIdProvider.setProperties(properties);
	}
	Environment environment = configuration.getEnvironment();
	if (environment != null && databaseIdProvider != null) {
	  // 获取databaseId
	  String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
	  configuration.setDatabaseId(databaseId);
	}
}

// 解析"configuration\typeHandlers"元素
private void typeHandlerElement(XNode parent) throws Exception {
	if (parent != null) {
	  for (XNode child : parent.getChildren()) {
		if ("package".equals(child.getName())) {
		  String typeHandlerPackage = child.getStringAttribute("name");
		  typeHandlerRegistry.register(typeHandlerPackage);
		} else {
		  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) {
			// 注册typeHandler
			if (jdbcType == null) {
			  typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
			} else {
			  typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
			}
		  } else {
			typeHandlerRegistry.register(typeHandlerClass);
		  }
		}
	  }
	}
}

private void mapperElement(XNode parent) throws Exception {
	if (parent != null) {
	  for (XNode child : parent.getChildren()) {
		if ("package".equals(child.getName())) { 
		  // 解析"package"元素
		  String mapperPackage = child.getStringAttribute("name");
		  configuration.addMappers(mapperPackage);
		} else {
		  // 解析"mapper"元素
		  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());
			mapperParser.parse(); // resource形式的mapper, XMLMapperBuilder解析
		  } 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(); // url形式的mapper,XMLMapperBuilder解析
		  } else if (resource == null && url == null && mapperClass != null) {
			Class<?> mapperInterface = Resources.classForName(mapperClass);
			configuration.addMapper(mapperInterface); // class形式的mapper,MapperAnnotationBuilder解析
		  } else {
			throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
		  }
		}
	  }
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值