首先,提一个思考题:在mapper.xml文件中写sql的时候,parameterType指明入参类型的时候,为什么只需要写String,Long,Integer等,而不用写java.lang.String,java.lang.Long这样呢?
其实是因为springboot在启动并自动初始化bean的过程中,会去加载一个叫TypeAliasRegistry的类,该类的构造器初始化了常用的所有数据类型如下:
private final Map> typeAliases = new HashMap(); public TypeAliasRegistry() { this.registerAlias("string", String.class); this.registerAlias("byte", Byte.class); this.registerAlias("long", Long.class); this.registerAlias("short", Short.class); this.registerAlias("int", Integer.class); this.registerAlias("integer", Integer.class); this.registerAlias("double", Double.class); this.registerAlias("float", Float.class); this.registerAlias("boolean", Boolean.class); this.registerAlias("byte[]", Byte[].class); this.registerAlias("long[]", Long[].class); this.registerAlias("short[]", Short[].class); this.registerAlias("int[]", Integer[].class); this.registerAlias("integer[]", Integer[].class); this.registerAlias("double[]", Double[].class); this.registerAlias("float[]", Float[].class); this.registerAlias("boolean[]", Boolean[].class); this.registerAlias("_byte", Byte.TYPE); this.registerAlias("_long", Long.TYPE); this.registerAlias("_short", Short.TYPE); this.registerAlias("_int", Integer.TYPE); this.registerAlias("_integer", Integer.TYPE); this.registerAlias("_double", Double.TYPE); this.registerAlias("_float", Float.TYPE); this.registerAlias("_boolean", Boolean.TYPE); this.registerAlias("_byte[]", byte[].class); this.registerAlias("_long[]", long[].class); this.registerAlias("_short[]", short[].class); this.registerAlias("_int[]", int[].class); this.registerAlias("_integer[]", int[].class); this.registerAlias("_double[]", double[].class); this.registerAlias("_float[]", float[].class); this.registerAlias("_boolean[]", boolean[].class); this.registerAlias("date", Date.class); this.registerAlias("decimal", BigDecimal.class); this.registerAlias("bigdecimal", BigDecimal.class); this.registerAlias("biginteger", BigInteger.class); this.registerAlias("object", Object.class); this.registerAlias("date[]", Date[].class); this.registerAlias("decimal[]", BigDecimal[].class); this.registerAlias("bigdecimal[]", BigDecimal[].class); this.registerAlias("biginteger[]", BigInteger[].class); this.registerAlias("object[]", Object[].class); this.registerAlias("map", Map.class); this.registerAlias("hashmap", HashMap.class); this.registerAlias("list", List.class); this.registerAlias("arraylist", ArrayList.class); this.registerAlias("collection", Collection.class); this.registerAlias("iterator", Iterator.class); this.registerAlias("ResultSet", ResultSet.class); }
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.typeAliases.containsKey(key) && this.typeAliases.get(key) != null && !((Class)this.typeAliases.get(key)).equals(value)) { throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + ((Class)this.typeAliases.get(key)).getName() + "'."); } else { this.typeAliases.put(key, value); } } }
DEBUG启动过程中打上断点,效果如下,可以推测,当该类初始化完成之后,会将构造器中传入的所有数据类型装载到这个叫typeAliases的Map中。
然后初始化sqlSessionFactory的过程中,会调用resolveAlias方法解析,代码如下
publicClass resolveAlias(String string) { try { if (string == null) { return null; } else { String key = string.toLowerCase(Locale.ENGLISH); Class value; if (this.typeAliases.containsKey(key)) { value = (Class)this.typeAliases.get(key); } else { value = Resources.classForName(string); } return value; } } catch (ClassNotFoundException var4) { throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + var4, var4); } }
DEBUG运行如下:
可以看到,我们在xml文件中写的string,在这里会先进if判断在typeAliases中是否有string,有就会进入下面的代码
value = (Class)this.typeAliases.get(key);
直接从里面取出string对应的全限定名java.lang.String。根据代码看,如果我们在xml中写全限定名java.lang.String,也是可以的,此时会进入else分支,通过反射获取到类。
到这里,前面的思考题就可以破案了。
为什么会去追这样一个属性的源码呢?源于开源项目ruoyi-cloud的system模块中的一个写法,在nacos配置中心可以看到,该模块采用了typeAliasesPackage为所有类指定了别名
这里只写到了system,而实际上该模块的实体类都在com.ruoyi.system.domain下面,这个属性会扫描该目录以及其子目录,所以这样写是可以解析到的,没有问题。但是当我把domain加上去的时候,按道理说也应该不会有问题啊,然而启动的时候直接报错了,报一个找不到SysDept类的异常,于是debug了一下,效果如下:
可以看出,该类并不是 com.ruoyi.system.domain下面的,而是com.ruoyi.system.api.domain下面的,那么报错就是理所当然了。
找出错误后,就想着去跟一下这个别名的解析办法,于是有了这篇文章。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)