驚了!這是一篇《IOC》說明書?
大家好,我是小菜,一個(gè)渴望在互聯(lián)網(wǎng)行業(yè)做到蔡不菜的小菜??扇峥蓜偅c(diǎn)贊則柔,白嫖則剛!死鬼~看完記得給我來個(gè)三連哦!

本文主要介紹
Spring的全面知識點(diǎn)如有需要,可以參考
如有幫助,不忘 點(diǎn)贊 ?
微信公眾號已開啟,小菜良記,沒關(guān)注的同學(xué)們記得關(guān)注哦!
說到Spring 你能想到什么?有經(jīng)歷過面試的小伙伴相信都會在面試的時(shí)候被問到 "談?wù)勀銓?Spring 的理解"。
對 Spring 的理解?那不就是個(gè)框架嘛,用來簡化代碼,提高開發(fā)效率的。話糙理不糙,事實(shí)卻是如此。但是想歸想,該回答還是得回答。那么 Spring 到底是什么?我們腦瓜子一閃而過!IOC、AOP 順口而出,如果你沒想到這兩個(gè)基本的概念,那么估計(jì)就得面試等通知了~
好了,既然 IOC、AOP 都已經(jīng)順口而出了,面試官估計(jì)想聽的也就這些,你如果扯出什么源碼之類的,面試官估計(jì)也該冒出冷汗了。

哈哈,說歸說,鬧歸鬧,當(dāng)然具體得看你面試的等級了!當(dāng)然你有底氣將源碼講好,那便是你的能耐了~
可以說不懂Spring ,基本上就可以不用去面試 Java 開發(fā)了。那么面試官問 Spring 會從哪些方面來問你呢?小菜大概整理如下:

看了這張圖,總感覺每個(gè)點(diǎn)都知道,但是讓你詳細(xì)針對某個(gè)點(diǎn)進(jìn)行深講,又不知從而說起?
Spring 可以說是我們開發(fā)中的核心,我們從 Spring 可以擴(kuò)展出了 SpringMVC、SpringBoot、SpringCloud

一篇文章想搞定 Spring 的所有知識點(diǎn),那有點(diǎn)天方夜譚了,飯要一口一口吃,技術(shù)要一點(diǎn)一點(diǎn)學(xué),學(xué)好 Spring 那就從 IOC 開始!
IOC 大法
聽到IOC這個(gè)詞,如果腦瓜子里沒有想到 "控制反轉(zhuǎn)",那就說明你真的不了解 IOC。控制反轉(zhuǎn) 不是一門技術(shù),而是一種設(shè)計(jì)思想。我們在以往的編程中如果需要一個(gè)類,一般是通過 new 的方式來創(chuàng)建一個(gè)類對象,而 IOC 的思想便是我們在 Spring 中只需要定義這個(gè)類,然后 Spring 就會自動的幫我們管理這些類,我們需要的時(shí)候只需要從這個(gè)容器獲取,而不用通過 new 的方式。

就好像這個(gè),如果我們想要購買蘋果或菠蘿,我們得單獨(dú)去購買,但是自從水果店的出現(xiàn)后我們就不用單獨(dú)購買,統(tǒng)一從水果店獲取即可
如果以上例子不能很好的理解這個(gè)概念,我們可以從代碼中分析:

看完以上的圖后,我們再來理解一下這一段話:IOC 的思想就是反轉(zhuǎn)資源獲取的方向,傳統(tǒng)的資源查找方式要求組件向容器發(fā)起請求查找資源,作為回應(yīng),容器適時(shí)地返回資源。而應(yīng)用了IOC之后,則是容器主動地將資源推送給他所管理的組件,組件所要做的僅是選擇一種合適的方式來接收資源,這種行為也被稱為查找的被動形式。
既然我們談到了 IOC 的概念,那就順便講下什么是 DI。
DI 是 IOC 另一種表述的方式:即組件以一些預(yù)先定義好的方式(setter, construct...)接收來自容器的資源注入,相對于 IOC 來說,這種表述更加直接。
看完以上,我們明白幾個(gè)概念:
誰依賴誰?
應(yīng)用程序依賴于 IOC 容器為什么需要依賴?
應(yīng)用程序需要IOC容器提供對象所需要的外部資源誰注入誰?
IOC容器向應(yīng)用程序注入外部資源注入了什么?
注入應(yīng)用程序所需要的外部資源(對象,資源,常量數(shù)據(jù)等)
㈠ 如何使用
① XML方式
讓我們來看下案例:
現(xiàn)有對象User:

我們傳統(tǒng)獲取對象的方式是這樣的:
User user = new User();
user.setName("小菜");
這種方式也挺簡單,直接通過 new 的方式來創(chuàng)建一個(gè)對象,傳統(tǒng)也直接。那么在 Spring 里面我們是怎么樣來獲取對象的呢?
我們先創(chuàng)建一個(gè)xml用來聲明 bean,那文件名就叫做 bean.xml 吧,內(nèi)容如下:

通過<bean>標(biāo)簽來聲明一個(gè)對象,用<property> 來聲明對象的屬性,獲取的方式也比較簡單:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
User user = ac.getBean("user1", User.class);
System.out.println(user);
通過 ApplicationContext 來獲取到這個(gè)對象,而且這種方法處處皆可用,獲取的的對象便是我們已經(jīng)定制好的User對象。
通過<property>注解聲明屬性的方式是基于屬性注入,在IOC依賴注入有三種方式:
屬性注入 構(gòu)造器注入 工廠方法注入(較少使用)
屬性注入我們上面已經(jīng)見識過了,那我們再來看下 構(gòu)造器注入 是怎么一回事
1. 構(gòu)造器注入

通過這種方式的注入,我們一樣能獲取到名稱為 小菜 的 User對象。
使用構(gòu)造器注入的方式,雖然也能很好的提供 Bean 對象,但是如果使用不恰當(dāng),那也是會踩坑的!小菜本著負(fù)責(zé)的態(tài)度,當(dāng)然要為小伙伴們指明道路~

我們現(xiàn)在看下 <constructor-org> 標(biāo)簽里面有哪些屬性:

value 我們已經(jīng)使用過了,就是用來表示注入的值
name 就是用來表明對象屬性的名稱
type 用來表明對象屬性的類型
index 用來表明改屬性在構(gòu)造函數(shù)中的位置,默認(rèn)從 0 開始計(jì)數(shù)

這不就是在說<constructor-org> 的用法嗎,哪里出現(xiàn)坑了,我看是小菜在坑人才是~莫急莫急, 坑這就來了!咱們來看一下新的User 對象:

對象當(dāng)然沒什么問題,該有的構(gòu)造函數(shù)也有。我們來試一下構(gòu)造一個(gè) 名為小菜,年齡23 的用戶對象吧,一頓操作之下:
<bean id="user3" class="cbuc.life.ioc.User">
<constructor-arg value="小菜"/>
<constructor-arg value="23"/>
</bean>
你看上去沒啥問題,我看上去也沒啥問題,但問題它就來了:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
User user = ac.getBean("user3", User.class);
System.out.println(user);
/** OUTPUT:
* User(name=小菜, salary=23.0)
*/
這尼瑪傻眼了,使用的人看到?jīng)]為年齡賦值,還以為是創(chuàng)建一個(gè) 名為小菜,工資23的用戶對象。解決的方法上面也說了,具體怎么用呢?
<bean id="user4" class="cbuc.life.ioc.User">
<constructor-arg value="小菜"/>
<constructor-arg value="23" type="int"/>
</bean>
這樣就可以避免復(fù)制錯誤的尷尬。如果你跟我說那 salary 也是 int 類型的怎么辦,那就可以借助 name 了
<bean id="user4" class="cbuc.life.ioc.User">
<constructor-arg value="小菜"/>
<constructor-arg value="23" type="int" name="age"/>
</bean>
那如果一個(gè)構(gòu)造函數(shù)中既有 age 又有 salary ,我們又可以這樣做:
public User(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
這種情況我們還可以用到 index 這個(gè)屬性:
<bean id="user5" class="cbuc.life.ioc.User">
<constructor-arg value="小菜"/>
<constructor-arg value="23" index="1"/>
<constructor-arg value="2000" index="2"/>
</bean>
這樣子我們就可以獲取到想要的 User 對象了:
User(name=小菜, age=23, salary=2000)
唉,真麻煩,用這種方式創(chuàng)建出來的對象還不如我 new 出來的香。頓時(shí)對 Spring 產(chǎn)生了質(zhì)疑的態(tài)度

等等等等,貼心的小菜又來了,簡單給你說下另外一種創(chuàng)建的方法,那就是借助 注解 的方式。真是個(gè)渣男,用到時(shí)候美滋滋,創(chuàng)建的時(shí)候就抱怨這抱怨那的~ 已經(jīng)給你提前劇透還有注解的方式了,那就讓小菜把剩下的 XML 講完吧,畢竟小菜絕不始亂終棄,拒做渣男~
2. 字面值
XML 的使用中還支持 字面值 的使用,你要問我什么是 字面值?那我們只能問你在 Mybatis 的xml配置文件中有沒有見過<![CDATA[<Value>]] 這種寫法,你要是還跟我說沒有,那小菜就要考慮是否再出一期 Mybatis 的講解了~ 話不多說,先看使用吧:
我們來創(chuàng)建一個(gè)名為 Cbuc.~!<> 的特殊用戶,這么特殊的名稱那肯定得用特殊的方式了

結(jié)果是成功創(chuàng)建也成功獲取了~
3. 內(nèi)部Bean
什么是內(nèi)部類,那就是我私生的孩子不想讓別人發(fā)現(xiàn)!當(dāng)然有時(shí)候也可以讓別人發(fā)現(xiàn)~ 但是如果我在 XML 創(chuàng)建的過程中創(chuàng)建的類不想被人引用該怎么辦,那當(dāng)然也是有的辦了:

簡單發(fā)現(xiàn)三件事,第一件:對象成功創(chuàng)建也成功獲取了(廢話) 第二件:<bean> 的建立是在 <property> 屬性里的(這才符合內(nèi)部類) 第三件:<bean> 內(nèi)部建立沒有ID 這個(gè)屬性(都不想讓別人引用,要 ID 有何用)
如果你不想自己創(chuàng)建一個(gè) Address 對象,而是想要別人的,然后自己再改一改也能用,這簡單也說就是想白嫖,雖然說也行~

用技術(shù)可以白嫖,學(xué)技術(shù)不可白嫖
關(guān)注VX:小菜良記
每篇都是初戀的味道~
4. 集合屬性賦值
除了上面我們可以給基本類型和String 賦值之外,還可以給 List/Map 這些賦值,用法如下:
我們在 User 類中添加了幾個(gè)新屬性:
private List<String> phoneList;
private List<Address> addressList;
private Map<String, String> animalMap;

如果你覺得包一層<property> 有寫礙事,那么也不要緊,盡量滿足你的要求!p 命名空間 它來了~

盡管對集合屬性不好復(fù)制也可以借助 <util:map /> 或 <util:list /> 來幫助。真是 Spring 一點(diǎn)一點(diǎn)變好,而你一點(diǎn)一點(diǎn)變渣,現(xiàn)在是不是腦子還想著怎么使用注解 的方式來開發(fā)~

你以為結(jié)束了,卻只是過半!通過 XML 我們甚至可以看到繼承關(guān)系,驚不驚喜意不意外~
5. Bean 的繼承

我們直接通過 parent 屬性來指明父類對象,然后再給自己其他屬性賦值。說到這里,我們就再提一嘴,有一個(gè) abstract 屬性,看單詞就知道抽象的意思,但是卻起到 Java中 接口的作用,用處便是添加這個(gè)屬性并設(shè)為 true ,那么它的工作就是專門 “生孩子” ,也就是變成了一個(gè) 配置模板,只能作為其他 Bean 的模板,而不能被 Spring 實(shí)例化。

配置了這個(gè)屬性,我們要再想通過 Spring容器獲取,就會拋出以下錯誤:

6. 生命周期
如果我們有點(diǎn)屬性 Bean 的生命周期,那么應(yīng)該對 init 和 destory 兩個(gè)方法有些熟悉,那就是在 Bean 創(chuàng)建和銷毀的時(shí)候執(zhí)行的方法,我們同樣可以在 XML 配置 Bean 的時(shí)候指出。
在 User 對象中我們有個(gè) initMethod() 和 destroyMethod() 方法,然后在構(gòu)建 Bean 的時(shí)候指明:

然后從控制臺中可以看到初始化方法執(zhí)行了:

講到這里XML 的配置方式也講的差不多了,那就如你所愿,看看注解的方式吧~
② 注解方式
1. @Configuration
通過注解的方式創(chuàng)建Bean,我們需要用到兩個(gè)注解@Configuration和 @Bean,用法如下:
創(chuàng)建一個(gè)BeanConfig 的配置類,然后通過 AnnotationConfigApplicationContext 獲取該類

這種方法就很美滋滋,去除了 XML文件的配置,感覺方便了不少,嘴角也露出迷人的微笑。
注解的方式簡單而強(qiáng)大, 讓人不勝向往!接下來歡迎來到注解新天地,導(dǎo)游小菜~

我們在上面見識到了 @Configuration 和 @Bean 兩個(gè)注解,這兩個(gè)注解的使用幫我們很好的構(gòu)建和獲取bean 的過程。那我們就從認(rèn)識這兩個(gè)注解開始!
@Configuration & @Bean
這個(gè)注解用在類上,作用于xml配置文件一致,向Spring表明這是一個(gè)配置類。配合 @Bean 可以初始化自定義Bean
那我們有時(shí)候會不會只想要一個(gè)默認(rèn)的 Bean,不需要定制化,當(dāng)然用上面的方式我們也能很好的實(shí)現(xiàn):
@Configuration
public class BeanConfig {
@Bean
public User getDefaultUser() {
return new User();
}
}
2. @ComponentScan
但是如果一兩個(gè) Bean,我們這樣子做還可以接受,當(dāng) Bean 的數(shù)量多起來估計(jì)又會抱怨了~
解決方法又來了,那就是 包掃描,何為 包掃描?那就是我們掃描指定包下的實(shí)體類,然后將其注冊到Spring容器中,這個(gè)方法實(shí)在是秒啊~那如何實(shí)現(xiàn)呢?借助@ComponentScan注解:

該有的注解@ComponentScan有了,但是好像還有個(gè)陌生的注解 @Component 。其實(shí)這里不止可以用 @Component 還可以用 **@Controller、@Repository、@Service ... ** 這些注解,這些注解的共同點(diǎn)就是把標(biāo)記了這些注解的類納入Spring容器中進(jìn)行管理。但是單單標(biāo)記這些注解還不夠,還需要我們上面說的 @ComponentScan 這個(gè)注解的配合,它告訴Spring 哪個(gè)packages下用注解標(biāo)識的類會被spring自動掃描并且裝入bean容器。
ComponentScan是個(gè)強(qiáng)大的注解,我們一起看下這個(gè)注解里面有哪些屬性:
basePackages :指明要掃描的包
**excludeFilters = Filter[] **:指明掃描的時(shí)候按照什么規(guī)則來排除其他組件
includeFilters = Filter[]:指明掃描的時(shí)候按照什么規(guī)則來只獲取需要的組件

從上圖中我們可以看到這個(gè)注解的簡單用法,我們想要的結(jié)果是注入cbuc.life.ioc 包下的使用注解@Component 標(biāo)注的類,如果使用@Controller 注解標(biāo)注的類,則不注入。
在Filter 中我們還看到一個(gè)枚舉類:FilterType,里面有這些屬性:
FilterType.ANNOTATIONl:按照注解
FilterType.ASSIGNABLE_TYPE :按照給定的類型
FilterType.ASPECTJ:按照 ASPECTJ 表達(dá)式
FilterType.REGEX:按照正則表達(dá)式
FilterType.GUSTOM:按照自定義規(guī)則
這里我們重點(diǎn)認(rèn)識下 FilterType.GUSTOM 這個(gè)過濾定義規(guī)則,它支持我們自定義過濾規(guī)則,自定的規(guī)則類需要實(shí)現(xiàn)TypeFilter:



通過這個(gè)我們自定義的規(guī)則, 可以完美的將 Person 這個(gè)類放入Spring容器中,而 UserController 這個(gè)類卻沒有放置。
如果我們需要定義多個(gè) @ComponentScan ,我們可以借助@ComponentScans 將它們組合起來:
@ComponentScans(value = {@ComponentScan(),@ComponentScan()})
3. @Scope & @Lazy
我們在 User 對象的構(gòu)造函數(shù)中寫上這樣一行代碼,表示被使用的時(shí)候,會提示我們它被創(chuàng)建了:
public User() {
System.out.println("User 對象被創(chuàng)建了");
}
當(dāng)我們在代碼中使用它的時(shí)候:
@Configuration
@ComponentScan(basePackages = "cbuc.life.ioc")
public class BeanConfig {
@Bean
public User getUser() {
User user = new User();
user.setName("小菜");
user.setAge(23);
user.setSalary(2000);
return user;
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
}
}
這個(gè)時(shí)候我們在控制臺看到的內(nèi)容是這樣的:

這說明了什么?說明了IOC容器啟動后會調(diào)用方法創(chuàng)建對象放到IOC容器中,以后每次獲取都是直接從容器中拿。那么相當(dāng)于在程序的整個(gè)生命周期中,每個(gè)地方用到的 Bean 都是同一個(gè)!這種稱為單例模式。單例模式的好處相信大家也不陌生,最顯而易見的有點(diǎn)便是節(jié)約了系統(tǒng)資源,不需要頻繁創(chuàng)建和銷毀對象。但是有些情況下我們不想要單例模式,那種時(shí)候,Spring當(dāng)然也支持你修改Bean的作用域!那就是借助 @Scope 注解。我們先知道一下Spring中存在幾種Bean的作用域,才能更好的切換~
singleton:bean在每個(gè)SpringIOC容器中都只有一個(gè)實(shí)例 (默認(rèn)作用域) protorype:一個(gè)bean的定義可以有多個(gè)實(shí)例 request::每次 http 請求都會創(chuàng)建一個(gè) bean。該作用域僅在基于web的Spring ApplicationContext 情形下有效 session:在一個(gè) http session 中,一個(gè)bean定義對應(yīng)一個(gè)示例。該作用域僅在基于web的SpringApplicationContext 情形下有效 global-session:在一個(gè)全局的 http session 中,一個(gè)bean定義對應(yīng)一個(gè)示例。該作用域僅在基于web的SpringApplicationContext情形下有效
存在了5中作用域,如果我們想要切換作用域,那么只需要在@Scope上指明即可:

使用了prototype這種方式,IOC容器啟動的時(shí)候不會創(chuàng)建對象,只用當(dāng)使用到的時(shí)候才會創(chuàng)建對象
在單例中,有一種懶漢式加載,這里當(dāng)然也是支持的,只需一個(gè)@Lazy注解

這樣子盡管使用的單例模式,但是IOC容器啟動時(shí)也不會創(chuàng)建對象,只有需要的時(shí)候才會創(chuàng)建
4. @Conditional
condition 的意思是條件,那么這個(gè)注解的用處便是 按照一定的條件進(jìn)行判斷,滿足條件后再給容器中注冊Bean
這里簡單寫個(gè)例子,
MyCondition:

使用:

通過這種方式,如果是windows操作系統(tǒng)則注入U(xiǎn)ser對象,反之不注入。
5. @Import
我們回顧一下給容器中注冊組件的幾種方式,閉眼想一想~ 好了,小菜來給你復(fù)習(xí)一下:
包掃描+組件標(biāo)注注解 (@Controller 、@Service、@Repository 、@Component)
在配置類中通過 @Bean 注冊
除了上面的兩種,我知道你是難以滿足的,那么就再來一種!那就是@Import的方式
使用方式有三種,下面我們一一介紹:
1)@Import(要導(dǎo)入到容器中的組件)

2)ImportSelector(返回需要導(dǎo)入的組件的全類名數(shù)組)
我們需要編寫自定義的 ImportSelector :

然后在@Import 注解中引入:

3)ImportBeanDefinitionRegistrar(手動注冊bean到容器中)
這個(gè)類就比較有意思,有些因果的味道~同樣的我們需要自定義 ImportBeanDefinitionRegistrar

然后在@Import 注解中引入:

通過上面3種@Import的用法,是否意識到了Spring的強(qiáng)大,它仿佛處處為我們著想,我們想要的不想要的,它全都有!
別急!還有~
6. @Value
這個(gè)注解是給參數(shù)賦值的,用幾種比較強(qiáng)大的用法:
基本數(shù)值賦值 支持 SPEL 寫法 可以用 ${}取出配置文件中的值

7. @Autowired & @Qualifier
此注解用于bean的field、setter方法以及構(gòu)造方法上,顯式地聲明依賴。
默認(rèn)優(yōu)先按照類型去容器中找對應(yīng)的組件:applicationContext.getBean(User.class),如果找到多個(gè)相同類型的組件,就會將屬性的名稱作為組件的ID再去容器中查找:applicationContext.getBean("user"),我們也可以使用 @Qualifier 來指定裝配組件的ID,而不是使用屬性名:

@Autowired 自動裝配的時(shí)候默認(rèn)一定要將屬性賦好值,否則就會報(bào)錯。不過我們可以使用required = false 讓自動裝配允許使用空裝配:
@Autowired(required = false)
@Qualifier("userController")
private UserController userController;
用于 Field 上:
@Component
class Book{
@Autowired
private Address address;
}
用于 **setter()**方法上:
@Component
class Book{
private Address address;
@Autowired
public void setAddress(Address address) {
this.address = address;
}
}
用于構(gòu)造函數(shù)上:
@Component
class Book{
private Address address;
public Book(Address address) {
this.address = address;
}
}
這種方式需要注意的是一個(gè)類中只允許有一個(gè)構(gòu)造方法使用此注解。此外,在Spring4.3之后,如果一個(gè)類僅僅只有一個(gè)構(gòu)造方法, 那么即使不使用此注解,Spring也會自動注入相關(guān)的Bean
8. @Profile
Spring 為我們提供@Profile,可以指定組件在哪個(gè)環(huán)境的情況下才能被注冊到容器中
加了環(huán)境標(biāo)識的bean,只有這個(gè)環(huán)境被激活的時(shí)候才能注冊到容器中。默認(rèn)是default環(huán)境 寫在配置類上,只有是指定的環(huán)境的時(shí)候,整個(gè)配置類里面的所有配置才能開始生效 沒有標(biāo)注環(huán)境標(biāo)識的bean,在任何環(huán)境下都是加載的

㈡ IOC 容器
上面如何使用是講的差不多了,你學(xué)到了多少呢~ 那你在學(xué)的過程中有沒有一個(gè)問號一直在。那就是為啥能通過 ApplicatinContext 來獲取到 Spring 中構(gòu)建的 Bean 呢?。
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
User user = ac.getBean("user4", User.class);
IOC 容器其實(shí)就是一個(gè)大工廠,它用來管理我們所有的對象以及依賴關(guān)系
原理簡單來說就是三步:
Ⅰ:通過 Java 反射技術(shù)獲取類的所有信息
Ⅱ:再通過配置文件(
XML) 或 注解(Annoation) 來描述類與類之間的關(guān)系Ⅲ:結(jié)合上面兩步獲取到的信息就可以構(gòu)建出對應(yīng)的對象之間的依賴關(guān)系

在 Spring IOC 容器讀取 Bean 的配置創(chuàng)建 Bean 之前,必須對它進(jìn)行實(shí)例化,只有在容器實(shí)例化后,才可以從 IOC 容器里面獲取到 Bean 實(shí)例并使用。
那么 Spring 中提供了兩種類型的 IOC 容器實(shí)現(xiàn):
BeanFactory :IOC 容器的基本實(shí)現(xiàn) ApplicationContext:提供了更多的高級特性,是 BeanFactory 的子接口
BeanFactory 是 Spring 框架的基礎(chǔ)設(shè)施,面向 Spring 本身,ApplicationContext 是面向 Spring 框架的開發(fā)者,幾乎所有的應(yīng)用場景都直接用 ApplicationContext 而非底層的 BeanFactory。

通過繼承圖可以看到 ApplicationContext 又有兩個(gè)子類 ClassPathXmlApplicationContext 和 AnnoationConfigApplicationContext ,當(dāng)然實(shí)際遠(yuǎn)遠(yuǎn)不止這些,我們上面用 XML 的方式是用到 ClassPathXmlApplicationContext ,而用注解的方式是用到 AnnoationConfigApplicationContext 。
那么為什么使用 ApplicationContext 而不是 BeanFactory ,我們就先來看看兩者的區(qū)別:
ApplicationContext能夠利用反射技術(shù)自動識別出配置文件中定義的 BEANPostProcessor、InstantiationAwareBeanPostProcessor、BeanFactoryPostProcessor ,并自動將它們注冊到應(yīng)用上下文中,而BeanFactory需要在代碼中通過手動調(diào)用 **addBeanFatoryPostProcessor()**方法進(jìn)行注冊。ApplicationContext在初始化應(yīng)用上下文的時(shí)候就實(shí)例化了所有但實(shí)例的Bean,而BeanFactory在初始化容器的時(shí)候并為實(shí)例化 Bean,直到第一次訪問某個(gè)Bean時(shí)才實(shí)例化目標(biāo) Bean
那么我們可以繼續(xù)看下Bean的初始化過程:

㈢備戰(zhàn)面試
以上那些內(nèi)容相信已經(jīng)為你儲備了不少知識干糧了,對于開發(fā),對于面試,相信你也已經(jīng)摩拳擦掌了!既然已經(jīng)準(zhǔn)備好了,那我們就進(jìn)入面試環(huán)節(jié)!

控制反轉(zhuǎn)(IOC)有什么用?
管理對象的創(chuàng)建和依賴關(guān)系的維護(hù) 解耦,由容器器維護(hù)具體的對象 托管了類的產(chǎn)生過程
IOC的優(yōu)點(diǎn)是什么?
IOC或依賴注入把應(yīng)用的代碼降到最低,它使應(yīng)用更加容易測試,單元測試不再需要單例和 JNDI 查找機(jī)制。以最小的代價(jià)和最小的侵入性使松散耦合得以實(shí)現(xiàn)。IOC 容器支持加載服務(wù)時(shí)以 懶漢式 或 餓漢式 加載。
IOC容器裝配Bean有幾種方式?4 種!
XML 配置 注解配置 JavaConfig 基于Groovy DSL配置(少見)
依賴注入有幾種方式?3 種!
屬性注入(通過 setter() 方法) 構(gòu)造函數(shù)注入 工廠方法注入
Bean有幾種作用域?5 種!
singleton:bean在每個(gè)SpringIOC容器中都只有一個(gè)實(shí)例 (默認(rèn)作用域) protorype:一個(gè)bean的定義可以有多個(gè)實(shí)例 request::每次 http 請求都會創(chuàng)建一個(gè) bean。該作用域僅在基于web的Spring ApplicationContext 情形下有效 session:在一個(gè) http session 中,一個(gè)bean定義對應(yīng)一個(gè)示例。該作用域僅在基于web的SpringApplicationContext 情形下有效 global-session:在一個(gè)全局的 http session 中,一個(gè)bean定義對應(yīng)一個(gè)示例。該作用域僅在基于web的SpringApplicationContext情形下有效
Spring中有幾種自動裝配方式?5 種
no:默認(rèn)的方式是不進(jìn)行自動裝配的,通過手工設(shè)置ref屬性來進(jìn)行裝配bean。
byName:通過bean的名稱進(jìn)行自動裝配,如果一個(gè)bean的 property 與另一bean 的name 相同,就進(jìn)行自動裝配。
byType:通過參數(shù)的數(shù)據(jù)類型進(jìn)行自動裝配。
constructor:利用構(gòu)造函數(shù)進(jìn)行裝配,并且構(gòu)造函數(shù)的參數(shù)通過byType進(jìn)行裝配。
autodetect:自動探測,如果有構(gòu)造方法,通過 construct的方式自動裝配,否則使用 byType的方式自動裝配。
@Autowired 注解有什么作用
默認(rèn)是按照類型裝配注入的,默認(rèn)情況下它要求依賴對象必須存在(可以設(shè)置它required屬性為false)。
提供了更細(xì)粒度的控制,包括在何處以及如何完成自動裝配。可以修飾setter方法、構(gòu)造器、屬性等。
@Autowired和@Resource之間的區(qū)別
@Autowired可用于:構(gòu)造函數(shù)、成員變量、Setter方法 @Autowired默認(rèn)是按照類型裝配注入的,默認(rèn)情況下它要求依賴對象必須存在(可以設(shè)置它required屬性為false) @Resource默認(rèn)是按照名稱來裝配注入的,只有當(dāng)找不到與名稱匹配的bean才會按照類型來裝配注入
Spring中 Bean 的生命周期
Spring 容器從 XML 文件中讀取 Bean 的定義,并實(shí)例化 Bean Spring根據(jù) Bean 的定義填充所有屬性 如果 Bean 實(shí)現(xiàn)了 BeanNameAware 接口,Spring將傳遞 Bean 的ID到 setBeanName ()方法中如果 Bean 實(shí)現(xiàn)了 BeanFactoryAware 接口,Spring 將傳遞 beanFactory 到 setBeanFactory()方法中如果有和 Bean 相關(guān)聯(lián)的 BeanPostProcessors,Spring會在 postProcesserBeforeInitialization()方法內(nèi)調(diào)用他們如果 Bean 實(shí)現(xiàn)了InitializingBean,會調(diào)用它的 afterPropertySet()方法,如果 Bean 聲明了初始化方法,那么會調(diào)用此方法如果有BeanPostProcessors 和 Bean 關(guān)聯(lián),那么會調(diào)用這些 Bean 的 postProcesserAfterInitialization()方法如果 Bean實(shí)現(xiàn)了 DisposableBean ,它將調(diào)用 destroy()方法
ApplicationContext 和 BeanFactory 的區(qū)別
BeanFactory可以稱為 低級容器。它比較簡單,可以理解為就是一個(gè) HashMap,key 是 BeanName,Value 就是 Bean 實(shí)例。通常只提供注冊(put) 和 獲取(get) 這兩個(gè)功能。ApplicationContext 可以稱為 高級容器。它過繼承了多個(gè)接口,因此多了更多的功能。例如資源的獲取,支持多種消息(例如 JSP tag 的支持),對 BeanFactory 多了工具級別的支持等待,它 代表著整個(gè)大容器的所有功能。該接口定義了一個(gè)refresh()方法,用于刷新整個(gè)容器,即重新加載/刷新所有的 bean。
ApplicationContext 的通常實(shí)現(xiàn)是什么?
FileSystemXmlApplicationContext:此容器從一個(gè) XML 文件中加載 bean 的定義,我們需要提供Bean配置文件的全路徑名給它的構(gòu)造函數(shù) ClassPathXmlApplicationContext:此容器也從一個(gè)XML文件中加載beans的定義,這里,你需要正確設(shè)置classpath因?yàn)檫@個(gè)容器將在classpath里找bean配置 WebXmlApplicationContext:此容器加載一個(gè)XML文件,此文件定義了一個(gè)WEB應(yīng)用的所有bean

關(guān)于Spring中的IOC相關(guān)知識就到這里結(jié)束啦,不知道小伙伴們看的過不過癮。不過癮的小伙伴趕緊關(guān)注點(diǎn)起來,下一篇AOP給你安排上!
路漫漫,小菜與你一同求索!

今天的你多努力一點(diǎn),明天的你就能少說一句求人的話!
我是小菜,一個(gè)和你一起學(xué)習(xí)的男人。
??微信公眾號已開啟,小菜良記,沒關(guān)注的同學(xué)們記得關(guān)注哦!
