| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
Nel92X
9年前发布

mybatis 源码分析之 BaseBuilder

来自: http://renchx.com/mybatis2

解析 typeAliases

在 XMLConfigBuilder 当中的 parseConfiguration 方法当中 typeAliasesElement(root.evalNode("typeAliases")); 来解析 typeAliases,下面是详细代码:

private void typeAliasesElement(XNode parent) {      if (parent != null) {        for (XNode child : parent.getChildren()) {          if ("package".equals(child.getName())) {            String typeAliasPackage = child.getStringAttribute("name");            configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);          } else {            String alias = child.getStringAttribute("alias");            String type = child.getStringAttribute("type");            try {              Class<?> clazz = Resources.classForName(type);              if (alias == null) {                typeAliasRegistry.registerAlias(clazz);              } else {                typeAliasRegistry.registerAlias(alias, clazz);              }            } catch (ClassNotFoundException e) {              throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);            }          }        }      }    }

对应的 xml 格式如下:

<typeAliases>          <package name="com.rcx.test"/>          <typeAlias type="com.rcx.User" alias="User"/>          <typeAlias type="com.rcx.Book" />  </typeAliases>

当是 package 的时候把这个包下面的所有类都扫描出来当成别名。下面的两种方式是指定具体的 class,区别就是指定了别名,和没指定别名,没指定别名的时候使用 class.getSimpleName(); 来当作别名。

下面看一下 TypeAliasRegistry 的内部数据结构:

public class TypeAliasRegistry {      private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();      public TypeAliasRegistry() {      registerAlias("string", String.class);      ...省略了内置的基本类似别名      registerAlias("iterator", Iterator.class);      }    }

结构很简单,里面就是一个 HashMap 然后对这个 map 进行各种操作。

BaseBuilder

上面提到的 XMLConfigBuilder 继承于 BaseBuilder,而且其他所有解析 XML 的 Builder 都会继承这个抽象类。

看下 BaseBuilder 当中的结构:

public abstract class BaseBuilder {    protected final Configuration configuration;    protected final TypeAliasRegistry typeAliasRegistry;    protected final TypeHandlerRegistry typeHandlerRegistry;      public BaseBuilder(Configuration configuration) {      this.configuration = configuration;      this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();      this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();    }      ...其他方法先省略  }

当创建 BaseBuilder 子类实例的时候,需要传入 Configuration 的实例,入口的解析器 Builder 就是 XMLConfigBuilder,看下它的构造方法:

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

因为在 SqlSessionFactoryBuilder 类当中 build 生成 SqlSessionFactory 的时候是调用了 XMLConfigBuilder 的 parse 方法生成 Configuration 实例,代码如下:

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {          //省略了 try 和 catch        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);        return build(parser.parse());    }      public SqlSessionFactory build(Configuration config) {      return new DefaultSqlSessionFactory(config);    }

所以初始化 Configuration 实例的流程就清晰了:

  1. 先创建 XMLConfigBuilder 实例,然后创建了 Configuration 实例
  2. 在 XMLConfigBuilder 当中把 Configuration 的每一个节点都解析然后设置进去
  3. 最后返回 Configuration 实例,完成初始化工作

当然 BaseBuilder 当中还包含了解析 Builder 的一些通用的工具方法,下面简单列几个:

  protected Pattern parseExpression(String regex, String defaultValue) {      return Pattern.compile(regex == null ? defaultValue : regex);    }      protected Boolean booleanValueOf(String value, Boolean defaultValue) {      return value == null ? defaultValue : Boolean.valueOf(value);    }      protected Integer integerValueOf(String value, Integer defaultValue) {      return value == null ? defaultValue : Integer.valueOf(value);    }

XMLConfigBuilder 的具体工作

要想了解 XMLConfigBuilder 的具体工作就要看它的 parseConfiguration 方法:

private void parseConfiguration(XNode root) {      try {        //issue #117 read properties first        propertiesElement(root.evalNode("properties"));//解析内置的属性        typeAliasesElement(root.evalNode("typeAliases"));//解析别名        pluginElement(root.evalNode("plugins"));//解析插件        objectFactoryElement(root.evalNode("objectFactory"));//解析对象工厂        objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));        reflectionFactoryElement(root.evalNode("reflectionFactory"));        settingsElement(root.evalNode("settings"));//解析默认设置        // read it after objectFactory and objectWrapperFactory issue #631        environmentsElement(root.evalNode("environments"));//解析环境        databaseIdProviderElement(root.evalNode("databaseIdProvider"));        typeHandlerElement(root.evalNode("typeHandlers"));//解析类型处理器        mapperElement(root.evalNode("mappers"));//解析用户定义的 mappers      } catch (Exception e) {        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);      }    }

从上面可以看出来,主要是对 config.xml 进行解析,刚才分析了别名的解析比较简单,比较复杂的是 mappers 的解析。

下面挑一些进行简单分析 解析插件

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

对应的 xml 如下:

<plugins>          <plugin interceptor="com.rcx.TestInterceptor">              <property name="" value=""/>              <property name="" value=""/>          </plugin>  </plugins>

不需要过多的解释,主要看 configuration.addInterceptor(interceptorInstance); 在 configuration 当中的数据结构。

protected final InterceptorChain interceptorChain = new InterceptorChain();    public void addInterceptor(Interceptor interceptor) {      interceptorChain.addInterceptor(interceptor);    }    public class InterceptorChain {      private final List<Interceptor> interceptors = new ArrayList<Interceptor>();      public Object pluginAll(Object target) {      for (Interceptor interceptor : interceptors) {        target = interceptor.plugin(target);      }      return target;    }      public void addInterceptor(Interceptor interceptor) {      interceptors.add(interceptor);    }      public List<Interceptor> getInterceptors() {      return Collections.unmodifiableList(interceptors);    }    }

数据结构也很明了,在 List 当中按顺序存放所有的插件。

* 解析 typeHandler *

private void typeHandlerElement(XNode parent) throws Exception {      if (parent != null) {        for (XNode child : parent.getChildren()) {          if ("package".equals(child.getName())) {            String typeHandlerPackage = child.getStringAttribute("name");            typeHandlerRegistry.register(typeHandlerPackage);          } else {            String javaTypeName = child.getStringAttribute("javaType");            String jdbcTypeName = child.getStringAttribute("jdbcType");            String handlerTypeName = child.getStringAttribute("handler");            Class<?> javaTypeClass = resolveClass(javaTypeName);            JdbcType jdbcType = resolveJdbcType(jdbcTypeName);            Class<?> typeHandlerClass = resolveClass(handlerTypeName);            if (javaTypeClass != null) {              if (jdbcType == null) {                typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);              } else {                typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);              }            } else {              typeHandlerRegistry.register(typeHandlerClass);            }          }        }      }    }

对应的 XML 如下:

<typeHandlers>          <package name="com.rcx.test"/>          <typeHandler handler="" javaType="" jdbcType=""/>  </typeHandlers>

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

package 是在这个包下的都扫描成 typeHandler,typeHandler 标签的具体分析,下面看 typeHandlerRegistry 的数据结构:

// 在 Configuration 当中的属性  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();    public final class TypeHandlerRegistry {      private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);    private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();    private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);    private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();      public TypeHandlerRegistry() {      register(Boolean.class, new BooleanTypeHandler());      ...//省略      register(char.class, new CharacterTypeHandler());    }    }

JDBC_TYPE_HANDLER_MAP 这个 map 存放的是 JDBC 类型的 TypeHandler 在 TypeHandlerRegistry 构造方法里面已经进行了初始化:

public TypeHandlerRegistry() {      register(JdbcType.BOOLEAN, new BooleanTypeHandler());      register(JdbcType.BIT, new BooleanTypeHandler());      。。。省略  }

之所以创建的是 EnumMap 是因为数据库类型一定小于 64 种,使用 EnumMap 会更快、也节省空间。

TYPE_HANDLER_MAP 最个 map 是存放我们自定义的类型的转换的 map,我们自定义的 TypeHandler 都要继承于 BaseTypeHandler 这个类,BaseTypeHandler 继承于 TypeReference,继承于 TypeReference 的主要作用就是可通过反射拿到具体的 TypeHandler 的泛型 class。

public abstract class TypeReference<T> {      private final Type rawType;      protected TypeReference() {      rawType = getSuperclassTypeParameter(getClass());    }      Type getSuperclassTypeParameter(Class<?> clazz) {      Type genericSuperclass = clazz.getGenericSuperclass();      if (genericSuperclass instanceof Class) {        // try to climb up the hierarchy until meet something useful        if (TypeReference.class != genericSuperclass) {          return getSuperclassTypeParameter(clazz.getSuperclass());        }          throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "          + "Remove the extension or add a type parameter to it.");      }        Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];      // TODO remove this when Reflector is fixed to return Types      if (rawType instanceof ParameterizedType) {        rawType = ((ParameterizedType) rawType).getRawType();      }        return rawType;    }      public final Type getRawType() {      return rawType;    }      @Override    public String toString() {      return rawType.toString();    }    }

所以 TYPE_HANDLER_MAP 的 key 是 Type 类型,但是他的 value 是一个 Map<JdbcType, TypeHandler<?>> map,看起来很奇怪但是仔细想想很合理,有多个 jdbc 类型可以转换成相同的 java 类型,那么有可能就需要不同的 TypeHandler。

ALL_TYPE_HANDLERS_MAP 就是存放所有的 typeHandler

TypeHandlerRegistry 类当中的重载的 register 就不仔细分析了。

---EOF---

 本文由用户 Nel92X 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1456359172698.html
MyBatis 源码分析 MyBatis3 持久层框架