一:Mybatis初始化

在使用mybatis的時候咱們通常設置xml,而後利用beanfactory建立bean進行加載,那麼裏面詳細過程如何:mysql

1、初始化配置:spring

    在org.apache.ibatis.session這個包下面有一個Configuration類,這個是mybatis的配置類sql

    他的配置數據庫

    Configuration配置apache

        properties:屬性session

        settings:設置mybatis

        typeAliases:別名app

        typeHandlers:類型處理器dom

        objectFactory:對象工廠ide

        pulgins:插件

        environments:環境

            environment:環境變量

            transactionManager:事務管理器

            dataSource:數據源

mybatis能夠依賴於spring生成SqlSessionFactory也能夠依賴mybatis自身的SqlSessionFactoryBuilder()去獲取SqlSessionFactory我項目中採用的是spring集成mybatis,下面就簡單的記錄如下spring如何從加載到進行查詢結束。

這是我spring的配置:

<bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="maxActive" value="30" />
        <property name="initialSize" value="2" />
        <property name="maxWait" value="30000" />
        <property name="maxIdle" value="30" />
        <property name="minIdle" value="1" />
        <property name="testOnBorrow" value="false"></property>
        <property name="testWhileIdle" value="true"></property>
        <property name="validationQuery" value="select 1"></property>
        <property name="timeBetweenEvictionRunsMillis"><value>30000</value></property>  
        <property name="numTestsPerEvictionRun"><value>10</value></property>
        <property name="minEvictableIdleTimeMillis" value="30000"></property>
    </bean>
    <bean id="dataSource" parent="parentDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="${cms.url}" />
        <property name="username" value="${cms.username}" />
        <property name="password" value="${cms.password}" />
    </bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">     
        <property name="configLocation" value="classpath:mybatis_configuration.xml" />     
        <property name="dataSource" ref="dataSource" />     
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

下面是mybatis的設置:
<configuration>

    <!-- 別名 -->
    <typeAliases>
        <typeAlias type="cn.cover.server.domain.Advert" alias="Advert" />
        <typeAlias type="cn.cover.server.domain.AppVersion" alias="AppVersion" />
        <typeAlias type="cn.cover.server.domain.Live" alias="Live" />
        <typeAlias type="cn.cover.server.domain.DailyDate" alias="DailyDate" />
    </typeAliases>

    <mappers>
        <mapper resource="sqlmap/Advert.xml" />
        <mapper resource="sqlmap/AppVersion.xml" />
        <mapper resource="sqlmap/Live.xml" />
        <mapper resource="sqlmap/Daily.xml" />
    </mappers>
</configuration>

配置採用到注入到SqlSessionFactoryBean中,SqlSessionFactoryBean

在看一下SqlSessionFactoryBean裏面的buildSqlSessionFactory()方法,其中...表示當前方法不執行

 protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

    Configuration configuration; //Configuration對象

    //用來解析xml

    XMLConfigBuilder xmlConfigBuilder = null;

    //我配置的config不爲空,因此用這個
    if (this.configLocation != null) {

        //經過location獲取input流解析xml文件
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);

    //經過xml文件生成對應的configuration對象
      configuration = xmlConfigBuilder.getConfiguration();
    } else {
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
      }
      configuration = new Configuration();
      configuration.setVariables(this.configurationProperties);
    }

    .....

    if (xmlConfigBuilder != null) {//上面配置xmlConfigBuilder不未空
      try {

    //針對mybatis配置,獲取/configuration節點下面的數據
        xmlConfigBuilder.parse();

        if (this.logger.isDebugEnabled()) {
          this.logger.debug("Parsed configuration file: '" + this.configLocation + "'");
        }
      } catch (Exception ex) {
        throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
      } finally {
        ErrorContext.instance().reset();
      }
    }

    //針對事務的處理,若是當前事務工廠沒有就new SpringManagedTransactionFactory

    if (this.transactionFactory == null) {
      this.transactionFactory = new SpringManagedTransactionFactory();
    }

    //而後設置configuration對象中的environment

    Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
    configuration.setEnvironment(environment);

    if (this.databaseIdProvider != null) {
     ..
    }

    if (!isEmpty(this.mapperLocations)) {//針對mapper文件進行解析xml文件
      ...
    }

    return this.sqlSessionFactoryBuilder.build(configuration);
  }

下面咱們分別看一下每一個方法的執行

xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);

會調用org.apache.ibatis.builder.xml包下面的XMLConfigBuilder類下面方法

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }

關於XPathParser方法就不惜看了,看一下this的,this調用下面方法

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {

/***

**調用父類的構造方法,傳入參數調用new的Configuration對象

** 在Configuration對象中new的時候會在構造方法中 

**typeAliasRegistry.registerAlias("xxxx", xxxx.class);註冊不少默認的別名

**/

    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }設置變量

 

而後是執行configuration = xmlConfigBuilder.getConfiguration();

XMLConfigBuilder類沒有實現這個方法,會調用父類的getConfiguration()方法,獲取剛纔設置的configuration對象

而後在去執行

 xmlConfigBuilder.parse();

能夠看一下里面的具體實現

public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;

    //獲取/configuration節點下面的數據
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

下面看一下 parseConfiguration(parser.evalNode("/configuration"));

他的傳入參數是一個XNode對,XNode封裝了節點的一些列屬性

private void parseConfiguration(XNode root) {
    try {

    //獲取properties文件進行設置數據庫的配置,該處沒有用,由於採用了spring配置
      propertiesElement(root.evalNode("properties")); //issue #117 read properties first

    //讀取mybatis_config.xml裏面的<typeAliases>標籤下面的數據
      typeAliasesElement(root.evalNode("typeAliases"));

     //讀取mybatis_config.xml裏面的<plugins>標籤下面的數據
      pluginElement(root.evalNode("plugins"));

     //讀取mybatis_config.xml裏面的<objectFactory>標籤下面的數據
      objectFactoryElement(root.evalNode("objectFactory"));

     //讀取mybatis_config.xml裏面的<objectWrapperFactory>標籤下面的數據
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));

    //讀取mybatis_config.xml裏面的<settings>標籤下面的數據
      settingsElement(root.evalNode("settings"));

    //讀取mybatis_config.xml裏面的<environments>標籤下面的數據
   environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));

  //讀取mybatis_config.xml裏面的<mappers>標籤下面的數據
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

由於mybatis把sql寫在了xml文件裏面,主要看一下 mapperElement(root.evalNode("mappers"));

下面是這個方法的實現,經過獲取xml裏面的resource標籤或者url,class標籤進行設置

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {//若是mappers下面的字標籤名字爲package採用這種,每用過
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {//我採用的是resource配置,能夠看出來能夠獲取resource這個屬性的值
          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();
          }}...
    }
  }

看一下XMLMapperBuilder

public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
        configuration, resource, sqlFragments);
  }

改方法會調用這個方法

private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    super(configuration);
    this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
    this.parser = parser;
    this.sqlFragments = sqlFragments;
    this.resource = resource;
  }相似於XMLBuilder裏面的配置

在看一下 mapperParser.parse();這個方法

public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      bindMapperForNamespace();
    }

    parsePendingResultMaps();
    parsePendingChacheRefs();
    parsePendingStatements();
  }

能夠看出來就是去獲取mapper節點數據下面的數據,看一下

private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace.equals("")) {
          throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      sqlElement(context.evalNodes("/mapper/sql"));
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }

更直觀,分別獲取mapper節點下面的parameterMap,resultMap,sql還有select等其餘操做

mybatis在初始化的時候在解析sql的時候會把全部sql解析成MappedStatement對象,存儲在內存中,具體存在Configuration 對象的mappedStatements中,key是在mybatis_config.xml裏面設置的別名+id

總之mybatis在初始化的時候不管採用mybatis的配置仍是使用spring計策或嗯mybatis都是把全部配置信息初始化到內存中,包括事務配置,sql配置,存儲在configuration對象中

相關文章
相關標籤/搜索