1. 程式人生 > 其它 >mybatis原始碼reflection包--引數解析器ParamNameResolver

mybatis原始碼reflection包--引數解析器ParamNameResolver

技術標籤:# mybatis基礎包原始碼

ParamNameResolver是一個引數名解析器,負責把方法的引數按順序解析出來並進行標註。

1.因為設計到字串處理,隨便寫一個方法進行debug跟蹤

ParamNameResolver在構造器中對getUserInfo進行解析,邏輯很簡單,獲取該方法所有引數型別進行遍歷,如果該引數上有@Param註解就獲取Param中的value作為屬性名,沒有的話就判斷配置中useActualParamName是否允許使用原始引數名,不允許就用引數順序進行命名。最後把解析結果存到ParamNameResolver的names屬性中。

 // 方法入參的引數次序表。鍵為引數次序,值為引數名稱或者引數@Param註解的值
  private final SortedMap<Integer, String> names;
  // 該方法入參中是否含有@Param註解
  private boolean hasParamAnnotation;

  /**
   * 引數名解析器的構造方法
   * @param config 配置資訊
   * @param method 要被分析的方法
   */
  public ParamNameResolver(Configuration config, Method method) {
    // 獲取引數型別列表
    final Class<?>[] paramTypes = method.getParameterTypes();
    // 準備存取所有引數的註解,是二維陣列
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();
    final SortedMap<Integer, String> map = new TreeMap<>();
    int paramCount = paramAnnotations.length;
    // 迴圈處理各個引數
    for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
      if (isSpecialParameter(paramTypes[paramIndex])) {
        // 跳過特別的引數
        continue;
      }
      // 引數名稱
      String name = null;
      for (Annotation annotation : paramAnnotations[paramIndex]) {
        // 找出引數的註解
        if (annotation instanceof Param) {
          // 如果註解是Param
          hasParamAnnotation = true;
          // 那就以Param中值作為引數名
          name = ((Param) annotation).value();
          break;
        }
      }

      if (name == null) {
        // 否則,保留引數的原有名稱
        if (config.isUseActualParamName()) {
          name = getActualParamName(method, paramIndex);
        }
        if (name == null) {
          // 引數名稱取不到,則按照引數index命名
          name = String.valueOf(map.size());
        }
      }
      map.put(paramIndex, name);
    }
    names = Collections.unmodifiableSortedMap(map);
  }

debug跟蹤後 names的結果如下:

2.ParamNameResolver的getNamedParams函式是在確定names屬性後,給出方法引數名->引數值的對映

原始碼如下:

  public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    if (args == null || paramCount == 0) {
      return null;
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];
    } else {
      final Map<String, Object> param = new ParamMap<>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        // 首先按照類註釋中提供的key,存入一遍   【引數的@Param名稱 或者 引數排序:實參值】
        // 注意,key和value交換了位置
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        // 再按照param1, param2, ...的命名方式存入一遍
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }

假設對上邊自己定義的介面呼叫

getUserInfo(1,18,"波多野結衣")

debug跟蹤他返回的結果是: