Mybatis系列三:类型别名、类型解析器的注册

TypeAlias可以帮助我们在Mybatis配置文件中直接引用类别名,而不必使用类完全限定名那么冗长的名字。TypeAliasRegistry、Configuration实例化时会注册默认的类别名,方便我们使用。类别名忽略大小写,在注册类别名或根据类别名或去类时,Mybatis会将别名转换成小写。

TypeHandlerRegistry帮助我们将Java类型和数据库类型进行转换。一个Java类型可以对应多个数据库类型。

 

一、TypeAliasRegistry

注册类别名或根据别名获取类都会将别名转成小写,TypeAliasRegistry实例化时会注册常用类别名。

 

1.1 扫描指定包下类注册别名

public void registerAliases(String packageName){

   registerAliases(packageName, Object.class);

 }

 

 public void registerAliases(String packageName, Class<?> superType){

   // 获取指定包下执行类型的所有类

   ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();

   resolverUtil.find(new ResolverUtil.IsA(superType), packageName);

   Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();

   for(Class<?> type : typeSet){

     // 忽略内部类、接口、抽象类(包括package-info.java)

     if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {

       registerAlias(type);

     }

   }

 }

 

1.2 注册类别名

public void registerAlias(Class<?> type) {

   // 获取类名

   String alias = type.getSimpleName();

   // 获取类上的@Alias注解

   Alias aliasAnnotation = type.getAnnotation(Alias.class);

   if (aliasAnnotation != null) {

     alias = aliasAnnotation.value();

   }

   registerAlias(alias, type);

 }

 

1.3 保存别名(转成小写)和类映射关系

// value若为NULL,后续相同别名的会被覆盖。如果没有获取时返回NULL,需要注意处理。

public void registerAlias(String alias, Class<?> value) {

   if (alias == null) {

     throw new TypeException("The parameter alias cannot be null");

   }

   // 别名转成小写

   String key = alias.toLowerCase(Locale.ENGLISH);

   if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {

     throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");

   }

   TYPE_ALIASES.put(key, value);

 }

 

1.4 根据别名(转成小写)获取类

public <T> Class<T> resolveAlias(String string) {

   try {

     if (string == null) {

       return null;

     }

     // 别名转成小写

     String key = string.toLowerCase(Locale.ENGLISH);

     Class<T> value;

     if (TYPE_ALIASES.containsKey(key)) {

       value = (Class<T>) TYPE_ALIASES.get(key);

     } else {

       value = (Class<T>) Resources.classForName(string);

     }

     return value;

   } catch (ClassNotFoundException e) {

     throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);

   }

 }

二、TypeHandlerRegistry

2.1 根据JavaType(如果存在)获取typeHandler实例 getInstance

public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {

   if (javaTypeClass != null) {

     try {

  // 需要Java类型参数

       Constructor<?> c = typeHandlerClass.getConstructor(Class.class);

       return (TypeHandler<T>) c.newInstance(javaTypeClass);

     } catch (NoSuchMethodException ignored) {

       // ignored

     } catch (Exception e) {

       throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);

     }

   }

   try {

     Constructor<?> c = typeHandlerClass.getConstructor();

     return (TypeHandler<T>) c.newInstance();

   } catch (Exception e) {

     throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);

   }

 }

 

2.2 根据typeHandlerClass注册类型处理器

// 获取typeHandler Class上的@MappedTypes(Java类型)

public void register(Class<?> typeHandlerClass) {

   boolean mappedTypeFound = false;

   // 获取typeHandler Class上的@MappedTypes(Java类型)

   MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);

   if (mappedTypes != null) {

     for (Class<?> javaTypeClass : mappedTypes.value()) {

  // 传送门:5.3

       register(javaTypeClass, typeHandlerClass);

       mappedTypeFound = true;

     }

   }

 

   // 没有@MappedType即没有指定Java类型

   if (!mappedTypeFound) {

     // 传送门:5.4

     register(getInstance(null, typeHandlerClass));

   }

 }

 

2.3 根据Java类型、typeHandlerClass注册类型处理器

public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {

   // 传送门:5.5

   register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));

 }

 

2.4 根据typeHandler实例注册类型处理器

public <T> void register(TypeHandler<T> typeHandler) {

   boolean mappedTypeFound = false;

   // 获取typeHandler 实例上的@MappedTypes(Java类型)

   MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class);

   if (mappedTypes != null) {

     for (Class<?> handledType : mappedTypes.value()) {

  // 传送门:5.5

       register(handledType, typeHandler);

       mappedTypeFound = true;

     }

   }

   // @since 3.1.0 - try to auto-discover the mapped type

   if (!mappedTypeFound && typeHandler instanceof TypeReference) {

     try {

       TypeReference<T> typeReference = (TypeReference<T>) typeHandler;

       register(typeReference.getRawType(), typeHandler);

       mappedTypeFound = true;

     } catch (Throwable t) {

       // maybe users define the TypeReference with a different type and are not assignable, so just ignore it

     }

   }

   if (!mappedTypeFound) {

     // 传送门:5.5

     register((Class<T>) null, typeHandler);

   }

 

2.5 根据Java类型、typeHandler实例注册类型处理器

private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {

   // 获取typeHandler 实例上的@MappedJdbcTypes(JDBC类型)

   MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);

   if (mappedJdbcTypes != null) {

     for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {

  // 传送门:5.6

       register(javaType, handledJdbcType, typeHandler);

     }

     if (mappedJdbcTypes.includeNullJdbcType()) {

  // 传送门:5.6

       register(javaType, null, typeHandler);

     }

   } else {

// 传送门:5.6

     register(javaType, null, typeHandler);

   }

 }

 

2.6 根据Java类型、JDBC类型、typeHandler实例注册类型处理器

// 注册TypeHandler Class --> TypeHandler 实例映射关系,如果JavaType不为空,注册JavaType --> Map<JdbcType, TypeHandler实例> 映射关系

private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {

   if (javaType != null) {

     Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);

     if (map == null || map == NULL_TYPE_HANDLER_MAP) {

       map = new HashMap<JdbcType, TypeHandler<?>>();

  // 一个Java类型可能对应多个TypeHandler

       TYPE_HANDLER_MAP.put(javaType, map);

     }

     map.put(jdbcType, handler);

   }

   

   // TypeHandler Class --> TypeHandler 实例

   ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);

 }

 

2.7 扫描指定包注册TypeHandler

 public void register(String packageName) {

   // 扫描指定包下实现TypeHandler接口的类

   ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();

   resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);

   Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();

   for (Class<?> type : handlerSet) {

     // 忽略内部类和接口(包括package-info.java)和抽象类

     if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {

  // 传送门:5.2

       register(type);

     }

   }

 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: typeAliasesElement 在 MyBatis 中用于定义类型别名。在解析过程中,MyBatis 首先会将其中的类型别名注册到它的类型别名注册器中。然后,在执行 SQL 语句时,MyBatis 就可以使用这些类型别名来解析映射关系。 具体来说,当 MyBatis 在解析 typeAliasesElement 时,会执行以下步骤: 1. 遍历所有的类型别名元素。 2. 对于每个类型别名元素,获取其中的类型别名和类名。 3. 将类型别名与类名注册类型别名注册器中。 4. 重复步骤 1-3,直到遍历完所有的类型别名元素。 在解析过程中,MyBatis 会使用类加载器加载类型别名所对应的类。这样,在执行 SQL 语句时,MyBatis 就可以使用这些类来解析映射关系。 ### 回答2: mybatis的typeAliasesElement是一个XML元素,用于定义类型别名。它的解析过程如下: 1. 在mybatis的配置文件中,我们可以使用typeAliasesElement来定义类型别名。它是在<configuration>标签内部使用的。 2. 当mybatis解析配置文件时,会解析typeAliasesElement元素。 3. 解析过程中,首先会获取typeAliasesElement元素的属性值,如alias和type。 4. 如果type属性有值,表示我们要为某个类定义一个别名mybatis会通过反射机制获取到该类的全限定名,并将别名和类的全限定名进行映射。 5. 如果alias属性有值,表示我们要为一个包路径定义别名mybatis会扫描该包下的所有类,并将类名和别名进行映射。 6. 解析完成后,mybatis会将这些别名和类的映射关系存储起来,供后续使用。 总的来说,mybatis的typeAliasesElement解析过程就是将类或包路径与别名进行映射,以方便在mapper文件中使用别名来代替具体的类名。这样可以简化mapper文件的编写,提高开发效率。同时也使得mapper文件的可读性更强,更易于维护。 ### 回答3: mybatis中的typeAliasesElement是用来解析类型别名的元素。在mybatis的配置文件中可以使用typeAliasesElement来定义类型别名,它的作用是为了在使用mapper文件中的resultType、parameterType和typeHandler等地方时可以直接使用类型别名代替具体的类名。 解析typeAliasesElement的过程如下: 1. 首先,解析器会读取mybatis的配置文件中的typeAliasesElement元素。 2. 然后,解析器会获取typeAliasesElement元素中的所有子元素。 3. 解析器会遍历所有子元素,并将每个子元素的name和type属性值分别获取到。 4. 接下来,解析器会将name和type属性值进行解析和处理。 5. 对于name属性值,解析器会将其作为类型别名来处理。 6. 对于type属性值,解析器会使用反射的方式获取该属性值对应的类型,并将其作为name属性值对应的类型。 7. 最后,解析器会将得到的name和type属性值建立映射关系,并存储到mybatis类型别名注册表中。 通过上述解析过程,我们可以在mapper文件中直接使用类型别名来指定resultType、parameterType和typeHandler等属性值,而无需使用具体的类名。这样可以简化配置,提高代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值