1. 程式人生 > >SpringMVC conflicts with existing, non-compatible bean definition of same name and class 的解決辦法

SpringMVC conflicts with existing, non-compatible bean definition of same name and class 的解決辦法

問題起因

最近,專案組的裡的同事遇到一個問題,他自己負責的模組,SpringMVC的Controller與其他模組的Controller 類名重名了,導致整個工程都起不來了。

後臺報的錯誤是這樣的:

1

××Controller' for bean class [××ontroller] conflicts with existing, non-compatible bean definition of same name and class

午飯時,他一直和我抱怨這個問題,還說找不到辦法。

後面我想了一下,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。

後記:

下午讓同事試了一下,果然可以了。