在最近的一次項目上線之后,遇到了大面積客戶,報告系統(tǒng)服務(wù)異常的情況.查看服務(wù)器的日志發(fā)現(xiàn)了空指針異常,發(fā)現(xiàn)是該類的所有注入的service都為null.但是無法在短時間快速的找到問題,并且修復,只能回滾本次上線代碼....
回滾之后,開始緊鑼密鼓的排查工作,一開始猜測是因為抽象類原因?qū)е伦⑷胧?雖然不太可能,因為之前都是正常運行的代碼),但是后來查閱資料發(fā)現(xiàn),spring在為bean注入屬性的時候,會將其父類的屬性也一并注入了,所以這里問題的產(chǎn)生和抽象類沒有關(guān)系.
因為實在沒有頭緒,只能開始排查本次上線的改動點,最后發(fā)現(xiàn)有一個點比較可疑,本次上線中增加了一個配置,在applicationContext.xml中增加了這樣一行配置.
當時這是為了解決注入失敗的問題而增加的配置(烏龍事件,注入類的時候,一個類不小心寫成了實現(xiàn)類,而非接口,導致jdk動態(tài)代理注入失敗),將動態(tài)代理強制改為了CGLIB.為了驗證猜想將配置去掉,發(fā)現(xiàn)注入成功,不再報錯(這里有個誤區(qū),一直以為是注入失敗的問題,導致排查問題走了很多彎路).問題已經(jīng)找到, 于是開始排查原因,排查過程不再贅述,這里直接說最后的原因.
CGLIB動態(tài)代理在創(chuàng)建代理的,會將靜態(tài)方法,final方法等排除在外.
這導致,cglib的代理根本不會去攔截final和靜態(tài)方法.在我們的項目中,調(diào)用的正是final方法
由于這個execute是final方法,所以cglib不會攔截.在spring中,cglib的代理最終執(zhí)行的方法,是通過被代理對象去執(zhí)行的(假設(shè)方法被攔截到的話),而被代理的對象中,這些注入的屬性都是有值的,所以執(zhí)行成功.而本例中,由于是final方法,不會被攔截,所以直接通過代理類對象本身去調(diào)用execute方法,而不是通過被代理對象去執(zhí)行,而問題就出在代理對象中的屬性是從來沒有被注入過的,所以出現(xiàn)了空指針的情況.問題到此已經(jīng)一清二楚.
僅作記錄!