博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌
Java知识图谱点击链接:体系化学习Java(Java面试专题)
💕💕 感兴趣的同学可以收藏关注下 ,不然下次找不到哟💕💕
1、配置解析方法
在我的另一篇文章:深入学习 Mybatis 的四大组件源码 中有介绍到 XMLConfigBuilder.parse方法,这个方法是 MyBatis 中用于解析配置文件的核心方法之一。下面是对该方法的源码分析和注释:
public Configuration parse() {
// 如果configuration对象为空,就创建一个新的对象
if (!parsed) {
parsed = true;
// 调用parseConfiguration方法解析配置文件
configurationElement(parser.evalNode("/configuration"));
}
return configuration;
}
// 解析配置文件
private void configurationElement(XNode context) {
try {
// 创建一个Configuration对象
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
// 解析properties节点
propertiesElement(context.evalNode("properties"));
// 解析settings节点
Properties settings = settingsAsProperties(context.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
// 解析typeAliases节点
typeAliasesElement(context.evalNode("typeAliases"));
// 解析plugins节点
pluginElement(context.evalNode("plugins"));
// 解析objectFactory节点
objectFactoryElement(context.evalNode("objectFactory"));
// 解析objectWrapperFactory节点
objectWrapperFactoryElement(context.evalNode("objectWrapperFactory"));
// 解析reflectorFactory节点
reflectorFactoryElement(context.evalNode("reflectorFactory"));
// 将settings节点中的属性设置到Configuration对象中
settingsElement(settings);
// 解析environments节点
environmentsElement(context.evalNode("environments"));
// 解析databaseIdProvider节点
databaseIdProviderElement(context.evalNode("databaseIdProvider"));
// 解析typeHandlers节点
typeHandlerElement(context.evalNode("typeHandlers"));
// 解析mappers节点
mapperElement(context.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
// 解析mappers节点
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
// 遍历mappers节点下的所有子节点
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
// 如果子节点是package,就扫描指定包下的所有映射器
String mapperPackage = child.getStringAttribute("name");
builderAssistant.addMapper(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, builderAssistant.getConfiguration(), resource, builderAssistant.getConfiguration().getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, builderAssistant.getConfiguration(), url, builderAssistant.getConfiguration().getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
// 如果指定了映射器接口,就将其添加到Configuration对象中
Class<?> mapperInterface = Resources.classForName(mapperClass);
builderAssistant.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
XMLConfigBuilder.parse方法的作用是解析MyBatis配置文件,该方法首先会创建一个新的Configuration对象,然后解析配置文件中的各个节点,并将解析结果设置到Configuration对象中。其中,configurationElement方法是解析配置文件的核心方法,它会依次解析properties、settings、typeAliases、plugins、objectFactory、objectWrapperFactory、reflectorFactory、environments、databaseIdProvider、typeHandlers和mappers节点。对于mappers节点,如果子节点是package,就会扫描指定包下的所有映射器;如果子节点是mapper,就会解析指定的映射器文件或映射器接口,并将其添加到Configuration对象中。在解析过程中,如果出现异常,就会抛出BuilderException异常。
核心方法是以下这一段:
// 解析properties节点
propertiesElement(context.evalNode("properties"));
// 解析settings节点
Properties settings = settingsAsProperties(context.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
// 解析typeAliases节点
typeAliasesElement(context.evalNode("typeAliases"));
// 解析plugins节点
pluginElement(context.evalNode("plugins"));
// 解析objectFactory节点
objectFactoryElement(context.evalNode("objectFactory"));
// 解析objectWrapperFactory节点
objectWrapperFactoryElement(context.evalNode("objectWrapperFactory"));
// 解析reflectorFactory节点
reflectorFactoryElement(context.evalNode("reflectorFactory"));
// 将settings节点中的属性设置到Configuration对象中
settingsElement(settings);
// 解析environments节点
environmentsElement(context.evalNode("environments"));
// 解析databaseIdProvider节点
databaseIdProviderElement(context.evalNode("databaseIdProvider"));
// 解析typeHandlers节点
typeHandlerElement(context.evalNode("typeHandlers"));
// 解析mappers节点
mapperElement(context.evalNode("mappers"));
接下来我们就一点点的看解析的步骤!
2、propertiesElement(context.evalNode("properties"))
先看这段:
// 解析properties节点 propertiesElement(context.evalNode("properties"));
MyBatis中XMLConfigBuilder类中的一个私有方法 propertiesElement ,用于解析配置文件中的properties节点。下面是对该方法的详细解释:
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
// 获取properties节点下的所有子节点
Properties defaults = context.getChildrenAsProperties();
// 获取properties节点的resource属性
String resource = context.getStringAttribute("resource");
// 获取properties节点的url属性
String url = context.getStringAttribute("url");
// 如果resource和url都为空,就直接使用defaults中的属性
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) {
// 从指定的resource中加载属性
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
// 从指定的url中加载属性
defaults.putAll(Resources.getUrlAsProperties(url));
}
// 将解析出来的属性设置到Configuration对象中
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
该方法首先判断properties节点是否存在,如果存在则获取其下的所有子节点,并将其转换为Properties对象。接着,该方法会获取properties节点的resource和url属性,如果两个属性都为空,则直接使用子节点中解析出来的属性。如果resource和url属性中有一个不为空,则从指定的资源(文件或URL)中加载属性,并将其合并到子节点中解析出来的属性中。最后,该方法将合并后的属性设置到Configuration对象中,以供后续的数据库操作使用。
举个例子,假设我们在MyBatis的配置文件中定义了一个properties节点,如下所示:
<properties resource="db.properties">
<property name="username" value="root" />
<property name="password" value="123456" />
</properties>
其中,resource属性指定了db.properties文件的路径,同时在properties节点下还定义了两个property子节点,分别表示数据库用户名和密码。在Java代码中,可以通过以下方式获取这些属性:
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);
Properties properties = sessionFactory.getConfiguration().getVariables();
String username = properties.getProperty("username");
String password = properties.getProperty("password");
propertiesElement 就是将配置文件转换成Properties对象,全局可以通过 properties.getProperty 方法获取属性。
3、loadCustomVfs(settings)
接下来我们看这段
loadCustomVfs(settings);
loadCustomVfs 是 MyBatis中XMLConfigBuilder类中的一个私有方法,用于加载自定义的虚拟文件系统(VFS)。下面是对该方法的详细解释:
private void loadCustomVfs(Properties props) throws ClassNotFoundException {
// 获取vfsImpl属性的值
String value = props.getProperty("vfsImpl");
if (value != null) {
// 将vfsImpl属性的值按照逗号分隔符拆分成多个类名
String[] clazzes = value.split(",");
for (String clazz : clazzes) {
if (!clazz.isEmpty()) {
// 加载指定的类
@SuppressWarnings("unchecked")
Class<? extends VFS> vfsImpl = (Class<? extends VFS>) Resources.classForName(clazz);
// 注册自定义的VFS实现类
configuration.setVfsImpl(vfsImpl);
}
}
}
}
该方法首先从配置文件中获取vfsImpl属性的值,该属性指定了自定义的VFS实现类。如果该属性存在,则将其按照逗号分隔符拆分成多个类名,并逐个加载指定的类。最后,该方法将自定义的VFS实现类注册到Configuration对象中,以供后续的数据库操作使用。
举个例子,假设我们需要使用自定义的VFS实现类来管理MyBatis的映射文件,我们可以在MyBatis的配置文件中添加如下配置:
<configuration>
<properties>
<property name="vfsImpl" value="com.example.MyVFS" />
</properties>
...
</configuration>
其中,vfsImpl属性指定了自定义的VFS实现类为com.example.MyVFS。在Java代码中,可以通过以下方式加载自定义的VFS实现类:
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);
VFS myVFS = new MyVFS();
configuration.setVfsImpl(myVFS);
以上代码中,我们通过SqlSessionFactoryBuilder创建了SqlSessionFactory对象,并创建了自定义的VFS实现类MyVFS。最后,我们通过setVfsImpl方法将自定义的VFS实现类注册到Configuration对象中。
4、loadCustomLogImpl(settings)
接下来我们看这段
loadCustomLogImpl(settings);
loadCustomLogImpl(settings)是MyBatis框架中XMLConfigBuilder类的一个私有方法,用于加载自定义的日志实现类。下面是对该方法的详细解释:
private void loadCustomLogImpl(Properties props) {
Class<? extends Log> clazz = resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(clazz);
}
该方法首先通过getProperty方法获取配置文件中名为logImpl的属性值,该属性值指定了自定义的日志实现类。接着,通过resolveClass方法将属性值转换为Class对象,最后将Class对象设置到Configuration对象中,以供后续的数据库操作使用。
举个例子,假设我们需要使用自定义的日志实现类来记录MyBatis的日志信息,我们可以在MyBatis的配置文件中添加如下配置:
<configuration>
<properties>
<property name="logImpl" value="com.example.MyLog" />
</properties>
...
</configuration>
其中,logImpl属性指定了自定义的日志实现类为com.example.MyLog。在Java代码中,可以通过以下方式加载自定义的日志实现类:
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);
Log myLog = new MyLog();
configuration.setLogImpl(myLog.getClass());
以上代码中,我们通过SqlSessionFactoryBuilder创建了SqlSessionFactory对象,并创建了自定义的日志实现类MyLog。最后,我们通过setLogImpl方法将自定义的日志实现类注册到Configuration对象中。
5、typeAliasesElement(context.evalNode("typeAliases"))
接下来我们看这段
typeAliasesElement(context.evalNode("typeAliases")
typeAliasesElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 typeAliases 元素。下面是该方法的源代码及其说明:
public Element typeAliasesElement(XNode parent) {
if (parent != null) {
// 获取typeAliases元素
for (XNode child : parent.getChildren()) {
if ("typeAliases".equals(child.getName())) {
return (Element) child.getNode();
}
}
}
return null;
}
该方法接收一个 XNode 类型的参数 parent ,表示要解析的MyBatis配置文件中的某个节点。该方法首先判断该节点是否为 typeAliases ,如果是,则返回该节点的 Element 对象,否则返回 null 。
下面是一个示例代码,它演示了如何使用 typeAliasesElement 方法来获取MyBatis配置文件中的 typeAliases 元素:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLConfigBuilder builder = new XMLConfigBuilder(inputStream);
Configuration configuration = builder.parse();
XNode typeAliasesNode = configuration.getTypeAliasesElement();
if (typeAliasesNode != null) {
Element typeAliasesElement = typeAliasesNode.evalNode("typeAliases");
// 处理typeAliasesElement
}
在这个示例代码中,我们首先创建一个 XMLConfigBuilder 对象,并使用它解析MyBatis配置文件。然后,我们获取配置文件中的 typeAliases 节点,并使用 typeAliasesElement 方法获取 typeAliases 元素。如果 typeAliases 元素存在,则可以对其进行进一步的处理。
6、pluginElement(context.evalNode("plugins"))
pluginElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 plugins 元素。下面是该方法的源代码及其说明:
public void pluginElement(XNode parent) throws Exception {
if (parent != null) {
// 获取plugins元素
for (XNode child : parent.getChildren()) {
// 获取plugin元素
if ("plugin".equals(child.getName())) {
// 获取plugin元素的属性
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
// 创建Interceptor实例并设置属性
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
// 添加到InterceptorChain中
configuration.addInterceptor(interceptorInstance);
}
}
}
}
该方法接收一个 XNode 类型的参数 parent ,表示要解析的MyBatis配置文件中的某个节点。该方法首先判断该节点是否为 plugins ,如果是,则遍历其所有子节点,查找名为 plugin 的子节点。对于每个 plugin 子节点,该方法获取其 interceptor 属性和所有子节点的属性,并创建对应的 Interceptor 实例,并将其添加到 InterceptorChain 中。
下面是一个示例代码,它演示了如何使用 pluginElement 方法来解析MyBatis配置文件中的 plugins 元素:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLConfigBuilder builder = new XMLConfigBuilder(inputStream);
Configuration configuration = builder.parse();
XNode pluginsNode = configuration.getPluginsElement();
if (pluginsNode != null) {
pluginElement(pluginsNode);
}
在这个示例代码中,我们首先创建一个 XMLConfigBuilder 对象,并使用它解析MyBatis配置文件。然后,我们获取配置文件中的 plugins 节点,并使用 pluginElement 方法解析其中的 plugin 元素。
7、 objectFactoryElement(context.evalNode("objectFactory"))
objectFactoryElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 objectFactory 元素。下面是该方法的源代码及其说明:
public void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
// 获取objectFactory元素的type属性和子元素
String type = context.getStringAttribute("type");
List<ConstructorArg> constructorArgs = parseConstructorArgElements(context.getChildren());
// 创建ObjectFactory实例并设置属性
ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
if (constructorArgs.size() > 0) {
// 通过构造方法创建实例
factory = (ObjectFactory) createInstanceByConstructor(factory, constructorArgs);
}
factory.setProperties(context.getChildrenAsProperties());
// 设置ObjectFactory
configuration.setObjectFactory(factory);
}
}
该方法接收一个 XNode 类型的参数 context ,表示要解析的MyBatis配置文件中的某个节点。该方法首先判断该节点是否为 objectFactory ,如果是,则获取其 type 属性和所有子元素,并根据 type 属性创建对应的 ObjectFactory 实例,并设置其属性。如果存在构造方法参数,则使用这些参数创建实例。最后,将创建的 ObjectFactory 实例设置到 Configuration 中。
8、objectWrapperFactoryElement(context.evalNode("objectWrapperFactory"))
objectWrapperFactoryElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 objectWrapperFactory 元素。下面是该方法的源代码及其说明:
public void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
// 获取objectWrapperFactory元素的type属性
String type = context.getStringAttribute("type");
// 创建ObjectWrapperFactory实例并设置属性
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
configuration.setObjectWrapperFactory(factory);
}
}
该方法接收一个 XNode 类型的参数 context ,表示要解析的MyBatis配置文件中的某个节点。该方法首先判断该节点是否为 objectWrapperFactory ,如果是,则获取其 type 属性,并根据 type 属性创建对应的 ObjectWrapperFactory 实例,并设置其属性。最后,将创建的 ObjectWrapperFactory 实例设置到 Configuration 中。
9、reflectorFactoryElement(context.evalNode("reflectorFactory"))
reflectorFactoryElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 reflectorFactory 元素。下面是该方法的源代码及其说明:
public void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
// 获取reflectorFactory元素的type属性
String type = context.getStringAttribute("type");
// 创建ReflectorFactory实例并设置属性
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
configuration.setReflectorFactory(factory);
}
}
该方法接收一个 XNode 类型的参数 context ,表示要解析的MyBatis配置文件中的某个节点。该方法首先判断该节点是否为 reflectorFactory ,如果是,则获取其 type 属性,并根据 type 属性创建对应的 ReflectorFactory 实例,并设置其属性。最后,将创建的 ReflectorFactory 实例设置到 Configuration 中。
10、settingsElement(settings)
settingsElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 settings 元素。下面是该方法的源代码及其说明:
public void settingsElement(Properties props) { // 将Properties对象中的所有属性设置到Configuration中 configuration.setVariables(props); // 设置cacheEnabled属性 if (props.containsKey("cacheEnabled")) { configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true)); } // 设置lazyLoadingEnabled属性 if (props.containsKey("lazyLoadingEnabled")) { configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false)); } // 设置aggressiveLazyLoading属性 if (props.containsKey("aggressiveLazyLoading")) { configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false)); } // 设置multipleResultSetsEnabled属性 if (props.containsKey("multipleResultSetsEnabled")) { configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true)); } // 设置useColumnLabel属性 if (props.containsKey("useColumnLabel")) { configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true)); } // 设置useGeneratedKeys属性 if (props.containsKey("useGeneratedKeys")) { configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false)); } // 设置autoMappingBehavior属性 if (props.containsKey("autoMappingBehavior")) { configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior"))); } // 设置defaultExecutorType属性 if (props.containsKey("defaultExecutorType")) { configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType"))); } // 设置defaultStatementTimeout属性 if (props.containsKey("defaultStatementTimeout")) { configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null)); } // 设置defaultFetchSize属性 if (props.containsKey("defaultFetchSize")) { configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null)); } // 设置safeRowBoundsEnabled属性 if (props.containsKey("safeRowBoundsEnabled")) { configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false)); } // 设置mapUnderscoreToCamelCase属性 if (props.containsKey("mapUnderscoreToCamelCase")) { configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false)); } // 设置localCacheScope属性 if (props.containsKey("localCacheScope")) { configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope"))); } // 设置jdbcTypeForNull属性 if (props.containsKey("jdbcTypeForNull")) { configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull"))); } // 设置lazyLoadTriggerMethods属性 if (props.containsKey("lazyLoadTriggerMethods")) { configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString")); } }
该方法接收一个 Properties 类型的参数 props ,表示要解析的MyBatis配置文件中的 settings 元素。该方法首先将 Properties 对象中的所有属性设置到 Configuration 中,然后根据属性名设置对应的属性值。
11、environmentsElement(context.evalNode("environments"))
environmentsElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 environments 元素。下面是该方法的源代码及其说明:
public void environmentsElement(XNode context) throws Exception {
if (context != null) {
// 如果environment属性没有设置,就使用default属性指定的环境
if (environment == null) {
environment = context.getStringAttribute("default");
}
// 遍历所有的environment子元素,找到指定的环境
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
// 解析transactionManager和dataSource元素,并设置到Configuration对象中
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());
}
}
}
}
该方法接收一个 XNode 类型的参数 context ,表示要解析的MyBatis配置文件中的 environments 元素。该方法首先检查 environment 属性是否设置,如果没有设置,则使用 default 属性指定的环境。然后,遍历所有的 environment 子元素,找到指定的环境,并解析其中的 transactionManager 和 dataSource 元素,并将它们设置到 Configuration 对象中。
12、 databaseIdProviderElement(context.evalNode("databaseIdProvider"))
databaseIdProviderElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 databaseIdProvider 元素。下面是该方法的源代码及其说明:
private void databaseIdProviderElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
Properties properties = context.getChildrenAsProperties();
DatabaseIdProvider databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
databaseIdProvider.setProperties(properties);
// 获取所有已经加载的DataSourceFactory
Set<String> dataSourceIds = new HashSet<>();
for (String name : configuration.getDataSourceNames()) {
dataSourceIds.add(name);
DataSource dataSource = getDataSourceFromEnvironment(name);
MetaObject metaDataSource = configuration.newMetaObject(dataSource);
// 获取databaseId
String databaseId = databaseIdProvider.getDatabaseId(dataSource);
// 设置databaseId
metaDataSource.setValue("databaseId", databaseId);
}
// 处理未加载的DataSourceFactory
for (String id : configuration.getConfigurationProperties().<String>getSet(DataSourceFactory.DataSourceFactoryProperty.DATA_SOURCE_FACTORY)) {
if (!dataSourceIds.contains(id)) {
DataSourceFactory factory = resolveDataSourceFactory(id);
DataSource dataSource = factory.getDataSource();
MetaObject metaDataSource = configuration.newMetaObject(dataSource);
String databaseId = databaseIdProvider.getDatabaseId(dataSource);
metaDataSource.setValue("databaseId", databaseId);
}
}
}
}
该方法接收一个 XNode 类型的参数 context ,表示要解析的MyBatis配置文件中的 databaseIdProvider 元素。该方法首先获取 type 属性的值,然后使用反射机制创建对应的 DatabaseIdProvider 对象,并将 context 中的子元素转换为 Properties 对象,最后将这些属性设置到 DatabaseIdProvider 对象中。接着,该方法获取所有已经加载的 DataSourceFactory ,遍历它们并获取 databaseId ,并将其设置到对应的 DataSource 对象中。最后,该方法处理未加载的 DataSourceFactory ,并为它们设置 databaseId
13、 typeHandlerElement(context.evalNode("typeHandlers"))
typeHandlerElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 typeHandlers 元素。下面是该方法的源代码及其说明:
private void typeHandlerElement(XNode parent) { 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) { if (jdbcType == null) { typeHandlerRegistry.register(javaTypeClass, typeHandlerClass); } else { typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass); } } else { typeHandlerRegistry.register(typeHandlerClass); } } } } }
该方法接收一个 XNode 类型的参数 parent ,表示要解析的MyBatis配置文件中的 typeHandlers 元素。该方法首先遍历 parent 的所有子元素,如果子元素的名称为 package ,则获取 name 属性的值,并将其注册到 typeHandlerRegistry 中。如果子元素的名称不为 package ,则获取 javaType 、 jdbcType 和 handler 属性的值,并使用反射机制创建对应的 TypeHandler 对象,并将其注册到 typeHandlerRegistry 中。
下面是一个示例代码,它演示了如何使用 typeHandlerElement 方法来解析MyBatis配置文件中的 typeHandlers 元素:14、mapperElement(context.evalNode("mappers"))
mapperElement 方法是MyBatis中的一个工具方法,用于解析MyBatis配置文件中的 mappers 元素。下面是该方法的源代码及其说明:
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
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());
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.");
}
}
}
}
}
该方法接收一个 XNode 类型的参数 parent ,表示要解析的MyBatis配置文件中的 mappers 元素。该方法首先遍历 parent 的所有子元素,如果子元素的名称为 package ,则获取 name 属性的值,并将其添加到 Configuration 对象中的MapperRegistry中。如果子元素的名称不为 package ,则获取 resource 、 url 和 class 属性的值,并根据不同情况进行解析和处理。
💕💕 本文由激流丶创作,原创不易,感谢支持!
💕💕喜欢的话记得点赞收藏啊!