SpringMVC conflicts with existing, non-compatible bean definition of same name and class 的解決辦法
問題起因
最近,專案組的裡的同事遇到一個問題,他自己負責的模組,SpringMVC的Controller與其他模組的Controller 類名重名了,導致整個工程都起不來了。
後臺報的錯誤是這樣的:
1 |
|
午飯時,他一直和我抱怨這個問題,還說找不到辦法。
後面我想了一下,SpringMVC的Controller 應該是採用類似鍵值對(key/value)的對映方式處理的。而當中的鍵,預設是用cotroller的類名(非全類名)作為鍵。這樣,如果不同包下面的兩個Contoller 重名的話,就會導致SpringMVC的容器管理中的controller map中的key重複了。
解決這個問題也比較簡單。
在@Controller 中,使用重名名就可以了
如 下例子:
test.controller.bill.BillSaveController
package test.controller.bill; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * Created by liuch on 5/27/15. */ @Controller @RequestMapping("/billsave") public class BillSaveController { @RequestMapping("/dosave") public String saveBill(){ return "billsave"; } }
及 test.controller.bill.BillSaveController
package test.controller.billsave; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * Created by liuch on 5/27/15. */ @Controller @RequestMapping("/billsave_test") public class BillSaveController { @RequestMapping("/test") public String test(){ return "test"; } }
上面這兩個程式碼雖然在不同的包下面,即全類名不同,但是類名卻是相同。
這樣,在Tomcat 啟動的時候,後臺會報錯:
SEVERE: Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/dispatcher-servlet.xml]; nested exception is java.lang.IllegalStateException: Annotation-specified bean name 'billSaveController' for bean class [test.controller.billsave.BillSaveController] conflicts with existing, non-compatible bean definition of same name and class [test.controller.bill.BillSaveController]
問題原因:
因為如果在使用註解 @Controller 時候,如果不使用命名,而SpringMVC會預設把類名的頭一個字母小寫,然後放到一個map中。
比如上面的例子,儘管上面兩個類全類名不同,但是他們使用了@Controller 註解的時候,都沒有使用命名。在SpringMVC在掃描Controller的時候,會把他們都預設解析為 billSaveController.然後以這個billSaveController為鍵(key), 放到一個全域性的map中。
這樣,就會出現兩個鍵完全一樣的Controller。由於SpringMVC不使用覆蓋的方式處理具有相同鍵的不同全類名的Controller,、掃描的時候就會包上面的錯誤。
解決的辦法:
在@Controller上使用名稱
如:test.controller.bill.BillSaveController中
package test.controller.bill; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * Created by liuch on 5/27/15. */ @Controller("testbillsave") @RequestMapping("/billsave") public class BillSaveController { @RequestMapping("/dosave") public String saveBill(){ return "billsave"; } }
test.controller.billsave.BillSaveController中,使用:
package test.controller.billsave; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * Created by liuch on 5/27/15. */ @Controller("realbillsave") @RequestMapping("/billsave_test") public class BillSaveController { @RequestMapping("/test") public String test(){ return "test"; } }
上面兩個Controller中,只要保證一個有命名即可,但是最好兩個都使用上。
這是一種良好的程式設計方式,因為你無法保證其他人不會使用和你一樣的類名的Controller。
後記:
下午讓同事試了一下,果然可以了。