最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

最近因?yàn)橥耣ean配置的問(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)閟pring bean覆蓋的機(jī)制導(dǎo)致讀取的redis配置不是原來(lái)的。

總結(jié)起來(lái),有兩點(diǎn)問(wè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:

<?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);
 }

}

運(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)看到以下輸出

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覆蓋

spring bean覆蓋2

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

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

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

你確定嗎?不完全正確。

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

1.解析依賴(lài)

inject

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

bean1

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ù)屬性名裝配

bean2

優(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能夠通過(guò)屬性名注入不同的bean了。

總結(jié)

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

相關(guān)文章

  • java題解Leetcode 8字符串轉(zhuǎn)換整數(shù)

    java題解Leetcode 8字符串轉(zhuǎn)換整數(shù)

    這篇文章主要為大家介紹了java題解Leetcode 8字符串轉(zhuǎn)換整數(shù)實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Java全面深入探究SpringBoot攔截器與文件上傳

    Java全面深入探究SpringBoot攔截器與文件上傳

    攔截器對(duì)使用SpringMvc、Struts的開(kāi)發(fā)人員來(lái)說(shuō)特別熟悉,因?yàn)槟阒灰肴プ龊靡粋€(gè)項(xiàng)目必然會(huì)用到它,文件上傳是一個(gè)很常見(jiàn)的功能。在項(xiàng)目開(kāi)發(fā)過(guò)程中,我們通常都會(huì)使用一些成熟的上傳組件來(lái)實(shí)現(xiàn)對(duì)應(yīng)的功能
    2022-05-05
  • SpringBoot項(xiàng)目中Maven剔除無(wú)用Jar引用的最佳實(shí)踐

    SpringBoot項(xiàng)目中Maven剔除無(wú)用Jar引用的最佳實(shí)踐

    在?Spring?Boot?項(xiàng)目開(kāi)發(fā)中,Maven?是最常用的構(gòu)建工具之一,通過(guò)?Maven,我們可以輕松地管理項(xiàng)目所需的依賴(lài),而,隨著項(xiàng)目的復(fù)雜化,無(wú)用的?Jar?包引用可能會(huì)逐漸增多,本文旨在詳細(xì)解析如何在?Spring?Boot?項(xiàng)目中剔除無(wú)用的?Jar?引用,需要的朋友可以參考下
    2025-01-01
  • javaweb頁(yè)面附件、圖片下載及打開(kāi)(實(shí)現(xiàn)方法)

    javaweb頁(yè)面附件、圖片下載及打開(kāi)(實(shí)現(xiàn)方法)

    下面小編就為大家?guī)?lái)一篇javaweb頁(yè)面附件、圖片下載及打開(kāi)(實(shí)現(xiàn)方法)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Java使用Random類(lèi)生成隨機(jī)數(shù)示例

    Java使用Random類(lèi)生成隨機(jī)數(shù)示例

    這篇文章主要介紹了Java使用Random類(lèi)生成隨機(jī)數(shù),結(jié)合實(shí)例形式分析了java基于Random類(lèi)生成隨機(jī)數(shù)與遍歷輸出相關(guān)操作技巧,需要的朋友可以參考下
    2019-07-07
  • JWT 設(shè)置token過(guò)期時(shí)間無(wú)效的解決

    JWT 設(shè)置token過(guò)期時(shí)間無(wú)效的解決

    這篇文章主要介紹了JWT 設(shè)置token過(guò)期時(shí)間無(wú)效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 在idea中創(chuàng)建SpringBoot模塊的兩種方式

    在idea中創(chuàng)建SpringBoot模塊的兩種方式

    這篇文章主要介紹了在idea中創(chuàng)建一個(gè)SpringBoot模塊,本文給大家分享兩種方式,每種方式分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • Java后綴數(shù)組之求sa數(shù)組的實(shí)例代碼

    Java后綴數(shù)組之求sa數(shù)組的實(shí)例代碼

    后綴數(shù)組就是一個(gè)字符串所有后綴大小排序后的一個(gè)集合,然后我們根據(jù)后綴數(shù)組的一些性質(zhì)就可以實(shí)現(xiàn)各種需求。這篇文章主要介紹了Java后綴數(shù)組-求sa數(shù)組,需要的朋友可以參考下
    2018-04-04
  • Java 圖片壓縮實(shí)現(xiàn)思路及代碼

    Java 圖片壓縮實(shí)現(xiàn)思路及代碼

    本文為大家詳細(xì)介紹下圖片壓縮的具體實(shí)現(xiàn)思路及java代碼,想學(xué)習(xí)的各位可以參考下哈,希望對(duì)大家有所幫助
    2013-07-07
  • Spring Boot2.3 新特性分層JAR的使用

    Spring Boot2.3 新特性分層JAR的使用

    這篇文章主要介紹了Spring Boot2.3 新特性分層JAR的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06

最新評(píng)論

镇原县| 襄樊市| 东阿县| 南木林县| 象山县| 灌云县| 林甸县| 澄迈县| 绥芬河市| 竹北市| 灌云县| 康保县| 五台县| 策勒县| 左贡县| 镇坪县| 灵川县| 湄潭县| 农安县| 军事| 项城市| 阿图什市| 渝中区| 南靖县| 揭东县| 永川市| 航空| 岑溪市| 眉山市| 金塔县| 朝阳县| 沅江市| 焦作市| 南城县| 石阡县| 泸溪县| 高淳县| 麻城市| 闸北区| 山阴县| 和顺县|