Mybatis系列(五)typeAliases源码解析


上篇文章 Mybatis系列(四)settings源码解析,介绍了setting节点,这篇我们来介绍typeAliases。typeAliases主要用来设置别名,可以为我们减少xml配置中对java类引用时冗余的全限定名。

比如我们在使用com.sean.entity.User,就可以配置别名user。

一、typeAliases配置

    <typeAliases>
        <typeAlias alias="user" type="com.sean.entity.User"/>
    </typeAliases>

后续对com.sean.entity.User全限定名的引用就可以简写成user,我们第一节的findUserById返回类型就可以可以简写成

    <select id="findUserById" parameterType="java.lang.Long" resultType="user">
        SELECT * FROM user WHERE id = #{id}
    </select>

resultType="com.sean.entity.User" 简写成 resultType="user",有没有很清爽的感觉。

二、typeAliasesElement源码

依旧是XMLConfigBuilder类中的parseConfiguration方法,这里就不再贴出,我们直接看它的this.typeAliasesElement(root.evalNode("typeAliases"));

	//解析typeAliases节点
    private void typeAliasesElement(XNode parent) {
        if (parent != null) {
            Iterator i$ = parent.getChildren().iterator();

            while(i$.hasNext()) {
                XNode child = (XNode)i$.next();
                String alias;
                //如果是子节点name是package,TypeAliasRegistry会扫描指定的包路径,进行别名注册
                if ("package".equals(child.getName())) {
                    alias = child.getStringAttribute("name");
                    this.configuration.getTypeAliasRegistry().registerAliases(alias);
                } else {
                	//如果子节点是typeAlias节点,那么就获取alias属性和type的属性值
                    alias = child.getStringAttribute("alias");
                    String type = child.getStringAttribute("type");

                    try {
                        Class<?> clazz = Resources.classForName(type);
                        //如果别名为null,使用 Bean 的首字母小写的非限定类名来作为它的别名
                        if (alias == null) {
                            this.typeAliasRegistry.registerAlias(clazz);
                        } else {
                            this.typeAliasRegistry.registerAlias(alias, clazz);
                        }
                    } catch (ClassNotFoundException var7) {
                        throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + var7, var7);
                    }
                }
            }
        }

    }

通过源码我们得知最终都是通过TypeAliasRegistry的registerAlias方法,进行别名注册。
先看包路径扫描注册别名:

    public void registerAliases(String packageName) {
        this.registerAliases(packageName, Object.class);
    }

    public void registerAliases(String packageName, Class<?> superType) {
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil();
        //根据包路径获取所以的class
        resolverUtil.find(new IsA(superType), packageName);
        Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
        Iterator i$ = typeSet.iterator();

        while(i$.hasNext()) {
            Class<?> type = (Class)i$.next();
            //忽略内部类、接口、成员类
            if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
            	//注册别名的方法,下边主要看这个方法
                this.registerAlias(type);
            }
        }

    }

注册别名的方法registerAlias

    public void registerAlias(Class<?> type) {
    	//这里判断有没有Alias注解,如果注解过,使用注解的别名,否则使用类名的第一个字母小写
        String alias = type.getSimpleName();
        Alias aliasAnnotation = (Alias)type.getAnnotation(Alias.class);
        if (aliasAnnotation != null) {
            alias = aliasAnnotation.value();
        }

        this.registerAlias(alias, type);
    }

    public void registerAlias(String alias, Class<?> value) {
        if (alias == null) {
            throw new TypeException("The parameter alias cannot be null");
        } else {
        	//取英文字母中的小写
            String key = alias.toLowerCase(Locale.ENGLISH);
            //如果有相同的别名已经存在就会报错
            if (this.TYPE_ALIASES.containsKey(key) && this.TYPE_ALIASES.get(key) != null && !((Class)this.TYPE_ALIASES.get(key)).equals(value)) {
                throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + ((Class)this.TYPE_ALIASES.get(key)).getName() + "'.");
            } else {
                this.TYPE_ALIASES.put(key, value);
            }
        }
    }

三、系统别名

mybatis默认给我们的别名

/**
   * 以下就是mybatis默认为我们注册的别名
   */
  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);
  }

所以在使用TypeAliasRegistryregisterAlias方法就可以注册别名了,一般是通过Configuration获取TypeAliasRegistry类对象,其中有一个getTypeAliasRegistry方法可以获得别名,如configuration.getTypeAliasRegistry()。然后就可以通过registerAlias方法对别名注册了。Configuration对象也对一些常用的配置项配置了别名。

        //事务方式别名
        this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
        //数据源类型别名
        this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        //缓存策略别名
        this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
        this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
        this.typeAliasRegistry.registerAlias("LRU", LruCache.class);
        this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
        this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
        //数据库标识别名
        this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
        //语言驱动类别名
        this.typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
        //日志类别名
        this.typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
        this.typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
        this.typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
        this.typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
        this.typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
        //动态代理别名
        this.typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
        this.typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

四、自定义别名

上边我们已经讲了怎么给对象设置别名,但是有时候我们有很多对象,有User1,User2,User3…
如果还这样设置<typeAlias alias="user" type="com.sean.entity.User"/>也会很麻烦。
刚刚看源码我们直接给报名设置别名。

    <typeAliases>
        <package name="com.sean.entity"/>
    </typeAliases>

这样mybatis讲扫描这个包里边的类,将其第一个字母变为小写作为其别名,比如类User的别名变为user。使用这样的规则,有时候会出现重名,比如我有两个包都有User类,com.sean.entity2.User,mybatis还增加了对com.sean.entity2这个包的扫描,那么就会出现异常,这个时候可以使用mybatis提供的注解@Alias(“user2”)进行区分。

package com.sean.entiry2;

import lombok.Data;
import org.apache.ibatis.type.Alias;

@Data
@Alias("user2")
public class User {

    private Long id;

    private String name;

    private Integer age;

    private String mobile;

}

这样就可以避免因为别名重名导致扫描失败的问题。
typeAliases节点到此结束,下一节我们继续介绍其他节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值