转载

mybatis 源码分析之 BaseBuilder

解析 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---

原文  http://renchx.com/mybatis2
正文到此结束
Loading...