您好,登錄后才能下訂單哦!
spring中bean與id出現相同而引發的故障如何解決?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
總結起來,有兩點問題:
代碼如下:
public class UserConfiguration { private int id; private String name; private String city; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } }
UserClient:
public class UserClient { private UserConfiguration configuration; public UserClient(UserConfiguration configuration) { this.configuration = configuration; } public String getCity() { return configuration.getCity(); } }
beans.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userConfiguration" class="com.rhwayfun.springboot.starter.rest.UserConfiguration"> <property name="id" value="${user1.id}"/> <property name="name" value="${user1.name}"/> <property name="city" value="${user1.city}"/> </bean> <bean id="userClient" class="com.rhwayfun.springboot.starter.rest.UserClient" autowire="byName"> <constructor-arg ref="userConfiguration"/> </bean> </beans>
beans2.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userConfiguration" class="com.rhwayfun.springboot.starter.rest.UserConfiguration"> <property name="id" value="${user2.id}"/> <property name="name" value="${user2.name}"/> <property name="city" value="${user2.city}"/> </bean> <bean id="userClient2" class="com.rhwayfun.springboot.starter.rest.UserClient"> <constructor-arg ref="userConfiguration"/> </bean> </beans>
application.properties:
user1.id=1 user1.name=bean1 user1.city=Hangzhou user2.id=2 user2.name=bean2 user2.city=Shanghai
Applition:
@SpringBootApplication public class Application{ @Autowired UserClient userClient2; @PostConstruct public void init() { String city = userClient2.getCity(); System.out.println(city); } public static void main(String[] args) throws InterruptedException { SpringApplication.run(Application.class, args); Thread.sleep(Long.MAX_VALUE); } }
運行程序,你會發現不管注入的userClient2還是userClient1,輸出的結果都是Shanghai。但是我們想實現的是,注入userClient1的時候輸出的應該是Hangzhou,注入userClient2的時候輸出的應該是Shanghai。這也是導致開頭說的問題的源頭所在。要實現這個效果很簡單,UserConfiguration換一個名字就可以了。
但是,為什么換個名字就可以了呢,不同spring配置文件相同bean id的bean為什么不會分別創建呢?原因就在于spring 對具有相同bean id的實例做了覆蓋處理。你可以理解為一個Map,key是bean id,value就是class,那么當兩次put相同id的bean的時候自然就被覆蓋了。
我們先回憶下bean的生命周期:
問題出在注冊bean定義的時候,我們可以控制臺看到以下輸出
Overriding bean definition for bean 'userConfiguration' with a different definition: replacing [Generic bean: class [com.rhwayfun.springboot.starter.rest.UserConfiguration]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [/Users/chubin/IdeaProjects/spring-boot-learning-examples/ spring-boot-starter-rest/target/classes/beans.xml]] with [Generic bean: class [com.rhwayfun.springboot.starter.rest.UserConfiguration]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [/Users/chubin/IdeaProjects/spring-boot-learning-examples /spring-boot-starter-rest/target/classes/beans2.xml]]
就是說beans.xml中配置的UserConfiguration被beans2.xml配置的UserConfiguration實例覆蓋了。那么自然我們得到的結果是Shanghai了。
spring bean覆蓋
經過上面的分析,我們已經知道是因為被覆蓋的導致的,那么怎么體現的呢?遇到解決不了的問題,看源碼往往能得到答案:
這段代碼的邏輯就是,如果不允許具有相同bean id的實例存在就拋出異常,而這個值默認是true,也就是允許存在相同的bean id定義。
@Autowired注解實現機制
bean覆蓋的問題解決了,那么還有一個問題,為什么使用@Autowired注入UserClient沒有報錯呢,明明配置了兩個類型的bean啊。@Autowired不是按照byType注入的嗎。
你確定嗎?不完全正確。
因為@Autowired是spring提供的注解,我們可以看到是如何注入的代碼,在AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement.inject()
方法中。
1.解析依賴
2.獲取候選bean、決定最終被被注入的最優bean
3.最優bean的決策過程:1)判斷時候有@Primary注解;2)如果沒有,得到最高優先級的bean,也就是是否有實現了org.springframework.core.Ordered
接口的bean(優先級比較,可以通過注解@Order(0)
指定,數字越小,優先級越高);3)如果仍然沒有,則根據屬性名裝配
優先級定義:
/** * Useful constant for the highest precedence value. * @see java.lang.Integer#MIN_VALUE */ int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; /** * Useful constant for the lowest precedence value. * @see java.lang.Integer#MAX_VALUE */ int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
至此,我們就能理解為什么@Autowired能夠通過屬性名注入不同的bean了。
關于spring中bean與id出現相同而引發的故障如何解決問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。