parent
1c6864501e
commit
d6144369ed
@ -0,0 +1,169 @@
|
||||
# mybatis 反射
|
||||
|
||||
## addDefaultConstructor
|
||||
|
||||
- mybatis 的反射相关内容在`org.apache.ibatis.reflection` 下存放. 本片主要讲解`org.apache.ibatis.reflection.Reflector`类, 先看一下该类的属性
|
||||
```java
|
||||
public class Reflector {
|
||||
|
||||
/**
|
||||
* 实体类.class
|
||||
*/
|
||||
private final Class<?> type;
|
||||
/**
|
||||
* 可读 属性
|
||||
*/
|
||||
private final String[] readablePropertyNames;
|
||||
/**
|
||||
* 可写 属性值
|
||||
*/
|
||||
private final String[] writablePropertyNames;
|
||||
/**
|
||||
* set 方法列表
|
||||
*/
|
||||
private final Map<String, Invoker> setMethods = new HashMap<>();
|
||||
/**
|
||||
* get 方法列表
|
||||
*/
|
||||
private final Map<String, Invoker> getMethods = new HashMap<>();
|
||||
/**
|
||||
* set 的数据类型
|
||||
*/
|
||||
private final Map<String, Class<?>> setTypes = new HashMap<>();
|
||||
/**
|
||||
* get 的数据类型
|
||||
*/
|
||||
private final Map<String, Class<?>> getTypes = new HashMap<>();
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
private Constructor<?> defaultConstructor;
|
||||
|
||||
/**
|
||||
* 缓存数据, 大写KEY
|
||||
*/
|
||||
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
- 构造方法, 构造方法传入一个类的字节码,在构造方法中设置相关的属性值
|
||||
```java
|
||||
public class Reflector {
|
||||
|
||||
/**
|
||||
* @param clazz 待解析类的字节码
|
||||
*/
|
||||
public Reflector(Class<?> clazz) {
|
||||
type = clazz;
|
||||
// 构造方法
|
||||
addDefaultConstructor(clazz);
|
||||
// get 方法
|
||||
addGetMethods(clazz);
|
||||
// set 方法
|
||||
addSetMethods(clazz);
|
||||
// 字段值
|
||||
addFields(clazz);
|
||||
readablePropertyNames = getMethods.keySet().toArray(new String[0]);
|
||||
writablePropertyNames = setMethods.keySet().toArray(new String[0]);
|
||||
for (String propName : readablePropertyNames) {
|
||||
// 循环操作设置到缓存中,
|
||||
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
|
||||
}
|
||||
for (String propName : writablePropertyNames) {
|
||||
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
- `addDefaultConstructor` 方法 , 下面截图内容为JDK8 mybatis中 的内容
|
||||
```java
|
||||
private void addDefaultConstructor(Class<?> clazz) {
|
||||
|
||||
// 获取类里面的所有构造方法
|
||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
||||
// 过滤得到空参构造 constructor -> constructor.getParameterTypes().length == 0
|
||||
Arrays.stream(constructors).filter(constructor -> constructor.getParameterTypes().length == 0)
|
||||
.findAny().ifPresent(constructor -> {
|
||||
System.out.println("有空参构造");
|
||||
this.defaultConstructor = constructor;
|
||||
});
|
||||
}
|
||||
```
|
||||
- 创建一个测试类
|
||||
```java
|
||||
public class People {
|
||||
private String name;
|
||||
|
||||
public People() {
|
||||
}
|
||||
|
||||
public People(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "People{" +
|
||||
"name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```java
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
class HfReflectorTest {
|
||||
@Test
|
||||
void getDefaultConstructorTest() throws Exception {
|
||||
Reflector reflector = new Reflector(People.class);
|
||||
// 获取空参构造方法
|
||||
Constructor<?> defaultConstructor = reflector.getDefaultConstructor();
|
||||
People o = (People) defaultConstructor.newInstance();
|
||||
o.setName("hhh");
|
||||
|
||||
System.out.println(o);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 准备工作完成了开始进行 debug , 在`org.apache.ibatis.reflection.Reflector#addDefaultConstructor`这个方法上打上断点
|
||||
|
||||

|
||||
|
||||
观察`constructors`属性存在两个方法,这两个方法就是我在`People`类中的构造方法.
|
||||
|
||||
根据语法内容我们应该对`parameterTypes`属性进行查看
|
||||
|
||||

|
||||
|
||||
可以发现空参构造的`parameterTypes`长度是0.因此可以确认`org.apache.ibatis.reflection.Reflector#addDefaultConstructor`方法获取了空参构造
|
||||
|
||||
- 继续看`org.apache.ibatis.reflection.Reflector#getDefaultConstructor`方法, 该方法是获取构造函数的方法,如果构造函数没有就抛出异常,这也是为什么我们的实体类需要把空参构造写上去的原因。
|
||||
|
||||
```java
|
||||
public Constructor<?> getDefaultConstructor() {
|
||||
if (defaultConstructor != null) {
|
||||
return defaultConstructor;
|
||||
} else {
|
||||
// 如果没有空参构造抛出的异常
|
||||
throw new ReflectionException("There is no default constructor for " + type);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 55 KiB |
Loading…
Reference in new issue