问题:
我在执行service层掉mapper层的时候会进到当前调用的实体类中的自定义方法,但是部分自定义方法是没有地方去调用过的,但是他还是会去调用。
这是我实体类中的自定义方法:
public boolean isStr() {
return true;
}
public boolean isSuperColumn(String javaField) {
}
public boolean isSuperColumn() {
}
public boolean isUsableColumn(String javaField) {
}
public String readConverterExp() {
}
源码:
这里我下载的是若依的代码 Mybatis是3.5.9的源码,其他版本基本上不会有太大的区别。
在SqlSessionFactoryBean 的 Resource [] mapperlocations 属性中会保存扫描到的所有的**mapper.xml 文件的地址,并且会解析为一个 XMLMapperBuilder对象,并且获取namespace 并且解析 resultMap 中的属性 。
得到的是当前包下面的所有的实体类对应的信息,我这里包下面是两个实体类
通过反射获取:
之后循环中会执行到一下代码中,最终获取到的所有的方法都在 classMethods 中存放,
public Reflector(Class<?> clazz) {
type = clazz;
// 默认的构造器
addDefaultConstructor(clazz);
// get方法
addGetMethods(clazz);
// set方法
addSetMethods(clazz);
// 属性字段
addFields(clazz);
// 从 getMethods 映射中获取可读属性名数组
readablePropertyNames = getMethods.keySet().toArray(new String[0]);
// 从 setMethods 映射中获取可写属性名数组
writablePropertyNames = setMethods.keySet().toArray(new String[0]);
// 将所有属性名的大写形式作为键,属性名作为值,存入到 caseInsensitivePropertyMap 中
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
addGetMethods()、addSetMethods()、addDefaultConstructor()方法是过滤方法的关键:
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
// 判断有没有空参的构造器 有的话赋值给 defaultConstructor
Arrays.stream(constructors).filter(constructor -> constructor.getParameterTypes().length == 0)
.findAny().ifPresent(constructor -> this.defaultConstructor = constructor);
}
private void addGetMethods(Method[] methods) {
Map<String, List<Method>> conflictingGetters = new HashMap<>();
//添加参数为空的
Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
.forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
resolveGetterConflicts(conflictingGetters);
}
再进入到isGetter方法:
public static boolean isGetter(String name) {
// 筛选出 get 或者 is 开头的
return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
}
真心大白!
结果:Mybatis会获取到service层调用mapper层接收的对象中的所有的方法并且进行过滤,以get开头或者 is 开头的 和参数为 空的 都会被获取到,并且后面的代码中也会循环使用到这些方法,所以才导致文章开头我贴上的代码我实际上没有调用但是一直在被调用。有不对的地方欢迎指正哈。