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中去。
0 0
原创粉丝点击