這幾天有同事問到伊佃,在junit的一些資料中驶鹉,為什么不推薦使用@FixMethodOrder(MethodSorters.JVM)來做執(zhí)行方法排序轰驳。
對于這個(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測試時(shí)也提到過類似的問題(運(yùn)行時(shí)環(huán)境略有不同嘁信,是在J9上跑的,不過本質(zhì)上沒有什么差別)疏叨,因此把這個(gè)問題拿來總結(jié)一下潘靖,以下代碼為OpenJDK 8u最新版本。
由于函數(shù)內(nèi)容較長蚤蔓,以幾張關(guān)鍵代碼的圖來說明分析過程:
- 方法入口
image.png
- 這里訪問了k->methods()卦溢,->操作符在instanceKlassHandler中被重載了,看起來比較繞
image.png
- 真實(shí)調(diào)用的是
image.png
- set_methods在類加載的時(shí)候被調(diào)用
image.png
- 在set_methods之前秀又,有一個(gè)比較重要的地方单寂,對方法進(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í)的先后順序