mybatis源码DEBUG学习2
来源:互联网 发布:java版qq 编辑:程序博客网 时间:2024/05/16 14:55
上一篇我们简单了解了mybatis是如何解析这个xml文件的,今天我们就来详细的看一下几个重要的地方,mybatis是如何一步步的解析这几个重要的xml配置文件信息的。
首先还是看到代码,具体的解析xml的代码是XMLConfigBuilder的parseConfiguration方法。在这以前我们先看到XMLConfigBuilder的父类BaseBuilder,在XMLConfigBuilder解析xml的时候,有很多解析的参数都存在父类的字段configuration中。
protected final Configuration configuration;
这个Configuration类中有各种各样的字段,存储着解析xml的结果。
然后我们再回到XMLConfigBuilder的parseConfiguration方法,废话不多说,先上代码。
private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
第一行
propertiesElement(root.evalNode("properties"));
就是加载properties标签内的内容,这个标签内的一般是外部配置文件,使用外部配置文件可以动态配置相关属性,debug进去这个方法,看下到底是如何做的,
private void propertiesElement(XNode context) throws Exception { if (context != null) { 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) { defaults.putAll(Resources.getResourceAsProperties(resource)); } else if (url != null) { defaults.putAll(Resources.getUrlAsProperties(url)); } Properties vars = configuration.getVariables(); if (vars != null) { defaults.putAll(vars); } parser.setVariables(defaults); configuration.setVariables(defaults); }}
可以看到首先会获取这个外部配置文件信息,然后把这个配置文件加载进来,最后把这个Properties set到XPathParser中的filed variables中和其父类BaseBuilder的field configuration的field variables中。其中如何使用这个加载进来的xml文件在这个地方还没体现,相信在后面加载数据源相关信息的时候是肯定会用到的。
第二行
Properties settings = settingsAsProperties(root.evalNode("settings"));
参照mybatis官方文档,setting是MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为,具体的在setting中可以配置哪些内容可以参照官方文档。这一步主要是获得一个setting的Properties对象,debug进settingsAsProperties方法。
private Properties settingsAsProperties(XNode context) { if (context == null) { return new Properties(); } 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)."); } } return props; }
首先加载这个标签内的内容,然后检查setting内标签的内容是否是合法的,最后返回一个Properties对象,这个对象在其他地方还要用到。
第四行,加载别名,
typeAliasesElement(root.evalNode("typeAliases"));
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 { typeAliasRegistry.registerAlias(alias, clazz); } } catch (ClassNotFoundException e) { throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e); } } } } }
首先会获得标签内的内容,然后根据反射生成一个Entity对象,然后把这个对象放到父类BaseBuilder的filed typeAliasRegistry中存着,最终typeAliasRegistry会使用一个叫TYPE_ALIASES的hashmap储存这个对象和key。
public void registerAlias(String alias, Class<?> value) { if (alias == null) { throw new TypeException("The parameter alias cannot be null"); } // issue #748 String key = alias.toLowerCase(Locale.ENGLISH); if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) { throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'."); } TYPE_ALIASES.put(key, value);}
第十行,加载environments
参照mybatis官方文档,environments可以配置多个数据源,但是每个SqlSessionFactory实例只能选择一个数据源,也就是说如果你要使用多个数据源,那么你要创建多个SqlSessionFactory。指定使用哪个environment创造SqlSessionFactory的相关代码如下:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
或
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment,properties);
如果你忽略环境参数,那么就会加载默认的环境参数
- 默认的环境ID(比如:default=”development”)。
- 每个 environment 元素定义的环境 ID(比如:id=”development”)。
- 事务管理器的配置(比如:type=”JDBC”)。
- 数据源的配置(比如:type=”POOLED”)。 这里我们在来看一下mybatis是如何加载environments的。
private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { 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()); } } } }
首先遍历所有的environment,然后构建一个事物的工厂类和数据源的工厂类,再生成一个Environment的内部类Builder的对象environmentBuilder,最后把这个对象set到BaseBuilder的filed configuration中去。
- mybatis源码DEBUG学习2
- mybatis源码DEBUG学习
- Mybatis源码学习
- MyBatis开始学习源码
- mybatis源码学习
- mybatis学习(1)---导入mybatis源码
- myBatis源码学习之SqlSessionFactoryBuilder
- myBatis源码学习之SqlSessionFactory
- myBatis源码学习之SqlSession
- Mybatis源码学习之TypeHandler
- 学习mybatis源码疑惑一
- Mybatis源码学习(一)-整体框架理解
- MyBatis Migrations 源码篇 学习笔记
- Mybatis源码学习(一)包结构
- Mybatis源码学习(二)annotation包
- Mybatis源码学习(三)cache包
- Mybatis-generator源码学习和修改
- mybatis源码学习之基础工程准备
- 关于Servlet的两种映射方法
- Intellij IDEA实用技巧
- SpringBoot项目实战--RabbitMQ
- Robot Framework之---iframe无id时的定位方法
- Java中Unsafe类详解
- mybatis源码DEBUG学习2
- jsonp原理详解——终于搞清楚jsonp是啥了
- VR 圈里经常被提起的概念
- 我的第一篇博客
- java 场景总结(一)
- gem5学习7——gem5仿真器启动过程
- ionic ActionSheet(上拉菜单)
- Python每日一练----2.基本数学函数
- android个人笔记之greendao初体验