免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
mybatis源碼分析-配置文件解析過程

mybatis源碼分析-環(huán)境搭建 一文中,我們的測試代碼如下:

public static void main(String[] args) throws IOException {     String resource = "mybatis-config.xml";      InputStream inputStream = Resources.getResourceAsStream(resource);      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);      SqlSession sqlSession = sqlSessionFactory.openSession();      try {          DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);          List<Dept> deptList = deptMapper.getAllDept();          System.out.println(deptList);      } finally {          sqlSession.close();      }   }  

mybatis源碼分析-SqlSessionFactory構(gòu)建過程 一文中探究了 SqlSessionFactory 對象的生成方式,但是那里還有兩行代碼沒有仔細研究,因為這兩行代碼涉及的東西有些多,這篇文章主要研究這兩行代碼背后的細節(jié)。代碼再貼一遍:

  XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);    return build(parser.parse());  

XMLConfigBuilder做了什么

需要研究的第一行代碼只是生成了一個 XMLConfigBuilder 對象而已。

public XMLConfigBuilder(InputStream inputStream) {      this((InputStream)inputStream, (String)null, (Properties)null);  }

繼續(xù)看構(gòu)造重載函數(shù):

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

這里繼續(xù)調(diào)用了另一個構(gòu)造函數(shù),只是入?yún)⒆優(yōu)?XPathParser對象。

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {      super(new Configuration());      this.localReflectorFactory = new DefaultReflectorFactory();      ErrorContext.instance().resource("SQL Mapper Configuration");      this.configuration.setVariables(props);      this.parsed = false;      this.environment = environment;      this.parser = parser;  }

這個構(gòu)造函數(shù)主要是賦值功能,給 XMLConfigBuilder 對象的屬性賦值。注意 XMLConfigBuilder extends BaseBuilder ,而 BaseBuilder 含有 Configuration 屬性 , 因此 XMLConfigBuilder 需要給一個默認的 Configuration 值,就是下面這行代碼的功能:

super(new Configuration());  

看上面的流程,似乎也不復(fù)雜,這里漏了一點 XPathParser 的創(chuàng)建,只有創(chuàng)建好了 XPathParser 才能進行文件解析,然后生成對應(yīng)的 Configuration 對象。

XPathParser 使用了 xPath 解析技術(shù)。

xml解析的技術(shù)有很多,以前用過 dom4j,當(dāng)使用dom4j查詢比較深的層次結(jié)構(gòu)的節(jié)點(標(biāo)簽,屬性,文本)時比較麻煩!使用xPath主要是用于快速獲取所需的節(jié)點對象。

本文不打算講解如何把 inputStream 轉(zhuǎn)為 XPathParser 對象,有興趣可以自學(xué)一下。

上面講解的代碼主要掌握創(chuàng)建 XMLConfigBuilder 對象時有一個特別重要的屬性 XPathParser ,這個屬性可以快速獲取 xml 的各種元素,方便后續(xù)操作。

parser.parse() 方法做了什么?

根據(jù)上下文,這里的 parser 就是 XMLConfigBuilder,我們來看下 parse() 方法做了什么:

public Configuration parse() {      if (this.parsed) {          throw new BuilderException("Each XMLConfigBuilder can only be used once.");      } else {          this.parsed = true;          this.parseConfiguration(this.parser.evalNode("/configuration"));          return this.configuration;      }  }

注意這段代碼的核心是:

this.parseConfiguration(this.parser.evalNode("/configuration"));  

注意this.parser 指的是 XMLConfigBuilder 里的 XPathParser 對象。evalNode 方法獲取全局配置文件里面 Configuration 下面的所有內(nèi)容?,F(xiàn)在想想全局配置文件的結(jié)構(gòu)吧。

再看下 parseConfiguration 方法:

private void parseConfiguration(XNode root) {    try {      propertiesElement(root.evalNode("properties"));      Properties settings = settingsAsProperties(root.evalNode("settings"));      loadCustomVfs(settings);      loadCustomLogImpl(settings);      typeAliasesElement(root.evalNode("typeAliases"));      pluginElement(root.evalNode("plugins"));      objectFactoryElement(root.evalNode("objectFactory"));      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));      reflectorFactoryElement(root.evalNode("reflectorFactory"));      settingsElement(settings);      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);    }  }

全局配置文件里面的每一個屬性,都有對應(yīng)的方法進行解析。解析成一個一個對象賦值給最大的那個 Configuration 對象,到此就完事了。

解析插件代碼

上面的解析配置文件的方法很多,本文不會把所有的解析代碼都一一探究,就使用插件解析代碼進行舉例說明吧。也就是下面這行代碼:

    pluginElement(root.evalNode("plugins"));  

在研究源碼之前,我們先了解下插件機制,下面的內(nèi)容都是從官網(wǎng)復(fù)制的:


MyBatis 允許你在已映射語句執(zhí)行過程中的某一點進行攔截調(diào)用。默認情況下,MyBatis 允許使用插件來攔截的方法調(diào)用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

這些類中方法的細節(jié)可以通過查看每個方法的簽名來發(fā)現(xiàn),或者直接查看 MyBatis 發(fā)行包中的源代碼。 如果你想做的不僅僅是監(jiān)控方法的調(diào)用,那么你最好相當(dāng)了解要重寫的方法的行為。 因為如果在試圖修改或重寫已有方法的行為的時候,你很可能在破壞 MyBatis 的核心模塊。 這些都是更低層的類和方法,所以使用插件的時候要特別當(dāng)心。

通過 MyBatis 提供的強大機制,使用插件是非常簡單的,只需實現(xiàn) Interceptor 接口,并指定想要攔截的方法簽名即可。

// ExamplePlugin.java  @Intercepts({@Signature(          type= Executor.class,          method = "update",          args = {MappedStatement.class,Object.class})})  public class ExamplePlugin implements Interceptor {      private Properties properties = new Properties();      public Object intercept(Invocation invocation) throws Throwable {          // implement pre processing if need          Object returnObject = invocation.proceed();          // implement post processing if need          return returnObject;      }      public void setProperties(Properties properties) {          this.properties = properties;      }  }

下面是如何配置:

<!-- mybatis-config.xml -->  <plugins>      <plugin interceptor="org.mybatis.example.ExamplePlugin">          <property name="someProperty" value="100"/>      </plugin>  </plugins>

現(xiàn)在我們想如何把上面配置文件的代碼解析出來,源碼如下:

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).getDeclaredConstructor().newInstance();              interceptorInstance.setProperties(properties);              configuration.addInterceptor(interceptorInstance);          }      }  }

由于 plugin 可以有多個,因此代碼循環(huán)解析,對于每一個 plugin,首先拿到屬性 interceptor,也就是自定義插件的實現(xiàn)類,如上面官網(wǎng)的例子 ExamplePlugin ,通過反射生成對象實例,該對象有個屬性 Properties,也就是 mybatis-config.xml 中的

 <property name="someProperty" value="100"/>  

內(nèi)容,只不過被

child.getChildrenAsProperties()

進行解析成鍵值對形式的 Properties 對象,代碼如下

public Properties getChildrenAsProperties() {      Properties properties = new Properties();      Iterator var2 = this.getChildren().iterator();        while(var2.hasNext()) {          XNode child = (XNode)var2.next();          String name = child.getStringAttribute("name");          String value = child.getStringAttribute("value");          if (name != null && value != null) {              properties.setProperty(name, value);          }      }        return properties;  }

這段代碼比較簡單,循環(huán)取 name 和 value 的值給 Properties 對象而已。

對于mybatis-config.xml其它配置,也是通過類似的方式解析成相關(guān)對象,最終都賦值給 Configuration對象而已。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Mybatis深入之初始化過程
Mybatis源碼分析(四):屬性接口之configLocation
Mybatis源碼詳解
mybatis源碼分析(1)
設(shè)計模式系列 | 建造者模式
深入淺出MyBatis
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服