技术债
- ReflectorFactory
- Configuration
- TypeAliasRegistry
- TypeHandlerRegistry
今天我们来偿还关于反射工具的技术债,也就是对应上述的ReflectorFactory类。
首先我们需要思考下面一个问题:
如果是让你搭建一个类反射的工具类,你会如何设计呢?
1.1MyBatis框架下的反射机制
首先我们查阅MyBatis框架下源码,可以很容易发现有一个包和反射有关,如下:
MyBatis反射包
乍一看,可能大家会被这么多类给吓到,感觉心虚,但是不要慌,你与他人的差距恰恰是在这里。(给自己喝一口鸡汤)
心定之后便是来思考从哪个类来入手(切记不要像个无头苍蝇下乱撞,顺着思路看会顺利很多)。这时我就瞄向了测试类,也就是官方单元测试Demo来整理思路。
反射测试类
那我们便开始进行分析.
2.DefaultObjectFactoryTest类抛砖引玉
//DefaultObjectFactoryTest
@Test
void createClass() {
DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory();
TestClass testClass = defaultObjectFactory.create(TestClass.class,
Arrays.asList(String.class, Integer.class), Arrays.asList("foo", 0));
Assertions.assertEquals((Integer) 0, testClass.myInteger, "myInteger didn't match expected");
Assertions.assertEquals("foo", testClass.myString, "myString didn't match expected");
}
其中这里涉及到的TestClass为:
public class TestClass {
String myString;
Integer myInteger;
public TestClass(String myString, Integer myInteger) {
this.myString = myString;
this.myInteger = myInteger;
}
}
万事俱备只欠东风,我们进行分析。
2.1 DefaultObjectFactory解析
这个类没有属性,默认无参构造方法。我们直接来看上面调用的方法:
//DefaultObjectFactory
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Class<?> classToCreate = resolveInterface(type);
// we know types are assignable
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
/**
* 解析类的类型
*/
protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class || type == Collection.class || type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) { // issue #510 Collections Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}
/**
* 实例化类
*/
private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
//如无构造函数和参数传进来,使用默认无参构造方法
try {
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
try {
return constructor.newInstance();
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
constructor.setAccessible(true);
return constructor.newInstance();
} else {
throw e;
}
}
}
//如存在构造函数和参数传进来,匹配有参构造方法实例化
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
try {
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
constructor.setAccessible(true);
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} else {
throw e;
}
}
} catch (Exception e) {
String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
.stream().map(Class::getSimpleName).collect(Collectors.joining(","));
String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
.stream().map(String::valueOf).collect(Collectors.joining(","));
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}
这个类逻辑不复杂,总结两点:
- 遇到无参构造函数使用java反射实例情况
- 遇到有参构造函数使用java反射实例情况
下面来挑战下一个测试类ReflectorTest。
2.2 ReflectorTest类解析
由于这个类是其他类的基础,我们变先拿这个类开刀,顾名思义这个类和Reflector有关,那么接下来我们开始撸第一个方法:
@Test
void testGetSetterType() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assertions.assertEquals(Long.class, reflector.getSetterType("id"));
}
我们来看 reflectorFactory.findForClass方法:
//DefaultReflectorFactory
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
如果缓存中存在则从缓存中取,如果没有直接通过new创建一个Reflector实例,那么接下来重点便是Reflector。
2.2.1 Reflector类解析
我们继续来看他的属性和构造方法:
//Reflector
private final Class<?> type;
private final String[] readablePropertyNames;
private final String[] writablePropertyNames;
private final Map<String, Invoker> setMethods = new HashMap<>();
private final Map<String, Invoker> getMethods = new HashMap<>();
private final Map<String, Class<?>> setTypes = new HashMap<>();
private final Map<String, Class<?>> getTypes = new HashMap<>();
private Constructor<?> defaultConstructor;
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
public Reflector(Class<?> clazz) {
//这里可以理解一个类一个Reflector实例
type = clazz;
//添加默认构造函数,即无参构造函数
addDefaultConstructor(clazz);
//添加get或者is开头的方法名的方法
addGetMethods(clazz);
//添加set开头的方法名的方法
addSetMethods(clazz);
//添加属性
addFields(clazz);
//可读属性,也就是存在Get方法的属性
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
//可写属性,也就是存在Set方法的属性
writablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
//下面就是把两个方法转化为可读属性和可写属性的大写,并使用Map类型映射
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
这个类方法有点多,我们只是大概看下类,见名知意即可:
Reflector类方法
Reflector构造方法中类的很简单,结合我的注释,我们来看下代码:
/**
* 添加默认构造函数,即无参构造函数
*/
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] consts = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : consts) {
if (constructor.getParameterTypes().length == 0) {
this.defaultConstructor = constructor;
}
}
}
/**
* 添加get或者is开头的方法名的方法
*/
private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap<>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
if (method.getParameterTypes().length > 0) {
continue;
}
String name = method.getName();
if ((name.startsWith("get") && name.length() > 3)
|| (name.startsWith("is") && name.length() > 2)) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
}
}
resolveGetterConflicts(conflictingGetters);
}
/**
* 添加set开头的方法名的方法
*/
private void addSetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingSetters = new HashMap<>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("set") && name.length() > 3) {
if (method.getParameterTypes().length == 1) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingSetters, name, method);
}
}
}
resolveSetterConflicts(conflictingSetters);
}
/**
* 添加属性
* @param clazz
*/
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!setMethods.containsKey(field.getName())) {
// issue #379 - removed the check for final because JDK 1.5 allows
// modification of final fields through reflection (JSR-133). (JGB)
// pr #16 - final static can only be set by the classloader
int modifiers = field.getModifiers();
if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
addSetField(field);
}
}
if (!getMethods.containsKey(field.getName())) {
addGetField(field);
}
}
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
剩下的就不一一列举,总结一下:
Reflector就是处理构造函数中传入的class,然后解析出其所有属性,包括构造函数,set、get方法还有所有对应的属性。我们至少要记住这个类的作用,对于后面解析很有作用。
3.今日总结
今天我们主要分析了ReflectorFactory,知其意是用来解析某个类属性的。那我们还剩下:
技术债
- Configuration
- TypeAliasRegistry
- TypeHandlerRegistry
网友评论