最近在做一些代碼安全性檢查,使用了Fortify。發現了一些曾經引以為豪的代碼既然會出現高危的錯誤。希望各位達人給予幫助。
         設計初衷:共享WebApplicationContext,通過getBean(String beanName)取得對應的bean處理相應的業務邏輯。
public class BaseAction extends Action {
    
private WebApplicationContext wac;
    
protected ServletContext context;    
    
public void setServlet(ActionServlet actionServlet) {
        
super.setServlet(actionServlet);
        context 
= actionServlet.getServletContext();
        wac 
= WebApplicationContextUtils.getRequiredWebApplicationContext(context);
    }


    
protected Object getBean(String beanName) {
        
return wac.getBean(beanName);
    }

}
      高危錯誤代碼:        
context = actionServlet.getServletContext();
        wac 
= WebApplicationContextUtils.getRequiredWebApplicationContext(context);
         錯誤原因分析:BaseAction繼承自Action,單例實現。該類含有屬性:wac與context,在多線程環境下不能保證這兩個屬性的合理邏輯。于是掉入了一個單例模式的陷阱。(請各位達人完善)
         解決方法:jdon(banq)給我的回復          
       
 banq:寫的方法是高危,但是看你的方法內容,則沒有關系。

你的方法內容是獲得一個Web項目的一個單例,實際就是Spring容器,而且大部分是讀,而不是讀寫并加。

單例陷阱我已經在以前帖子中說了,只有在單例+寫+同步等操作下才可能死鎖,因為代碼不可控性,今天你注意沒這么做,不代表其他無知的人不這么做,所以,這種singlton會被嚴謹的工具認為是高危,這是正確的。
 ME:謝謝 banq!
如果需要消除這段高危代碼,需要如何重構.
因為只是存在讀操作,我是否可以把wac與context定義為static(這樣工具不會報錯)

請問這樣改會不會有問題?
  banq:不能用static,這樣Spring容器中所有資源都不能隨著你的WEB項目消失而消失。

主要問題在于你的setServlet(ActionServlet actionServlet)這個方法,這其實是一個初始化工作,試驗在BaseAction的構造方法中首先實現,這樣表示有前有后,可能不會報高危錯誤。

實在不行,做一個懶加載的方法,在這個方法中,檢查一下wac是否為空,如果為,就進行初始化,不為空,就直接返回wac值。
去除setServlet方法,在getBean加入,如下,如果還不行,就每次老老實實的用WebApplicationContextUtils獲得Spring實例:

protected Object getBean(String beanName) {
if(wac==null){
context 
= actionServlet.getServletContext();
wac 
= WebApplicationContextUtils.getRequiredWebApplicationContext(context);
}


return wac.getBean(beanName);
}