新聞中心
最近,很多小伙伴出去面試,感覺自己面的不是很理想,回來后,不少小伙伴把面試題做了記錄發(fā)給我,讓我給大家解析下,然后發(fā)出來。當(dāng)我看到這些面試題時,快速在腦海中構(gòu)建起了整個知識體系,從基礎(chǔ)到框架、從分布式到微服務(wù),從數(shù)據(jù)結(jié)構(gòu)到算法,從虛擬化到云原生,從大數(shù)據(jù)到云計算,從實戰(zhàn)項目到性能調(diào)優(yōu)。其實,這些面試本質(zhì)上不難,很多都是對于基礎(chǔ)知識的考察。

公司主營業(yè)務(wù):網(wǎng)站設(shè)計、成都網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出鐵東免費做網(wǎng)站回饋大家。
今天開始,我們就來一一突破這些大廠的面試題,好了,開始今天的正文。
問題:
正如題目所說:Spring IOC容器中只存放單例Bean嗎?
先給出結(jié)論吧
這里,想來想去,我還是直接了當(dāng)?shù)恼f吧:是的,Spring IOC容器中只存放單例Bean。接下來,且聽我細細道來為哈只存放單例Bean。
問題分析
既然,我們已經(jīng)知道Spring IOC容器中只存放單例Bean,但是在面試的時候不能只說這一句話呀,否則,面試官就會把你直接Pass掉。為啥?如果你只說這一句話,面試官可能就會認(rèn)為你是懵的,而且懵對的概率為50%,如果你懵錯了,面試官認(rèn)為你不會,如果你懵對了,面試官有可能也會認(rèn)為你不會。所以,除了答對結(jié)論之外,還要清晰的說出Spring IOC容器中為啥只存放單例Bean。
好了,我們正式開始分析這個問題。
IOC容器初始化的時候,會將所有的bean初始化在singletonObjects這個ConcurrentHashMap中, bean是單例的。
在獲取bean的時候,首先會從singletonObjects去取,通過debug,發(fā)現(xiàn)如果scope是單例,則可以獲取到bean,如果scope是多例,則獲取不到bean,需要從一個叫mergedBeanDefinitions的ConcurrentHashMap中去獲取bean的定義,然后再根據(jù)bean的scope去決定如何創(chuàng)建bean,如果scope=prototype,則每次都會創(chuàng)建一個新的實例。
這里,我們可以大概得出這樣的結(jié)論:
IOC在初始化時,只會將scope= singleton(單例)的對象進行實例化,而不會去實例化scope=prototype的對象(多例)。
接下來,我們就來debug一下Spring的源碼。
首先,我們創(chuàng)建一個用于測試作用域為多例,獲取不同實例的Person類,如下所示。
- public class Person {
- @Value("張三")
- private String name;
- @Value("#{20-2}")
- private Integer age;
- @Value("${person.nickName}")
- private String nickName;
- public Person() {
- }
- public Person(String name, Integer age) {
- this.name = name;
- this.age = age;
- }
- //省略get/set
- }
接下來,創(chuàng)建一個MainConfig類,如下所示。
- @Configuration
- public class MainConfig {
- @Bean("person")
- @Scope("prototype")
- public Person person(){
- System.out.println("給容器中添加Person...");
- return new Person("張三", 25);
- }
- }
可以看到,此時MainConfig測試的是作用域為多例,獲取不同實例的場景。而如果要想測試作用域為單例,獲取相同實例的場景,則只需要將MainConfig類中的person()方法上的 @Scope("prototype")注解去掉即可,如下所示。
- @Configuration
- public class MainConfig {
- @Bean("person")
- public Person person(){
- System.out.println("給容器中添加Person...");
- return new Person("張三", 25);
- }
- }
接下來,再編寫一個main方法用于啟動測試程序。
- public static void main(String[] args){
- ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
- Person person = applicationContext.getBean(Person.class);
- Person person2 = applicationContext.getBean(Person.class);
- if(person.equals(person2)){
- System.out.println("同一個實例");
- }else{
- System.out.println("不同的實例");
- }
- }
啟動程序,開始debug測試單例情況。
調(diào)試單例作用域
經(jīng)過debug調(diào)試,在單例情況下,首次從singletonObjects 這個Map中獲取的bean為空,以后每次獲取時,從singletonObjects這個Map中獲取的bean就不為空了,會直接返回從這個Map中獲取的值。
第一次從singletonObjects 中獲取值的情況如下所示。
第二次再從singletonObjects這個Map中獲取的bean就不為空了。
此時,命令行會打印同一個實例。
說明單例作用域下,每次共用一個bean實例,并且這個bean實例是被保存到容器中的。
調(diào)試多例作用域
如果是多例情況,則外界無論獲取多少個bean,從singletonObjects 這個Map中都獲取不到對應(yīng)的bean實例,每次都需要新建一個bean返回。
通過調(diào)試源碼,可以發(fā)現(xiàn),當(dāng)bean是多例時,每次都會從一個叫做 mergedBeanDefinitions 的HashMap中獲取一個RootBeanDefinition對象,里面包含了bean的一些基礎(chǔ)信息,如下所示。
接下來,再根據(jù)bean的scope屬性來做處理,如果作用域是單例,則直接從容器中獲取,如果作用域是多例,則每次會創(chuàng)建一個實例。
此時,命令行會打印出不同的實例。
說明多例作用域下,每次都會創(chuàng)建一個bean實例并返回。
綜上所述:Spring IOC容器中只存放單例Bean。
本文轉(zhuǎn)載自微信公眾號「冰河技術(shù)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系冰河技術(shù)公眾號。
分享名稱:頭條一面:Spring IOC容器中只存放單例Bean嗎?
文章起源:http://www.5511xx.com/article/dhhodgc.html


咨詢
建站咨詢
