上次分析了properties标签的加载过程,今天继续分析下面的过程
private void parseConfiguration(XNode root) {
try {
//上次分析的过程
propertiesElement(root.evalNode("properties"));
//本地分析的过程
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
具体跟踪到这 org.apache.ibatis.builder.xml.XMLConfigBuilder.settingsAsProperties(XNode)
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
Properties props = context.getChildrenAsProperties();
// 1.分析一
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
for (Object key : props.keySet()) {
//2. 分析二
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
分析 一
代码跟踪到这 org.apache.ibatis.reflection.Reflector.Reflector(Class<?>)
public Reflector(Class<?> clazz) {
type = clazz;
addDefaultConstructor(clazz);// 1.1
addGetMethods(clazz);//1.2
addSetMethods(clazz);//主要分析这 1.3
addFields(clazz);//1.4
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
分析 1.1
将本地的无参构造方法当成是默认构造方法
分析 1.2
private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
//get方法有参数的直接过滤掉
if (method.getParameterTypes().length > 0) {
continue;
}
String name = method.getName();
if ((name.startsWith("get") && name.length() > 3)
|| (name.startsWith("is") && name.length() > 2)) {
//通过截取get 或is开头后面的名字作为属性
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
}
}
resolveGetterConflicts(conflictingGetters);
}
主要是解决get方法冲突问题
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
Method winner = null;
String propName = entry.getKey();
for (Method candidate : entry.getValue()) {
if (winner == null) {
winner = candidate;
continue;
}
Class<?> winnerType = winner.getReturnType();
Class<?> candidateType = candidate.getReturnType();
if (candidateType.equals(winnerType)) {
if (!boolean.class.equals(candidateType)) {
throw new ReflectionException(
"Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + winner.getDeclaringClass()
+ ". This breaks the JavaBeans specification and can cause unpredictable results.");
} else if (candidate.getName().startsWith("is")) {
winner = candidate;
}
} else if (candidateType.isAssignableFrom(winnerType)) {
// OK getter type is descendant
} else if (winnerType.isAssignableFrom(candidateType)) {
winner = candidate;
} else {
throw new ReflectionException(
"Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + winner.getDeclaringClass()
+ ". This breaks the JavaBeans specification and can cause unpredictable results.");
}
}
//选出最优匹配的加入到方法中
addGetMethod(propName, winner);
}
}
分析1.3 set方法与get类似
分析 1.4
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (field.isAccessible()) {
//将不在set方法中且不是static final的字段加入到field中
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())) {
//不在get方法中加入到field中
addGetField(field);
}
}
}
//递归查到父类的属性
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
分析二
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
//是否有children 即如果是a.b 那么就是有值
if (prop.hasNext()) {
if (reflector.hasSetter(prop.getName())) {
MetaClass metaProp = metaClassForProperty(prop.getName());
//递归查询是否有set方法
return metaProp.hasSetter(prop.getChildren());
} else {
return false;
}
} else {
//没有children就走这个
return reflector.hasSetter(prop.getName());
}
}
public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.');
if (delim > -1) {
name = fullname.substring(0, delim);
//含有.
children = fullname.substring(delim + 1);
} else {
name = fullname;
children = null;
}
indexedName = name;
delim = name.indexOf('[');
if (delim > -1) {
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}
总结:所有settings配置文件中的键在Configuration中都有相应的set方法