亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

最近因為同事bean配置的問題導致生產環(huán)境往錯誤的redis實例寫入大量的數據,差點搞掛redis。經過快速的問題定位,發(fā)現是同事新增一個redis配置文件,并且配置的RedisSentinelConfiguration的id是一樣的,然后在使用@Autowired注入bean的時候因為spring bean覆蓋的機制導致讀取的redis配置不是原來的。

總結起來,有兩點問題:

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

代碼如下:

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

}

運行程序,你會發(fā)現不管注入的userClient2還是userClient1,輸出的結果都是Shanghai。但是我們想實現的是,注入userClient1的時候輸出的應該是Hangzhou,注入userClient2的時候輸出的應該是Shanghai。這也是導致開頭說的問題的源頭所在。要實現這個效果很簡單,UserConfiguration換一個名字就可以了。

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

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

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

問題出在注冊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覆蓋

經過上面的分析,我們已經知道是因為被覆蓋的導致的,那么怎么體現的呢?遇到解決不了的問題,看源碼往往能得到答案:

spring bean覆蓋

spring bean覆蓋2

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

@Autowired注解實現機制

bean覆蓋的問題解決了,那么還有一個問題,為什么使用@Autowired注入UserClient沒有報錯呢,明明配置了兩個類型的bean啊。@Autowired不是按照byType注入的嗎。

你確定嗎?不完全正確。

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

1.解析依賴

inject

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

bean1

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

bean2

優(yōu)先級定義:

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

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • Java之HashMap案例詳解

    Java之HashMap案例詳解

    這篇文章主要介紹了Java之HashMap案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-08-08
  • JVM虛擬機的執(zhí)行流程解析

    JVM虛擬機的執(zhí)行流程解析

    這篇文章主要介紹了JVM虛擬機的執(zhí)行流程圖解,Java虛擬機的啟動是通過引導類加載器創(chuàng)建一個初始類來完成的,這個類是由虛擬機的具體實現指定的,程序開始執(zhí)行時他才運行,程序結束時他就停止,需要的朋友可以參考下
    2023-08-08
  • SpringData如何通過@Query注解支持JPA語句和原生SQL語句

    SpringData如何通過@Query注解支持JPA語句和原生SQL語句

    這篇文章主要介紹了SpringData如何通過@Query注解支持JPA語句和原生SQL語句,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • synchronized底層實現原理

    synchronized底層實現原理

    這篇文章主要介紹了synchronized底層實現原理,想弄懂它的實現synchronized的原理,我們只能通過看編譯好的字節(jié)碼文件,下面文章的詳細內容,我們就先從測試類開始吧,需要的小伙伴可以參考一下
    2022-01-01
  • 分享Java性能調優(yōu)的11個實用技巧

    分享Java性能調優(yōu)的11個實用技巧

    這些建議中的大多數都是基于Java的,但是也不一定,也有一些是可以應用于所有的應用程序和編程語言的。在我們分享基于Java的性能調優(yōu)技巧之前,讓我們先討論一下這些通用的性能調優(yōu)技巧
    2017-11-11
  • spring+hibernate 兩種整合方式配置文件的方法

    spring+hibernate 兩種整合方式配置文件的方法

    本篇文章主要介紹了spring+hibernate 兩種整合方式配置文件的方法,主要有兩種方式 1、注解方式 2、xml方式實現,有興趣的可以了解一下。
    2017-04-04
  • 全面總結java IO體系

    全面總結java IO體系

    這篇文章主要介紹了java IO體系的全面總結,下面和小編來一起學習一下吧
    2019-05-05
  • Java模板動態(tài)生成word文件的方法步驟

    Java模板動態(tài)生成word文件的方法步驟

    最近項目中需要根據模板生成word文檔,模板文件也是word文檔。本文使用使用freemarker模板生成word文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Spring定時任務關于@EnableScheduling的用法解析

    Spring定時任務關于@EnableScheduling的用法解析

    這篇文章主要介紹了Spring定時任務關于@EnableScheduling的用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • spring mvc @PathVariable綁定URI模板變量值方式

    spring mvc @PathVariable綁定URI模板變量值方式

    這篇文章主要介紹了spring mvc @PathVariable綁定URI模板變量值方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評論