Mybatis源码解析-TypeAliasRegistry

311 阅读3分钟
package org.apache.ibatis.type;
​
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.Resources;
​
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.util.*;
​
/**
 * @author Clinton Begin
 */
public class TypeAliasRegistry {
​
    private final Map<String, Class<?>> typeAliases = new HashMap<>();
​
    public TypeAliasRegistry() {
        registerAlias("string", String.class);
​
        registerAlias("byte", Byte.class);
        registerAlias("long", Long.class);
        registerAlias("short", Short.class);
        registerAlias("int", Integer.class);
        registerAlias("integer", Integer.class);
        registerAlias("double", Double.class);
        registerAlias("float", Float.class);
        registerAlias("boolean", Boolean.class);
​
        registerAlias("byte[]", Byte[].class);
        registerAlias("long[]", Long[].class);
        registerAlias("short[]", Short[].class);
        registerAlias("int[]", Integer[].class);
        registerAlias("integer[]", Integer[].class);
        registerAlias("double[]", Double[].class);
        registerAlias("float[]", Float[].class);
        registerAlias("boolean[]", Boolean[].class);
​
        registerAlias("_byte", byte.class);
        registerAlias("_long", long.class);
        registerAlias("_short", short.class);
        registerAlias("_int", int.class);
        registerAlias("_integer", int.class);
        registerAlias("_double", double.class);
        registerAlias("_float", float.class);
        registerAlias("_boolean", boolean.class);
​
        registerAlias("_byte[]", byte[].class);
        registerAlias("_long[]", long[].class);
        registerAlias("_short[]", short[].class);
        registerAlias("_int[]", int[].class);
        registerAlias("_integer[]", int[].class);
        registerAlias("_double[]", double[].class);
        registerAlias("_float[]", float[].class);
        registerAlias("_boolean[]", boolean[].class);
​
        registerAlias("date", Date.class);
        registerAlias("decimal", BigDecimal.class);
        registerAlias("bigdecimal", BigDecimal.class);
        registerAlias("biginteger", BigInteger.class);
        registerAlias("object", Object.class);
​
        registerAlias("date[]", Date[].class);
        registerAlias("decimal[]", BigDecimal[].class);
        registerAlias("bigdecimal[]", BigDecimal[].class);
        registerAlias("biginteger[]", BigInteger[].class);
        registerAlias("object[]", Object[].class);
​
        registerAlias("map", Map.class);
        registerAlias("hashmap", HashMap.class);
        registerAlias("list", List.class);
        registerAlias("arraylist", ArrayList.class);
        registerAlias("collection", Collection.class);
        registerAlias("iterator", Iterator.class);
​
        registerAlias("ResultSet", ResultSet.class);
    }
​
    @SuppressWarnings("unchecked")
    // throws class cast exception as well if types cannot be assigned
    public <T> Class<T> resolveAlias(String string) {
        try {
            if (string == null) {
                return null;
            }
            // issue #748
            String key = string.toLowerCase(Locale.ENGLISH);
            Class<T> value;
            if (typeAliases.containsKey(key)) {
                value = (Class<T>) typeAliases.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);
        }
    }
​
    /**
     * 根据包名注册别名
     *
     * @param packageName 包名
     */
    public void registerAliases(String packageName) {
        registerAliases(packageName, Object.class);
    }
​
    /**
     * 包名注册别名
     *
     * @param packageName 包名
     * @param superType   类型
     */
    public void registerAliases(String packageName, Class<?> superType) {
        // 解析工具类
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
        // 加载 其实上面传入的superType是Object.class,也就是IsA都能匹配上
        resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
        // 拿到刚刚加载的所有Class对象
        Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
        // 遍历去注册
        for (Class<?> type : typeSet) {
            // 忽略所有内部类 以及 接口(这里包括pack-info.java类型)
            // Ignore inner classes and interfaces (including package-info.java)
            // Skip also inner classes. See issue #6
            // 非匿名类 且 非接口 且 非成员类(内部)
            if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
                // 真正注册别名的地方
                registerAlias(type);
            }
        }
    }
​
    /**
     * 根据类 注册别名 以简单类名作为别名 或检查是否有@Alias注解来指定别名
     *
     * @param type Class
     */
    public void registerAlias(Class<?> type) {
        // 需要注册别名的类的 非限定类名 如User 这里就是拿简单类名注册为别名了 其实后面还会转成小写的user作为别名
        String alias = type.getSimpleName();
        // 如果有别名注解 则以别名注解上的为准
        Alias aliasAnnotation = type.getAnnotation(Alias.class);
        if (aliasAnnotation != null) {
            alias = aliasAnnotation.value();
        }
        // 重载方法
        registerAlias(alias, type);
    }
​
    /**
     * 根据类来 注册别名
     *
     * @param alias 别名
     * @param value 类信息
     */
    public void registerAlias(String alias, Class<?> value) {
        // 别名没指定 直接抛异常
        if (alias == null) {
            throw new TypeException("The parameter alias cannot be null");
        }
        // issue #748
        // 转小写 按照Locale的,不看了 可能返回的长度甚至不一样
        String key = alias.toLowerCase(Locale.ENGLISH);
        // 如果 别名冲突 则抛异常
        if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
            throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
        }
        // 丢进 private final Map<String, Class<?>> typeAliases = new HashMap<>(); 中
        typeAliases.put(key, value);
    }
​
    public void registerAlias(String alias, String value) {
        try {
            registerAlias(alias, Resources.classForName(value));
        } catch (ClassNotFoundException e) {
            throw new TypeException("Error registering type alias " + alias + " for " + value + ". Cause: " + e, e);
        }
    }
​
    /**
     * Gets the type aliases.
     *
     * @return the type aliases
     *
     * @since 3.2.2
     */
    public Map<String, Class<?>> getTypeAliases() {
        return Collections.unmodifiableMap(typeAliases);
    }
​
}

看下基本的方法

方法名参数解释
TypeAliasRegistry()TypeAliasRegistry的构造方法把基本类型的别名进行定义
resolveAlias(String string)string:别名传入的值为别名或者对应的类路径 1.根据别名返回注册的对象 2.根据类路径创建一个新的对象返回
registerAliases(String packageName)packageName:包名根据传入的包名。把当前包下面的类进行注册
registerAliases(String packageName, Class<?> superType)packageName:包名 superType:包名下的父类为此类型的类根据传入的包名。和父类为传入类的进行注册。
registerAlias(Class<?> type)type:要注册的类根据类 注册别名 以简单类名作为别名 或检查是否有@Alias注解来指定别名
registerAlias(String alias, Class<?> value)alias:别名 value:要注册的类根据别名和类信息来进行注册。别名重复则报错。
registerAlias(String alias, String value)alias:别名 value:要注册的类的类路径根据别名和类路径来进行注册。别名重复则报错。
getTypeAliases()返回所有别名的集合。不可修改

类型别名注册

在Mybatis编程中我们经常会用到将某个bean作为参数类型parameterType或者结果返回值类型ResultType,所以很多时候我们需要把完成的Bean的包名在mapper文件中写上,如下:

<select id="getStudentsByAlias" resultType="org.apache.ibatis.mytest.StudentDto" useCache="false" >
    select id,name,age from student
</select>

每个都这样写的话就会显得有些冗余 Mybatis为我们提供了类别名注册。就是对某个类进行设置别名。

它的配置方式有以下几种

通过mybatis.xml 的标签来进行配置

<typeAliases>
    <package name="org.apache.ibatis.mapping"/>
</typeAliases>

扫描包下面的所有类信息。并且赋值上别名。别名为类名。

<typeAliases>
    <typeAlias  alias="student" type="org.apache.ibatis.mytest.StudentDto"/>
</typeAliases>

扫描org.apache.ibatis.mytest.StudentDto对应的类。并赋值别名student

import lombok.Data;
import org.apache.ibatis.type.Alias;
​
/**
 * @author yangqiang
 * @date 2021-07-20 23:06
 */
@Data
@Alias("studentDto")
public class StudentDto {
    private Integer id;
    private String  name;
    private  Integer age;
}

通过注解的方式来进行别名的设置。这种方式需要搭配前两种方式来进行使用。

第一种方式没有声明别名时可以利用注解定义。

第二种方式通过注解定义报名下类的别名。