mybatis源码分析(2)

4 篇文章 0 订阅
2 篇文章 0 订阅

上次分析了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方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值