myBatis源码之XMLConfigBuilder

来源:互联网 发布:数据恢复软件的应用 编辑:程序博客网 时间:2024/05/21 18:36

XMLConfigBuilder是对mybatis的配置文件进行解析的类,会对myabtis解析后的信息存放在Configuration对象中,Configuration对象会贯穿整个mybatis的执行流程,为mybatis的执行过程提供各种需要的配置信息。


/** * @author Clinton Begin */public class XMLConfigBuilder extends BaseBuilder {  private boolean parsed;  private XPathParser parser;  private String environment;  public XMLConfigBuilder(Reader reader) {    this(reader, null, null);  }  public XMLConfigBuilder(Reader reader, String environment) {    this(reader, environment, null);  }  public XMLConfigBuilder(Reader reader, String environment, Properties props) {    this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);  }  public XMLConfigBuilder(InputStream inputStream) {    this(inputStream, null, null);  }  public XMLConfigBuilder(InputStream inputStream, String environment) {    this(inputStream, environment, null);  }  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);  }  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {    super(new Configuration());    ErrorContext.instance().resource("SQL Mapper Configuration");    this.configuration.setVariables(props);    this.parsed = false;    this.environment = environment;    this.parser = parser;  }  public Configuration parse() {    if (parsed) {      throw new BuilderException("Each XMLConfigBuilder can only be used once.");    }    parsed = true;//mybatis的配置文件的根节点是configuration,从根节点开始解析配置文件    parseConfiguration(parser.evalNode("/configuration"));    return configuration;  }  private void parseConfiguration(XNode root) {    try {  //解析子节点properties      propertiesElement(root.evalNode("properties")); //issue #117 read properties first  //解析子节点typeAliases 别名      typeAliasesElement(root.evalNode("typeAliases"));  //解析子节点plugins 插件      pluginElement(root.evalNode("plugins"));  //解析子节点objectFactory mybatis为结果创建对象时都会用到objectFactory      objectFactoryElement(root.evalNode("objectFactory"));  //解析子节点objectWrapperFactory      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));  //解析settings定义一些全局性的配置      settingsElement(root.evalNode("settings"));  //解析environments 可以配置多个运行环境,但是每个SqlSessionFactory 实例只能选择一个运行环境      environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631  //解析databaseIdProvider MyBatis能够执行不同的语句取决于你提供的数据库供应商。许多数据库供应商的支持是基于databaseId映射      databaseIdProviderElement(root.evalNode("databaseIdProvider"));  //解析typeHandlers 当MyBatis设置参数到PreparedStatement 或者从ResultSet 结果集中取得值时,就会使用TypeHandler  来处理数据库类型与java 类型之间转换      typeHandlerElement(root.evalNode("typeHandlers"));  //解析mappers 主要的crud操作都是在mappers中定义的      mapperElement(root.evalNode("mappers"));    } catch (Exception e) {      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);    }  }  //类别名解析  private void typeAliasesElement(XNode parent) {    if (parent != null) {      for (XNode child : parent.getChildren()) {//如果子节点是package,那么就获取package节点的name属性        if ("package".equals(child.getName())) {          String typeAliasPackage = child.getStringAttribute("name");          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);        } else {//如果子节点是typeAlias节点,那么就获取alias属性和type的属性          String alias = child.getStringAttribute("alias");          String type = child.getStringAttribute("type");          try {//通过type的值来加载获得类            Class<?> clazz = Resources.classForName(type);            if (alias == null) {//typeAliasRegistry会进行别名注册              typeAliasRegistry.registerAlias(clazz);            } else {              typeAliasRegistry.registerAlias(alias, clazz);            }          } catch (ClassNotFoundException e) {            throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);          }        }      }    }  }  //插件元素解析  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 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);    }  }  //配置元素解析  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);      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.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) {        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());        }      }    }  }  //解析databaseIdProvider MyBatis能够执行不同的语句取决于你提供的数据库供应商。许多数据库供应商的支持是基于databaseId映射  private void databaseIdProviderElement(XNode context) throws Exception {    DatabaseIdProvider databaseIdProvider = null;    if (context != null) {      String type = context.getStringAttribute("type");      if ("VENDOR".equals(type)) type = "DB_VENDOR"; // awful patch to keep backward compatibility      Properties properties = context.getChildrenAsProperties();      databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();      databaseIdProvider.setProperties(properties);    }    Environment environment = configuration.getEnvironment();    if (environment != null && databaseIdProvider != null) {      String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());      configuration.setDatabaseId(databaseId);    }  }  //事务配置解析,获得事务工厂(JDBC和MANAGED两种)  private TransactionFactory transactionManagerElement(XNode context) throws Exception {    if (context != null) {      String type = context.getStringAttribute("type");      Properties props = context.getChildrenAsProperties();      TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();      factory.setProperties(props);      return factory;    }    throw new BuilderException("Environment declaration requires a TransactionFactory.");  }  //数据源解析获得数据源工厂  private DataSourceFactory dataSourceElement(XNode context) throws Exception {    if (context != null) {      String type = context.getStringAttribute("type");      Properties props = context.getChildrenAsProperties();      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();      factory.setProperties(props);      return factory;    }    throw new BuilderException("Environment declaration requires a DataSourceFactory.");  }  //类型控制元素解析,数据库数据类型和Java数据类型的解析  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) {            if (jdbcType == null) {              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);            } else {              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);            }          } else {            typeHandlerRegistry.register(typeHandlerClass);          }        }      }    }  }  //mapper元素解析,获得各种crud操作或者配置文件  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.");          }        }      }    }  }  private boolean isSpecifiedEnvironment(String id) {    if (environment == null) {      throw new BuilderException("No environment specified.");    } else if (id == null) {      throw new BuilderException("Environment requires an id attribute.");    } else if (environment.equals(id)) {      return true;    }    return false;  }}



0 0
原创粉丝点击