<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          驚了!這是一篇《IOC》說明書?

          共 15375字,需瀏覽 31分鐘

           ·

          2021-03-17 07:27

          大家好,我是小菜,一個(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ò)展出了 SpringMVCSpringBoot、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。

          DIIOC 另一種表述的方式:即組件以一些預(yù)先定義好的方式(setter, construct...)接收來自容器的資源注入,相對于 IOC 來說,這種表述更加直接。

          看完以上,我們明白幾個(gè)概念:

          1. 誰依賴誰?應(yīng)用程序依賴于 IOC 容器

          2. 為什么需要依賴?應(yīng)用程序需要IOC容器提供對象所需要的外部資源

          3. 誰注入誰?IOC容器向應(yīng)用程序注入外部資源

          4. 注入了什么?注入應(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)簽里面有哪些屬性:

          image-20210311125706584

          value  我們已經(jīng)使用過了,就是用來表示注入的值

          name 就是用來表明對象屬性的名稱

          type 用來表明對象屬性的類型

          index 用來表明改屬性在構(gòu)造函數(shù)中的位置,默認(rèn)從 0 開始計(jì)數(shù)

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

          image-20210311132600788

          對象當(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;
          image-20210313170116952

          如果你覺得包一層<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)該對 initdestory 兩個(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

          image-20210315124345789

          通過這個(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)入到容器中的組件)

          image-20210315231502362

          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)境的情況下才能被注冊到容器中

          1. 加了環(huán)境標(biāo)識的bean,只有這個(gè)環(huán)境被激活的時(shí)候才能注冊到容器中。默認(rèn)是default環(huán)境
          2. 寫在配置類上,只有是指定的環(huán)境的時(shí)候,整個(gè)配置類里面的所有配置才能開始生效
          3. 沒有標(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è)子類 ClassPathXmlApplicationContextAnnoationConfigApplicationContext ,當(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ū)別

          1. @Autowired可用于:構(gòu)造函數(shù)、成員變量、Setter方法
          2. @Autowired默認(rèn)是按照類型裝配注入的,默認(rèn)情況下它要求依賴對象必須存在(可以設(shè)置它required屬性為false)
          3. @Resource默認(rèn)是按照名稱來裝配注入的,只有當(dāng)找不到與名稱匹配的bean才會按照類型來裝配注入

          Spring中 Bean 的生命周期

          1. Spring 容器從 XML 文件中讀取 Bean 的定義,并實(shí)例化 Bean
          2. Spring根據(jù) Bean 的定義填充所有屬性
          3. 如果 Bean 實(shí)現(xiàn)了 BeanNameAware 接口,Spring將傳遞 Bean 的ID到 setBeanName ()方法中
          4. 如果 Bean 實(shí)現(xiàn)了 BeanFactoryAware 接口,Spring 將傳遞 beanFactory 到 setBeanFactory() 方法中
          5. 如果有和 Bean 相關(guān)聯(lián)的 BeanPostProcessors,Spring會在 postProcesserBeforeInitialization() 方法內(nèi)調(diào)用他們
          6. 如果 Bean 實(shí)現(xiàn)了InitializingBean,會調(diào)用它的 afterPropertySet() 方法,如果 Bean 聲明了初始化方法,那么會調(diào)用此方法
          7. 如果有BeanPostProcessors 和 Bean 關(guān)聯(lián),那么會調(diào)用這些 Bean 的 postProcesserAfterInitialization() 方法
          8. 如果 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)注哦!


          瀏覽 79
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲精品一区二区三区蜜桃 | 国产成人高潮毛片 | 久久精品一二三视频 | 欧美在线aaa | www在线看 |