一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - spring中bean id相同引發(fā)故障的分析與解決

spring中bean id相同引發(fā)故障的分析與解決

2021-01-09 14:28rhwayfunn Java教程

最近在工作中遇到了關(guān)于bean id相同引發(fā)故障的問(wèn)題,通過(guò)查找相關(guān)資料終于解決了,下面這篇文章主要給大家介紹了因?yàn)閟pring中bean id相同引發(fā)故障的分析與解決方法,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。

前言

最近因?yàn)橥?a href="/article/128006.html">bean配置的問(wèn)題導(dǎo)致生產(chǎn)環(huán)境往錯(cuò)誤的redis實(shí)例寫(xiě)入大量的數(shù)據(jù),差點(diǎn)搞掛redis。經(jīng)過(guò)快速的問(wèn)題定位,發(fā)現(xiàn)是同事新增一個(gè)redis配置文件,并且配置的redissentinelconfiguration的id是一樣的,然后在使用@autowired注入bean的時(shí)候因?yàn)?a href="/article/79719.html">spring bean覆蓋的機(jī)制導(dǎo)致讀取的redis配置不是原來(lái)的。

總結(jié)起來(lái),有兩點(diǎn)問(wèn)題:

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

代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class userclient {
 
 private userconfiguration configuration;
 
 public userclient(userconfiguration configuration) {
  this.configuration = configuration;
 }
 
 public string getcity() {
  return configuration.getcity();
 }
 
}

beans.xml:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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:

?
1
2
3
4
5
6
7
user1.id=1
user1.name=bean1
user1.city=hangzhou
 
user2.id=2
user2.name=bean2
user2.city=shanghai

applition:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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)致開(kāi)頭說(shuō)的問(wèn)題的源頭所在。要實(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í)例化完畢

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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]]

就是說(shuō)beans.xml中配置的userconfiguration被beans2.xml配置的userconfiguration實(shí)例覆蓋了。那么自然我們得到的結(jié)果是shanghai了。

spring bean覆蓋

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

spring中bean id相同引發(fā)故障的分析與解決

spring中bean id相同引發(fā)故障的分析與解決

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

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

bean覆蓋的問(wèn)題解決了,那么還有一個(gè)問(wèn)題,為什么使用@autowired注入userclient沒(méi)有報(bào)錯(cuò)呢,明明配置了兩個(gè)類型的bean啊。@autowired不是按照bytype注入的嗎。

你確定嗎?不完全正確。

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

1.解析依賴

spring中bean id相同引發(fā)故障的分析與解決

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

spring中bean id相同引發(fā)故障的分析與解決

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

spring中bean id相同引發(fā)故障的分析與解決

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

?
1
2
3
4
5
6
7
8
9
10
11
/**
  * 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能夠通過(guò)屬性名注入不同的bean了。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:http://blog.csdn.net/u011116672/article/details/78074246

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 九九精品国产兔费观看久久 | 国产永久免费爽视频在线 | 美国女网址www呦女 美国复古性经典xxxxx | 婷婷天天 | 午夜一区二区福利视频在线 | 99久久免费精品视频 | 我和么公的秘密小说免费 | 2019午夜福合集高清完整版 | 被夫上司强迫中文 | 亚洲免费在线看 | 糖心在线观看 | 久久99亚洲热最新地址获取 | 波多野结衣家庭教师 | 乌克兰粉嫩摘花第一次 | japonensis日本护士18 | voyeur多毛厕所 | 11 13加污女qq看他下面 | 久久精品亚洲牛牛影视 | 激情婷婷综合久久久久 | 91欧美国产 | 成人性生交大片免费看软件 | 精品精品国产自在久久高清 | 亚裔maricahase和黑人 | 嫩草在线视频www免费观看 | 好舒服好爽再快点视频 | 福利一区三区 | 精品日本一区二区 | 成年男女免费大片在线观看 | 亚洲大逼 | 明星裸乳照无奶罩 | 男男gaygays中国 | 四虎影库紧急大通知 | 俄罗斯图书馆无打码久久 | 无限在线看免费视频大全 | 成人操| 日本丰满www色 | 无码一区二区三区视频 | 99热在线这里只有精品 | 色欲麻豆国产福利精品 | 满溢游泳池免费土豪全集下拉版 | 国产yw193.㎝m在线观看 |