In layman's language Mybatis series (four) --- Detailed configuration of properties and environments

Let me give you a simple example about the use of the properties.

< Configuration > 
<-! Method a: Specifies properties profile from the outside, except to specify resource attribute, but also by the url attribute url  
  <properties resource="dbConfig.properties"></properties> 
  -->
  <!-- 方法二: 直接配置为xml -->
  <properties>
      <property name="driver" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/test1"/>
      <property name="username" value="root"/>
      <property name="password" value="root"/>
  </properties>

Properties can also be passed to the sqlSessionFactoryBuilder.build (method). E.g:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
// ... 或者 ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);

If the property has been configured in more than one place, then MyBatis will be loaded in the following order:

  • In vivo properties specified properties element are read first.
  • Then reads the property file according to the attribute file attribute properties resource elements to read the class path or paths specified by the url attribute, and covering the same name attribute is read.
  • Finally, a method to read the property passed as parameters, and covering the same name attribute is read.

Look again at the use of envirements element node it:

< Environments default = "Development" > 
    < Environment ID = "Development" > 
      < the transactionManager type = "the JDBC" /> 
      < the dataSource type = "the POOLED" > 
         <-! Specified above database configuration file, the configuration file which is corresponding to these four attributes -> 
         < property name = "Driver" value = "$ {Driver}" /> 
         < property name = "URL" value = "$ {} URL" /> 
         <property name="username" value="${username}"/>
         <property name="password" value="${password}"/>
      </dataSource>
    </environment>  
    <!-- 我再指定一个environment -->
    <environment id="test">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <!- nameProperty<->and not the same as the above url
        ="url" value="jdbc:mysql://localhost:3306/demo"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  • Each corresponds to a database instance SqlSessionFactory

To specify which environment to create, as long as it will be passed as an optional parameter to SqlSessionFactoryBuilder. Can accept two ways to configure the environment signature is:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

If you ignore environmental parameters, then the default environment will be loaded as follows:

  • ID use the default environment (such as: default = "development").
  • Each environment defined environment ID (such as: id = "development").
  • Transaction manager configuration (for example: type = "JDBC").
  • Configuration data source (for example: type = "POOLED").

Transaction Manager (transactionManager)

There are two types of transaction manager with MyBatis (ie type = "[JDBC | MANAGED]"):

  • JDBC - This configuration is the direct use of JDBC commit and rollback is provided, which depends on the connection data obtained from the source to manage transactions scope.
  • MANAGED - This configuration almost did not do. It never commit or roll back a connection, but let the container to manage the entire life cycle of a transaction (such as context JEE application server). By default, it will close the connection, however, some containers do not want this, so you need to closeConnection property to false to prevent its default behavior is closed.

There are three built-in data source types (type = "[UNPOOLED | POOLED
| JNDI]"): to achieve this UNPOOLED- but each data source to open and close the connection when requested. Although a bit slow, but for simple applications in the database connection is not too high availability requirements, it is a good choice.
POOLED- implemented using this data source concept of "cell" will be organized JDBC connection objects, the authentication initialization and avoids creating a new connection time necessary for instance. This is a popular Web application that concurrent processing request responsive manner.
JNDI - this is to realize the data source, such as can be used in such an application server or EJB container, which may be centralized or configuration data in an external source, and then placing a reference JNDI context.

 

The last time we said mybatis by XMLConfigBuilder in this class parses mybatis configuration file, then this would then look for properties and environments XMLConfigBuilder resolve of:

public  class XMLConfigBuilder extends BaseBuilder {

    private boolean parsed;
    //xml解析器
    private XPathParser parser;
    private String environment;
  
    // element node is the last time when it comes to this method can be configured in the configuration file parsing mybatis
     // today is the first look at properties and environments node node 
    Private  void parseConfiguration (XNode root) {
         the try {
           // analytic properties of elements 
          propertiesElement ( root.evalNode ( "Properties")); // Issue # 117 Read Properties First 
          typeAliasesElement (root.evalNode ( "typeAliases" ));
          pluginElement(root.evalNode("plugins"));
          objectFactoryElement(root.evalNode("objectFactory"));
          objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
          settingsElement(root.evalNode("settings"));
          //解析environments元素
          environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
          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);
        }
    }
  
    
    // The following analytical properties look at a specific method 
    Private  void propertiesElement (XNode context) throws Exception {
         IF (context! = Null ) {
           // child node name and the attribute value set into the object properties
           // here can take note of the order , XML configuration priority, followed by the external configuration specified properties 
          the properties Defaults = context.getChildrenAsProperties ();
           // get the value of the properties node resource attribute 
          String = context.getStringAttribute resource ( "resource" );
           // Get the node url attribute properties value, resource can not be configured and url 
          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.");
          }
          // to set properties file parsed into objects Properties 
          IF (Resource! = Null ) {
            defaults.putAll(Resources.getResourceAsProperties(resource));
          } else if (url != null) {
            defaults.putAll(Resources.getUrlAsProperties(url));
          }
          // The configuration object configured Properties property with just analytical integration
           // configuration object will load all the elements mybatis node configuration files parsed, will also frequently mentioned object
           // Since configuration objects with a series of get / set methods that we can use if you mark the java code directly configured? 
          // The answer is yes, but using the configuration file to configure, the advantage goes without saying that 
          the Properties VARS = configuration.getVariables ();
           IF (! VARS = null ) {
            defaults.putAll(vars);
          }
          // the target set with a resolution configuration propertis into the parser, since the latter might use 
          parser.setVariables (Defaults);
           // set into the configuration objects 
          configuration.setVariables (defaults);
        }
    }
    
    // Next, consider analytically enviroments element node 
    Private  void environmentsElement (XNode context) throws Exception {
         IF (context! = Null ) {
             IF (Environment == null ) {
                 // value resolution default attribute environments node
                 // For example: <Environments default = "Development"> 
                Environment context.getStringAttribute = ( "default" );
            }
            // recursive resolution sub-node environments 
            for (XNode Child: context.getChildren ()) {
                 // <Environment id = "Development">, only enviroment node has an id attribute, then what is the role of this property?
                // Environments node under the environment can have multiple child nodes
                 @ like this: <environments default = "development" > <environment id = "development"> ... </ environment> <environment id = "test">. .. </ environments>
                 // means that we can correspond to a plurality of environments, such as development, test environment, the default attribute environments to select the corresponding Enviroment 
                String ID = child.getStringAttribute ( "ID" );
                
                // transaction, there are two MyBatis: JDBC and MANAGED configured directly using JDBC JDBC transaction, transaction hosted configured MANAGED sucked to the container, 
                    the TransactionFactory txFactory = transactionManagerElement (child.evalNode ( "the transactionManager" ));
                     / / Enviroment dataSource node is below a node, the node dataSource analytical (analytical method below will specifically dataSource, posting) 
                    DataSourceFactory dsFactory = dataSourceElement (child.evalNode ( "dataSource" ));
                    DataSource dataSource = dsFactory.getDataSource();
                    Environment.Builder environmentBuilder = new Environment.Builder(id)
                          .transactionFactory(txFactory)
                          .dataSource(dataSource);
                    // old rules, will be provided into the dataSource configuration objects 
                    configuration.setEnvironment (environmentBuilder.build ());
                }
            }
        }
    }
    
    // The following analytical methods dataSource See 
    Private DataSourceFactory dataSourceElement (XNode context) throws Exception {
         IF (context =! Null ) {
             // dataSource connection pool 
            String = context.getStringAttribute type ( "type" );
             // child node name , value property set properties into a target 
            the properties props = context.getChildrenAsProperties ();
             // create DataSourceFactory 
            DataSourceFactory Factory's = (DataSourceFactory) resolveClass (of the type). NewInstance ();
            factory.setProperties(props);
            return factory;
        }
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
    } 
}
View Code

  By the above interpretation of mybatis source code, I believe we configure mybatis, there has been an in-depth understanding.

  There is also a problem, we have seen above, use the $ {driver} This expression is how to resolve this form at the time of dataSource configuration? In fact, this class is resolved by PropertyParser:

/**
 * $ {} Class analytical expression of this form of
 */
public class PropertyParser {

  public static String parse(String string, Properties variables) {
    VariableTokenHandler handler = new VariableTokenHandler(variables);
    GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
    return parser.parse(string);
  }

  private static class VariableTokenHandler implements TokenHandler {
    private Properties variables;

    public VariableTokenHandler(Properties variables) {
      this.variables = variables;
    }

    public String handleToken(String content) {
      if (variables != null && variables.containsKey(content)) {
        return variables.getProperty(content);
      }
      return "${" + content + "}";
    }
  }
}

 

Guess you like

Origin www.cnblogs.com/deityjian/p/11080483.html