這幾天有同事問到,在junit的一些資料中,為什么不推薦使用@FixMethodOrder(MethodSorters.JVM)來做執(zhí)行方法排序。
對(duì)于這個(gè)問題,API中的說法如下:
/**
* Leaves the test methods in the order returned by the JVM.
* Note that the order from the JVM may vary from run to run
*/
也就是說在每次被加載運(yùn)行時(shí),順序是不確定的。
稍做一下分析,可以看出這個(gè)問題本質(zhì)上是Class類中
getDeclaredMethods0這個(gè)本地方法返回的順序問題。
private native Method[] getDeclaredMethods0(boolean publicOnly);
之前某項(xiàng)目在做webservice測(cè)試時(shí)也提到過類似的問題(運(yùn)行時(shí)環(huán)境略有不同,是在J9上跑的,不過本質(zhì)上沒有什么差別),因此把這個(gè)問題拿來總結(jié)一下,以下代碼為OpenJDK 8u最新版本。
由于函數(shù)內(nèi)容較長(zhǎng),以幾張關(guān)鍵代碼的圖來說明分析過程:
- 方法入口

image.png
- 這里訪問了k->methods(),->操作符在instanceKlassHandler中被重載了,看起來比較繞

image.png
- 真實(shí)調(diào)用的是

image.png
- set_methods在類加載的時(shí)候被調(diào)用

image.png
- 在set_methods之前,有一個(gè)比較重要的地方,對(duì)方法進(jìn)行了排序,這個(gè)順序決定了最終的返回結(jié)果

image.png
- 關(guān)注一下method_comparator

image.png
- 最初以為是按照方法的name進(jìn)行排序,結(jié)論和之前的現(xiàn)象不符(如果按照name排序,那么肯定是固定的),后來發(fā)現(xiàn)name其實(shí)是一個(gè)Symbol

image.png
- 繼續(xù)關(guān)注上面的fast_compare函數(shù),排序邏輯如下

image.png
- 到這里基本可以解釋為什么MethodSorters.JVM是一個(gè)亂序了,這里比較的是地址,Symbol在傳統(tǒng)意義的c堆中分配,因此無法保證每次獨(dú)立運(yùn)行時(shí)的先后順序