spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決

spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決?針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

10年積累的成都做網(wǎng)站、成都網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有樂安免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

總結(jié)起來,有兩點(diǎn)問題:

  • 為什么相同bean id的bean會(huì)被覆蓋
  • @Autowired注解不是按照byType的方式進(jìn)行注入的嗎

代碼如下:

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:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>
<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:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>
<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);
 }

}

運(yùn)行程序,你會(huì)發(fā)現(xiàn)不管注入的userClient2還是userClient1,輸出的結(jié)果都是Shanghai。但是我們想實(shí)現(xiàn)的是,注入userClient1的時(shí)候輸出的應(yīng)該是Hangzhou,注入userClient2的時(shí)候輸出的應(yīng)該是Shanghai。這也是導(dǎo)致開頭說的問題的源頭所在。要實(shí)現(xiàn)這個(gè)效果很簡(jiǎn)單,UserConfiguration換一個(gè)名字就可以了。

但是,為什么換個(gè)名字就可以了呢,不同spring配置文件相同bean id的bean為什么不會(huì)分別創(chuàng)建呢?原因就在于spring 對(duì)具有相同bean id的實(shí)例做了覆蓋處理。你可以理解為一個(gè)Map,key是bean id,value就是class,那么當(dāng)兩次put相同id的bean的時(shí)候自然就被覆蓋了。

我們先回憶下bean的生命周期:

  1. 實(shí)例化
  2. 填充屬性
  3. 調(diào)用BeanNameAware的setBeanName方法
  4. 調(diào)用BeanFactoryAware的setBeanFactory方法
  5. 調(diào)用ApplicationContextAware的setApplicationContext方法
  6. 調(diào)用BeanPostProcessor的預(yù)初始化方法
  7. 調(diào)用InitializingBean的afterPropertiesSet方法
  8. 調(diào)用自定義的初始化方法
  9. 調(diào)用BeanPostProcessor的初始化方法
  10. 實(shí)例化完畢

問題出在注冊(cè)bean定義的時(shí)候,我們可以控制臺(tái)看到以下輸出

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實(shí)例覆蓋了。那么自然我們得到的結(jié)果是Shanghai了。

spring bean覆蓋

經(jīng)過上面的分析,我們已經(jīng)知道是因?yàn)楸桓采w的導(dǎo)致的,那么怎么體現(xiàn)的呢?遇到解決不了的問題,看源碼往往能得到答案:

spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決

spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決

這段代碼的邏輯就是,如果不允許具有相同bean id的實(shí)例存在就拋出異常,而這個(gè)值默認(rèn)是true,也就是允許存在相同的bean id定義。

@Autowired注解實(shí)現(xiàn)機(jī)制

bean覆蓋的問題解決了,那么還有一個(gè)問題,為什么使用@Autowired注入U(xiǎn)serClient沒有報(bào)錯(cuò)呢,明明配置了兩個(gè)類型的bean啊。@Autowired不是按照byType注入的嗎。

你確定嗎?不完全正確。

因?yàn)锧Autowired是spring提供的注解,我們可以看到是如何注入的代碼,在AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement.inject()方法中。

1.解析依賴

spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決

2.獲取候選bean、決定最終被被注入的最優(yōu)bean

spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決

3.最優(yōu)bean的決策過程:1)判斷時(shí)候有@Primary注解;2)如果沒有,得到最高優(yōu)先級(jí)的bean,也就是是否有實(shí)現(xiàn)了org.springframework.core.Ordered接口的bean(優(yōu)先級(jí)比較,可以通過注解@Order(0)指定,數(shù)字越小,優(yōu)先級(jí)越高);3)如果仍然沒有,則根據(jù)屬性名裝配

spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決

優(yōu)先級(jí)定義:

/**
  * 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了。

關(guān)于spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

網(wǎng)頁(yè)名稱:spring中bean與id出現(xiàn)相同而引發(fā)的故障如何解決
文章來源:http://muchs.cn/article36/jpigsg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、微信公眾號(hào)、定制開發(fā)、網(wǎng)站策劃、云服務(wù)器、營(yíng)銷型網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)