SpringBoot中的排序

包含三個(gè)類

AnnotationAwareOrderComparator

OrderComparator

Comparator

類圖如下:


image-20200421180701888.png

步驟1:排序調(diào)用OrderComparator的compare方法

public int compare(@Nullable Object o1, @Nullable Object o2) {
   return doCompare(o1, o2, null);
}

步驟2:調(diào)用內(nèi)部方法doCompare贵白,先判斷是否有一個(gè)實(shí)現(xiàn)PriorityOrdered接口,如果有一個(gè)實(shí)現(xiàn)崩泡,順序關(guān)系可以確定直接返回禁荒。

如果都沒(méi)有實(shí)現(xiàn)或者都實(shí)現(xiàn)了PriorityOrdered接口,進(jìn)一步調(diào)用getOder方法返回排序值角撞,然后確定順序關(guān)系呛伴。

private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
    // 實(shí)現(xiàn)了PriorityOrdered接口,排序靠前
    // PriorityOrdered繼承自O(shè)rdered接口靴寂,也可以實(shí)現(xiàn)getOrder方法,所以實(shí)現(xiàn)PriorityOrdered的類里面getOrder越小的越靠前
   boolean p1 = (o1 instanceof PriorityOrdered);
   boolean p2 = (o2 instanceof PriorityOrdered);
   if (p1 && !p2) {
      return -1;
   }
   else if (p2 && !p1) {
      return 1;
   }

   int i1 = getOrder(o1, sourceProvider);
   int i2 = getOrder(o2, sourceProvider);
   return Integer.compare(i1, i2);
}

步驟3:內(nèi)部方法getOrder召耘,在OrderSourceProvider為null的情況下百炬,直接調(diào)用了getOder重構(gòu)方法

private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
   Integer order = null;
    //OrderSourceProvider這里不做分析
   if (obj != null && sourceProvider != null) {
      Object orderSource = sourceProvider.getOrderSource(obj);
      if (orderSource != null) {
         if (orderSource.getClass().isArray()) {
            Object[] sources = ObjectUtils.toObjectArray(orderSource);
            for (Object source : sources) {
               order = findOrder(source);
               if (order != null) {
                  break;
               }
            }
         }
         else {
            order = findOrder(orderSource);
         }
      }
   }
   return (order != null ? order : getOrder(obj));
}

步驟4:getOder里面調(diào)用了findOrder方法,findOrder返回null的時(shí)候直接返回最小排序值

protected int getOrder(@Nullable Object obj) {
   if (obj != null) {
      Integer order = findOrder(obj);
      if (order != null) {
         return order;
      }
   }
   return Ordered.LOWEST_PRECEDENCE;
}

步驟5:AnnotationAwareOrderComparator重寫findOrder方法

//AnnotationAwareOrderComparator重寫findOrder方法
@Override
@Nullable
protected Integer findOrder(Object obj) {
    // 先調(diào)用父類方法污它,判斷是否實(shí)現(xiàn)了Ordered接口剖踊,如果實(shí)現(xiàn)了調(diào)用getOrder方法,否則返回null
   Integer order = super.findOrder(obj);
   if (order != null) {
      return order;
   }
    // 如果沒(méi)有實(shí)現(xiàn)Ordered接口衫贬,或者實(shí)現(xiàn)了Ordered接口但是getOrder返回null德澈,則調(diào)用該方法
   return findOrderFromAnnotation(obj);
}

// 父類OrderComparator的findOrder方法
@Nullable
protected Integer findOrder(Object obj) {
    return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
}

步驟6:AnnotationAwareOrderComparator核心方法

@Nullable
private Integer findOrderFromAnnotation(Object obj) {
    // AnnotatedElement代表了在當(dāng)前JVM中的一個(gè)“被注解元素”(可以是Class,Method固惯,F(xiàn)ield梆造,Constructor,Package等
   AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
    // MergedAnnotations是Spring的工具類葬毫,from方法是從element中獲取注解镇辉,SearchStrategy是注解掃描策略,TYPE_HIERARCHY包含superclass贴捡,接口
   MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
    // 根據(jù)注解解析order
   Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
    // 如果order為null忽肛,并且排序?qū)ο髮?shí)現(xiàn)了DecoratingProxy,則從代理類中獲取排序order
   if (order == null && obj instanceof DecoratingProxy) {
      return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
   }
   return order;
}

步驟7:OrderUtils方法

@Nullable
static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) {
    // 如果注解元素不是一個(gè)類烂斋,每次都從注解中獲取order
   if (!(element instanceof Class)) {
      return findOrder(annotations);
   }
    // 緩存中存在該類屹逛,從緩存中獲取排序
   Object cached = orderCache.get(element);
   if (cached != null) {
      return (cached instanceof Integer ? (Integer) cached : null);
   }
    // 緩存不存在,就重新解析汛骂,并保存到緩存中
   Integer result = findOrder(annotations);
   orderCache.put(element, result != null ? result : NOT_ANNOTATED);
   return result;
}

@Nullable
private static Integer findOrder(MergedAnnotations annotations) {
    // 如果改元素上存在Order注解罕模,則返回value值
   MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
   if (orderAnnotation.isPresent()) {
      return orderAnnotation.getInt(MergedAnnotation.VALUE);
   }
    // 如果不存在Order注解,但是存在javax.annotation.Priority注解帘瞭,則返回該注解的value值
   MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);
   if (priorityAnnotation.isPresent()) {
      return priorityAnnotation.getInt(MergedAnnotation.VALUE);
   }
    // 如果注解都不存在手销,則返回null
   return null;
}

總結(jié):

兩個(gè)對(duì)象比較,排序規(guī)則調(diào)用判斷順序如下:

  1. 其中有一個(gè)實(shí)現(xiàn)了PriorityOrdered图张,則排序靠前锋拖,返回排序狀態(tài)诈悍。如果都沒(méi)有實(shí)現(xiàn)PriorityOrdered接口,或者都實(shí)現(xiàn)了PriorityOrdered接口兽埃,繼續(xù)往下執(zhí)行

  2. 分別獲取兩個(gè)對(duì)象的排序值侥钳,根據(jù)排序值確定排序狀態(tài)

  3. 如果實(shí)現(xiàn)了PriorityOrdered或者Ordered接口,調(diào)用getOrder方法返回排序值柄错。如果沒(méi)有實(shí)現(xiàn)這兩個(gè)接口或者getOrder方法返回null舷夺,繼續(xù)往下執(zhí)行

  4. 如果有Order注解,返回注解的value值作為排序值

  5. 如果有Priority注解售貌,返回value值作為排序值

  6. 如果都沒(méi)有给猾,返回最小排序值

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市颂跨,隨后出現(xiàn)的幾起案子敢伸,更是在濱河造成了極大的恐慌,老刑警劉巖恒削,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件池颈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钓丰,警方通過(guò)查閱死者的電腦和手機(jī)躯砰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)携丁,“玉大人琢歇,你說(shuō)我怎么就攤上這事∶渭” “怎么了矿微?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)尚揣。 經(jīng)常有香客問(wèn)我涌矢,道長(zhǎng),這世上最難降的妖魔是什么快骗? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任娜庇,我火速辦了婚禮,結(jié)果婚禮上方篮,老公的妹妹穿的比我還像新娘名秀。我一直安慰自己,他們只是感情好藕溅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布匕得。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汁掠。 梳的紋絲不亂的頭發(fā)上略吨,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音考阱,去河邊找鬼翠忠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛乞榨,可吹牛的內(nèi)容都是我干的秽之。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吃既,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼考榨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鹦倚,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤河质,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后申鱼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愤诱,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡云头,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年捐友,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溃槐。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匣砖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昏滴,到底是詐尸還是另有隱情猴鲫,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布谣殊,位于F島的核電站拂共,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏姻几。R本人自食惡果不足惜宜狐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛇捌。 院中可真熱鬧抚恒,春花似錦、人聲如沸络拌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)春贸。三九已至混萝,卻和暖如春遗遵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背譬圣。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工瓮恭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厘熟。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓屯蹦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親绳姨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子登澜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355