深入浅出Mybatis系列(六)---objectFactory、plugins、mappers简介与配置

上篇文章《深入浅出 Mybatis 系列(五)---TypeHandler 简介及配置(mybatis 源码篇)》简单看了一下 TypeHandler, 本次将结束对于 mybatis 的配置文件的学习, 本次涉及到剩下没提及到的几个节点的配置:objectFactory、databaseIdProvider、plugins、mappers。

那么,接下来,就简单介绍一下这几个配置的作用吧:

1、objectFactory 是干什么的? 需要配置吗?

  MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。默认情况下,我们不需要配置,mybatis 会调用默认实现的 objectFactory。 除非我们要自定义 ObjectFactory 的实现, 那么我们才需要去手动配置。

  那么怎么自定义实现 ObjectFactory? 怎么配置呢?

  自定义 ObjectFactory 只需要去继承 DefaultObjectFactory(是 ObjectFactory 接口的实现类),并重写其方法即可。具体的,本处不多说,后面再具体讲解。

  写好了 ObjectFactory, 仅需做如下配置: 

<configuration>
    ......
    <objectFactory type="org.mybatis.example.ExampleObjectFactory">
        <property name="someProperty" value="100"/>
    </objectFactory>
    ......
  </configuration

 

2、plugin 有何作用? 需要配置吗?

  plugins 是一个可选配置。mybatis 中的 plugin 其实就是个 interceptor, 它可以拦截 Executor 、ParameterHandler 、ResultSetHandler 、StatementHandler 的部分方法,处理我们自己的逻辑。Executor 就是真正执行 sql 语句的东西, ParameterHandler 是处理我们传入参数的,还记得前面讲 TypeHandler 的时候提到过,mybatis 默认帮我们实现了不少的 typeHandler, 当我们不显示配置 typeHandler 的时候,mybatis 会根据参数类型自动选择合适的 typeHandler 执行,其实就是 ParameterHandler 在选择。ResultSetHandler 就是处理返回结果的。

   怎么自定义 plugin ? 怎么配置?

   要自定义一个 plugin, 需要去实现 Interceptor 接口, 这儿不细说, 后面实战部分会详细讲解。定义好之后,配置如下:

<configuration>
    ......
    <plugins>
      <plugin interceptor="org.mybatis.example.ExamplePlugin">
        <property name="someProperty" value="100"/>
      </plugin>
    </plugins>
    ......
  </configuration>

 

3、mappers, 这下引出 mybatis 的核心之一了,mappers 作用 ? 需要配置吗?

  mappers 节点下,配置我们的 mapper 映射文件, 所谓的 mapper 映射文件,就是让 mybatis 用来建立数据表和 javabean 映射的一个桥梁。在我们实际开发中,通常一个 mapper 文件对应一个 dao 接口, 这个 mapper 可以看做是 dao 的实现。所以,mappers 必须配置。

  那么怎么配置呢?

<configuration>
    ......
    <mappers>
      <!-- 第一种方式:通过 resource 指定 -->
    <mapper resource="com/dy/dao/userDao.xml"/>
 <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 第二种方式, 通过class指定接口,进而将接口与对应的xml文件形成映射关系
         不过,使用这种方式必须保证 接口与mapper文件同名(不区分大小写), 
         我这儿接口是UserDao,那么意味着mapper文件为UserDao.xml 
 &lt;mapper class="com.dy.dao.UserDao"/&gt;
  </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
  
  <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 第三种方式,直接指定包,自动扫描,与方法二同理 
  &lt;package name="com.dy.dao"/&gt;
  </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
  <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 第四种方式:通过url指定mapper文件位置
  &lt;mapper url="file://........"/&gt;
   </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>

</mappers>
......
</configuration>

 

本篇仅作简单介绍, 更高级的使用以及其实现原理,会在后面的实战部分进行详细讲解。

这几个节点的解析源码,与之前提到的那些节点的解析类似,故此处不再讲。 我将源码折叠, 需要的可以打开看看。

/**
 * objectFactory 节点解析
 */
private void objectFactoryElement(XNode context) throws Exception {
    if (context != null) {
      //读取 type 属性的值, 接下来进行实例化 ObjectFactory, 并 set 进 configuration
      //到此,简单讲一下 configuration 这个对象,其实它里面主要保存的都是 mybatis 的配置
      String type = context.getStringAttribute("type");
      //读取 propertie 的值, 根据需要可以配置, mybatis 默认实现的 objectFactory 没有使用 properties
      Properties properties = context.getChildrenAsProperties();
  ObjectFactory factory </span>=<span style="color: rgba(0, 0, 0, 1)"> (ObjectFactory) resolveClass(type).newInstance();
  factory.setProperties(properties);
  configuration.setObjectFactory(factory);
}

}

/**

  • plugins 节点解析
    */
    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 的时候,需要去实现 Interceptor, 这儿先不具体讲,以后会详细讲解
    Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
    interceptorInstance.setProperties(properties);
    configuration.addInterceptor(interceptorInstance);
    }
    }
    }

/**

  • mappers 节点解析

  • 这是 mybatis 的核心之一,这儿先简单介绍,在接下来的文章会对它进行分析
    */
    private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
    for (XNode child : parent.getChildren()) {
    if ("package".equals(child.getName())) {
    //如果 mappers 节点的子节点是 package, 那么就扫描 package 下的文件, 注入进 configuration
    String mapperPackage = child.getStringAttribute("name");
    configuration.addMappers(mapperPackage);
    }
    else {
    String resource
    = child.getStringAttribute("resource");
    String url
    = child.getStringAttribute("url");
    String mapperClass
    = child.getStringAttribute("class");
    //resource, url, class 三选一

     <span style="color: rgba(0, 0, 255, 1)">if</span> (resource != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; url == <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; mapperClass == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
       ErrorContext.instance().resource(resource);
       InputStream inputStream </span>=<span style="color: rgba(0, 0, 0, 1)"> Resources.getResourceAsStream(resource);
       </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">mapper映射文件都是通过XMLMapperBuilder解析</span>
       XMLMapperBuilder mapperParser = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
       mapperParser.parse();
     } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (resource == <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; url != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; mapperClass == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
       ErrorContext.instance().resource(url);
       InputStream inputStream </span>=<span style="color: rgba(0, 0, 0, 1)"> Resources.getUrlAsStream(url);
       XMLMapperBuilder mapperParser </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
       mapperParser.parse();
     } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (resource == <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; url == <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; mapperClass != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
       Class</span>&lt;?&gt; mapperInterface =<span style="color: rgba(0, 0, 0, 1)"> Resources.classForName(mapperClass);
       configuration.addMapper(mapperInterface);
     } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
       </span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> BuilderException("A mapper element may only specify a url, resource or class, but not more than one."<span style="color: rgba(0, 0, 0, 1)">);
     }
    

    }
    }
    }
    }

View Code

 

本次就简单的到此结束, 从下篇文章开始,将会开始接触到 mybatis 的核心部分,不过首先还是要讲 mapper 文件的配置及使用, 并通过源码进一步深入核心。