1、JavaBean规范
JavaBean 具有如下特征:
- 所有的属性都是私有的(通过 getter 和 setter 访问)
- 拥有公有的无参构造函数
- 提供 setter/getter
- 实现 Serializable 接口
2、Reflector 和 ReflectorFactory
出于性能方面的考虑,Mybatis 不是等到使用的时候去解析 XML/反射类,而是为每一个类提供了反射器类 Reflector ,该类中存储了反射需要使用的类的元信息。
2.1 Reflector 属性
2.1.1 属性
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private Class<?> type;
//可读属性的名称集合,可读属性就是存在相应 getter 方法的属性,初始值为空数组
private String[] readablePropertyNames = EMPTY_STRING_ARRAY;
//可写属性的名称集合,可写属性就是存在相应 setter 方法的属性,初始值为空数组
private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;
//记录了属性相应的 setter 方法,key 是属性名称,value 是 Invoker 对象,它是对 setter 方法对应 Method 对象的封装
private Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
//记录了属性相应的 getter 方法,key 是属性名称,value 是 Invoker 对象,它是对 getter 方法对应 Method 对象的封装
private Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
//记录了属性相应的 setter 方法的参数值类型,key 是属性名称,value 是 setter 方法的参数类型
private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
//记录了属性相应的 getter 方法的参数值类型,key 是属性名称,value 是 getter 方法的返回值类型
private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
//记录了默认构造方法
private Constructor<?> defaultConstructor;
//记录了所有属性名称的集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();
从上面类的属性中,我们可以看出:
- 一个反射器 Reflector 对应着一个 Class 对象
- 记录了默认构造函数
- 其余的是属性及其 setter/gettter 相关
对于一个属性(只有有 setter/getter 才能被称之为属性)
(1)如果是可读的(有 getter 方法),则 Reflector 会将其及其方法处理后放入对应的可读相关的集合中;
(2)如果是可写的(有 setter 方法),则 Reflector 会将其及其方法处理后放入对应的可写相关的集合中;
(3)最后使用Map<String, String> caseInsensitivePropertyMap
记录所有的属性。
2.1.2 Invoker 接口
在存储方法的时候,Reflector
使用的是 Map<String, Invoker>
,而不是 Map<String, Method>
。该接口定义了方法的调用和获取类型,定义如下:
public interface Invoker {
//调用获取指定字段的值或者执行指定的方法
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
//获取类型
Class<?> getType();
}
- MethodInvoker:方法的 Invoker
- GetFieldInvoker:如果没有
getter
,则使用该方法,通过Filed
类直接读取成员变量的值 - SetFieldInvoker:如果没有
setter
,则使用该方法,通过Filed
类直接设置成员变量的值
通过该封装以后,本来需要声明 Map<String, Method>
和 Map<String, Field>
表示的,只需要使用 Map<String, Field>
即可表示。
2.2 Reflector 对外提供的方法
Reflector 对外提供的方法主要与构造函数和属性相关。
- 构造函数:根据 Class 对象,设置 Reflector 相应的成员变量。
public Reflector(Class<?> clazz)
- 查找是否有相应的属性
public String findPropertyName(String name)
- 判断是否有默认构造函数
public boolean hasDefaultConstructor()
- 获取默认的构造函数
public Constructor<?> getDefaultConstructor()
- 获取 Reflector 对应的 Class 类型
public Class<?> getType()
- getter 相关的方法
//获取所有的可读属性
public String[] getGetablePropertyNames()
//获取所有的可读属性的 Invoker
public Invoker getGetInvoker(String propertyName)
//获取对应属性的类型
public Class<?> getGetterType(String propertyName)
//对应属性是否有相应的 getter
public boolean hasGetter(String propertyName)
- setter相关的方法
//获取所有的可写属性
public String[] getSetablePropertyNames()
//获取所有的可写属性的 Invoker
public Invoker getSetInvoker(String propertyName)
//获取可写属性 setter 方法的参数
public Class<?> getSetterType(String propertyName)
//对应属性是否有相应的 setter
public boolean hasSetter(String propertyName)
2.3 Reflector 私有方法
每个 Reflector 对应缓存一个类的元反射信息,通过 Map 进行缓存,后续通过键查找即可。因此,就涉及到几个方法:
2.3.1获取方法签名
根据函数名称、参数和返回值类型来取得签名,保证方法的唯一性
private String getSignature(Method method)
该方法获取方法的签名,签名的格式为:
返回值类型#方法名:参数1,参数2,参数3
签名的目的是为了保证唯一性,那么使用语言本身的特性来保证唯一性是最好的:
- 方法名不一致,则方法不一致
- 返回值不一致或者不是其子类,则方法不一致
- 参数数量,参数类型顺序不一致,则方法不一致
因此,以上的规则保证方法的唯一性。
2.3.2获取类的所有方法
private Method[] getClassMethods(Class<?> cls)
注意,由于在获取方法时,通过调用当前类及其除 Object
之外的所有父类的 getDeclaredMethods()
和 getInterfaces()
方法,因此,其获取到的方法是该类及其父类的所有方法。
由此,产生一个问题,如果子类重写了父类中的方法,如果返回值相同,则可以通过键值重复来去掉。但是,如果方法返回值类型是相同实体方法返回值类型的子类型,则就会导致两个方法是同一个方法,但是签名不同。因此,需要解决此类冲突。
2.3.3解决方法冲突:getter方法冲突解决
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters)
到了此步骤,属性已经以 propName->List<Method>
的形式存在于内存中。此时,需要将 Map<String, List>
转换为 Map<String, Invoker>
。
该方法只需要特别注意当返回值类型不同,则哪一个方法的返回值是另一个方法返回值类型的子类型,就把 propName
指向该方法包装成的 Invoker
。这是因为重写(override
)时,重写方法的返回值类型可以是被重写方法的子类。
2.3.4解决方法冲突:setter方法冲突解决
首先需要特别注意的是,为什么 setter 也会出现冲突,毕竟没有返回值类型。主要是因为泛型的存在:
public void setPrice(T price);
public void setPrice(Double price);
public void setPrice(Integer price);
显然,遇到此类情况,子类中的方法才是我们需要的:
Class<?> paramType1 = setter1.getParameterTypes()[0];
Class<?> paramType2 = setter2.getParameterTypes()[0];
if (paramType1.isAssignableFrom(paramType2)) {
return setter2;
} else if (paramType2.isAssignableFrom(paramType1)) {
return setter1;
}
参数中,父类方法泛型经过类型擦除后,变成 Object
。因此,通过以上的方法,哪个是子类,我们就获取哪一个。
3、ReflectorFactory
看名称,工厂方法,是为了创建个缓存 Reflector
的:
/**
* 主要负责 Reflector 对象的创建和缓存
*/
public interface ReflectorFactory {
/**
* 检测 ReflectorFactory 对象是否会缓存 Reflector 对象
*/
boolean isClassCacheEnabled();
/**
* 设置是否缓存
*/
void setClassCacheEnabled(boolean classCacheEnabled);
/**
* 缓存中查找 Class 对应的 Reflector 对象,找不到则创建
*/
Reflector findForClass(Class<?> type);
}
只有三个方法:是否缓存,设置要不要缓存,根据类型查找 Reflector 对象,找不到则创建。其与 Reflector 的关系:
mybatis 为我们提供了该方法的默认实现 DefaultReflectorFactory
。该类的实现很简单,就是通过 ConcurrentMap<Class<?>, Reflector>
对 Reflector
进行缓存。
4、MetaClass
Reflector
实现了实体类元信息的封装,但是类中的成员变量是类的情况没有进行处理。而 MetaClass 通过 ReflectorFactory
类型的成员变量,实现了实体类中成员变量是类情况的处理,通过与属性工具类的结合,实现了对复杂表达式的解析和实现了获取指定描述信息的功能。
4.1 成员变量
public class MetaClass {
//ReflectorFactory 对象,用于缓存 Reflector 对象
private ReflectorFactory reflectorFactory;
//在创建 MetaClass 时会指定一个类,该 Reflector 对象会用于记录该类相关的元信息
private Reflector reflector;
MetaClass 有两个成员变量,分别是 reflectorFactory
和 reflector
。
4.2 创建
MetaClass 构造函数是私有的:
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
但是,其提供了两个创建的方法,这两个方法也是通过该方法进行创建对象的。
- 通过
Class
对象进行了Reflector
对象的创建,并赋值给成员变量
public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
return new MetaClass(type, reflectorFactory);
}
- 通过属性进行创建
/**
* 通过属性名称,获取属性的 MetaClass
*/
public MetaClass metaClassForProperty(String name) {
Class<?> propType = reflector.getGetterType(name);
return MetaClass.forClass(propType, reflectorFactory);
}
4.3 方法
该类中最重要的方法是:
/**
* 解析复杂的属性表达式,例如:<result property="orders[0].items[0].name" column="item1"/> 中 property="orders[0].items[0].name"
* 案例:
* @param name tele.name
* @param builder
* @return
*/
private StringBuilder buildProperty(String name, StringBuilder builder) {
//构造兼解析,name:tele.name
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
//prop.getName():tele propertyName:tele
String propertyName = reflector.findPropertyName(prop.getName());
if (propertyName != null) {
builder.append(propertyName);
builder.append(".");
//为该属性创建对应的 MetaClass 对象
MetaClass metaProp = metaClassForProperty(propertyName);
//递归解析 PropertyTokenizer.children 字段,并将解析结果添加到 builder 中保存
metaProp.buildProperty(prop.getChildren(), builder);
}
} else {
String propertyName = reflector.findPropertyName(name);
if (propertyName != null) {
builder.append(propertyName);
}
}
//tele.name
return builder;
}
理解了这个方法(递归,该类中有很多类似的),就可以很好的对这个类进行理解,以查找(richType.richProperty)为例:
- 通过 PropertyTokenizer 对表达式进行解析, 得到当前的 name=richType, children=richProperty
- 从 reflector 中查找该 richType 属性
- 将 richType 添加到 builder 中
- 使用 metaClassForProperty 创建 richType 的 MetaClass
- 递归调用自身来处理子表达式
退出的条件就是没有子表达式。这个是为了,我们类中有成员变量是类,我们可以通过其找到他们的所有类及其属性。
注意,在此过程中,ReflectorFactory
一直是同一个,而其内部缓存了多个 Reflector
对象。
5、MetaObject
对对象级别的元信息进行封装!
6、总结
上面类的关系:
Reflector
实现了实体类元信息的封装,但是类中的成员变量是类的情况没有进行处理。而 MetaClass 通过 ReflectorFactory
类型的成员变量,实现了实体类中成员变量是类情况的处理,从而结合属性工具实现了对复杂表达式的处理。