• 深入浅出Mybatis系列(八)---objectFactory、plugins、mappers


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

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

    // ExampleObjectFactory.java
    public class ExampleObjectFactory extends DefaultObjectFactory {
      public Object create(Class type) {
        return super.create(type);
      }
      public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
        return super.create(type, constructorArgTypes, constructorArgs);
      }
      public void setProperties(Properties properties) {
        super.setProperties(properties);
      }
      public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
      }}

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

    <!-- mybatis-config.xml -->
    <objectFactory type="org.mybatis.example.ExampleObjectFactory">
      <property name="someProperty" value="100"/>
    </objectFactory>

    ObjectFactory 接口很简单,它包含两个创建用的方法,一个是处理默认构造方法的,另外一个是处理带参数的构造方法的。 最后,setProperties 方法可以被用来配置 ObjectFactory,在初始化你的 ObjectFactory 实例后, objectFactory 元素体中定义的属性会被传递给 setProperties 方法。

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

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

    通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

    // ExamplePlugin.java
    @Intercepts({@Signature(
      type= Executor.class,
      method = "update",
      args = {MappedStatement.class,Object.class})})
    public class ExamplePlugin implements Interceptor {
      public Object intercept(Invocation invocation) throws Throwable {
        return invocation.proceed();
      }
      public Object plugin(Object target) {
        return Plugin.wrap(target, this);
      }
      public void setProperties(Properties properties) {
      }
    }

     要自定义一个plugin, 需要去实现Interceptor接口,定义好之后,配置如下:

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

    3、mappers, 这下引出mybatis的核心之一了

    既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。 但是首先我们需要告诉 MyBatis 到哪里去找到这些语句。 Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。例如:

    <!-- 使用相对于类路径的资源引用 -->
    <mappers>
      <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    </mappers>
    <!-- 使用完全限定资源定位符(URL) -->
    <mappers>
      <mapper url="file:///var/mappers/AuthorMapper.xml"/>
      <mapper url="file:///var/mappers/BlogMapper.xml"/>
      <mapper url="file:///var/mappers/PostMapper.xml"/>
    </mappers>
    <!-- 使用映射器接口实现类的完全限定类名 -->
    <mappers>
      <mapper class="org.mybatis.builder.AuthorMapper"/>
      <mapper class="org.mybatis.builder.BlogMapper"/>
      <mapper class="org.mybatis.builder.PostMapper"/>
    </mappers>
    <!-- 将包内的映射器接口实现全部注册为映射器 -->
    <mappers>
      <package name="org.mybatis.builder"/>
    </mappers>

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

    /**
     * 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 = (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 三选一
              
              if (resource != null && url == null && mapperClass == null) {
                ErrorContext.instance().resource(resource);
                InputStream inputStream = Resources.getResourceAsStream(resource);
                //mapper映射文件都是通过XMLMapperBuilder解析
                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.");
              }
            }
          }
        }
      }
    View Code
  • 相关阅读:
    洛谷 P1316丢瓶盖
    喵哈哈村的魔法考试 (1)
    英语 词根 词缀 查询网址
    洛谷 保龄球
    find函数
    图书管理员
    最大公约数和最小公倍数问题
    openjudge 错误探测
    函数 记忆化搜索模型
    JSon_零基础_002_将List类型数组转换为JSon格式的对象字符串,返回给界面
  • 原文地址:https://www.cnblogs.com/deityjian/p/11081935.html
Copyright © 2020-2023  润新知