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

基于spring DI的三種注入方式分析

 更新時(shí)間:2021年07月05日 09:46:26   作者:CrazySnail_x  
這篇文章主要介紹了基于spring DI的三種注入方式分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。

一.前言: IOC(控制反轉(zhuǎn))與DI(依賴注入)

Spring框架對(duì)Java開發(fā)的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反轉(zhuǎn))和AOP,平時(shí)使用最多的就是其中的IOC,我們通過(guò)將組件交由Spring的IOC容器管理,將對(duì)象的依賴關(guān)系由Spring控制,避免硬編碼所造成的過(guò)度程序耦合。

在講依賴注入之前,我覺得有必要了解一下IOC(控制反轉(zhuǎn))與DI(依賴注入)的關(guān)系,在這篇文章中有詳細(xì)的介紹:spring IOC 與 DI。

二.DI的三種常見注入方式

DI的三種常見注入方式為:setter注入、構(gòu)造器注入和基于注解的注入(也叫field注入),下面來(lái)分別講講他們的特點(diǎn)。

2.1 基于注解注入

首先來(lái)看一下它的實(shí)現(xiàn):

@RestController
@RequestMapping("/annotation")
public class AnnotationController {
    @Autowired
    private DiService diService;
 
    @GetMapping("/test001")
    public String test001() {
        return diService.test001("annotation");
    }
}

這種方式應(yīng)該是目前最常見的注入方式了,原因很簡(jiǎn)單:

1、注入方式非常簡(jiǎn)單:加上@Autowired注解,加入要注入的字段,即可完成。

2、使得整體代碼簡(jiǎn)潔明了,看起來(lái)美觀大方。

在介紹注解注入的方式前,先簡(jiǎn)單了解bean的一個(gè)屬性autowire,autowire主要有三個(gè)屬性值:constructor,byName,byType。

  • constructor:通過(guò)構(gòu)造方法進(jìn)行自動(dòng)注入,spring會(huì)匹配與構(gòu)造方法參數(shù)類型一致的bean進(jìn)行注入,如果有一個(gè)多參數(shù)的構(gòu)造方法,一個(gè)只有一個(gè)參數(shù)的構(gòu)造方法,在容器中查找到多個(gè)匹配多參數(shù)構(gòu)造方法的bean,那么spring會(huì)優(yōu)先將bean注入到多參數(shù)的構(gòu)造方法中。
  • byName:被注入bean的id名必須與set方法后半截匹配,并且id名稱的第一個(gè)單詞首字母必須小寫,這一點(diǎn)與手動(dòng)set注入有點(diǎn)不同。
  • byType:查找所有的set方法,將符合符合參數(shù)類型的bean注入。

下面進(jìn)入正題:

注解方式注冊(cè)bean:

在以前的開發(fā)中,我們主要使用四種注解注冊(cè)bean,每種注解可以任意使用,只是語(yǔ)義上有所差異:

  1. @Component:可以用于注冊(cè)所有bean
  2. @Repository:主要用于注冊(cè)dao層的bean
  3. @Controller:主要用于注冊(cè)控制層的bean
  4. @Service:主要用于注冊(cè)服務(wù)層的bean

隨著springboot的流行,@Bean注解也逐漸的被我們使用起來(lái)。Spring的@Bean注解用于告訴方法,產(chǎn)生一個(gè)Bean對(duì)象,然后這個(gè)Bean對(duì)象交給Spring管理。產(chǎn)生這個(gè)Bean對(duì)象的方法Spring只會(huì)調(diào)用一次,隨后這個(gè)Spring將會(huì)將這個(gè)Bean對(duì)象放在自己的IOC容器中。

注解方式注入依賴(主要有兩種):

  • @Resource :java的注解,默認(rèn)以byName的方式去匹配與屬性名相同的bean的id,如果沒有找到就會(huì)以byType的方式查找,如果byType查找到多個(gè)的話,使用@Qualifier注解(spring注解)指定某個(gè)具體名稱的bean。
  • @Autowired :spring注解,默認(rèn)是以byType的方式去匹配類型相同的bean,可以結(jié)合@Qualifier 注解根據(jù)byName方式匹配。

關(guān)于他們的具體用法與區(qū)別,因?yàn)閮?nèi)容比較多,所以寫在另一篇博客中,請(qǐng)見:@Autowired 和 @Resource 詳解

2.2 構(gòu)造器注入

老規(guī)矩,先上代碼示例:

@RestController
@RequestMapping("/constructor")
public class ConstructorController {
    private final DiService diService;
    private final String result; 
    public ConstructorController(DiService diService) {
        this.diService = diService;
        this.result = diService.test001("constructor");
    }
 
    @GetMapping("/test001")
    public String test001() {
        return diService.test001(this.result);
    }
}

這里有一個(gè)問題,如果只有一個(gè)有參數(shù)的構(gòu)造方法并且參數(shù)類型與注入的bean的類型匹配,那就會(huì)注入到該構(gòu)造方法中。如果有多個(gè)有參數(shù)的構(gòu)造方法并且每個(gè)構(gòu)造方法的參數(shù)列表里面都有要注入的屬性,那userDaoJdbc會(huì)注入到哪里呢?

在Spring4.x版本中推薦的注入方式就是這種,相較于上面的field注入方式而言,就顯得有點(diǎn)難看,特別是當(dāng)注入的依賴很多(5個(gè)以上)的時(shí)候,就會(huì)明顯的發(fā)現(xiàn)代碼顯得很臃腫。對(duì)于從field注入轉(zhuǎn)過(guò)來(lái)+有強(qiáng)迫癥的同學(xué)來(lái)說(shuō),簡(jiǎn)直可以說(shuō)是石樂志 ,但是為啥spring官方還會(huì)這么推薦呢?

官方文檔里是這么說(shuō)的:

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.

翻譯一下就是:Spring團(tuán)隊(duì)通常提倡構(gòu)造函數(shù)注入,因?yàn)樗试S將應(yīng)用程序組件實(shí)現(xiàn)為不可變的對(duì)象,并確保所需的依賴不為空。此外,注入構(gòu)造函數(shù)的組件總是以完全初始化的狀態(tài)返回給客戶機(jī)(調(diào)用)代碼。

簡(jiǎn)單解釋一下:

  • 不可變的對(duì)象:其實(shí)說(shuō)的就是final關(guān)鍵字,這里不再多解釋了。
  • 依賴不為空:省去了我們對(duì)其檢查。當(dāng)要實(shí)例化ConstructorController的時(shí)候,由于自己實(shí)現(xiàn)了有參數(shù)的構(gòu)造函數(shù),所以不會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù),那么就需要Spring容器傳入所需要的參數(shù),所以就兩種情況:1、有該類型的參數(shù)->傳入,OK 。2:無(wú)該類型的參數(shù)->報(bào)錯(cuò)。這樣就可以保證不會(huì)為空。
  • 完全初始化的狀態(tài):這個(gè)可以跟上面的依賴不為空結(jié)合起來(lái),向構(gòu)造器傳參之前,要確保注入的內(nèi)容不為空,那么肯定要調(diào)用依賴組件的構(gòu)造方法完成實(shí)例化。而在Java類加載實(shí)例化的過(guò)程中,構(gòu)造方法是最后一步(之前如果有父類先初始化父類,然后自己的成員變量,最后才是構(gòu)造方法,這里不詳細(xì)展開。)。所以返回來(lái)的都是初始化之后的狀態(tài)。

與注解方式注入相比,構(gòu)造器注入可復(fù)用性高,如果使用field注入,缺點(diǎn)顯而易見,對(duì)于IOC容器以外的環(huán)境,除了使用反射來(lái)提供它需要的依賴之外,無(wú)法復(fù)用該實(shí)現(xiàn)類。而且將一直是個(gè)潛在的隱患,因?yàn)槟悴徽{(diào)用將一直無(wú)法發(fā)現(xiàn)NPE的存在。

相對(duì)于注解注入,構(gòu)造器注入可以防止循環(huán)依賴的問題,若如下代碼:

public class A {
    @Autowired
    private B b;
}
 
public class B {
    @Autowired
    private A a;
}

如果使用構(gòu)造器注入,在spring項(xiàng)目啟動(dòng)的時(shí)候,就會(huì)拋出:

BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference?

從而提醒你避免循環(huán)依賴,如果是注解注入的話,啟動(dòng)的時(shí)候不會(huì)報(bào)錯(cuò),在使用那個(gè)bean的時(shí)候才會(huì)報(bào)錯(cuò)。

2.3 setter注入

這是在spring3.x出來(lái)的時(shí)候,官方推薦的注入方式,但是在spring4.x以后就沒有見它推薦了,而且在實(shí)際開發(fā)中已經(jīng)很少能見到這種注入方式了。

下面來(lái)看一下它的實(shí)現(xiàn):

@RestController
@RequestMapping("/setter")
public class SetterController {
    private DiService diService; 
    @Autowired
    public void setDiService(DiService diService) {
        this.diService = diService;
    }
 
    @GetMapping("/test001")
    public String test001() {
        return diService.test001("setter");
    }
}

試想一下,一旦需要注入的組件很多,那我們會(huì)累死的,所以大家都不喜歡用它也是情理之中的事情。

這里有一點(diǎn)需要注意:如果通過(guò)set方法注入屬性,那么spring會(huì)通過(guò)默認(rèn)的空參構(gòu)造方法來(lái)實(shí)例化對(duì)象,所以如果在類中寫了一個(gè)帶有參數(shù)的構(gòu)造方法,一定要把空參數(shù)的構(gòu)造方法寫上,否則spring沒有辦法實(shí)例化對(duì)象,導(dǎo)致報(bào)錯(cuò)。

總結(jié)

這么多的依賴注入方式,我們應(yīng)該怎么選擇呢?那種方式最好呢?

其實(shí),有句古話說(shuō)的很對(duì),合適自己的才是最好的,我們需要看情況來(lái)選擇使用哪種注入方式。

使用構(gòu)造器注入的好處:

  1. 保證依賴不可變(final關(guān)鍵字)
  2. 保證依賴不為空(省去了我們對(duì)其檢查)
  3. 保證返回客戶端(調(diào)用)的代碼的時(shí)候是完全初始化的狀態(tài)
  4. 避免了循環(huán)依賴
  5. 提升了代碼的可復(fù)用性

另外,當(dāng)有一個(gè)依賴有多個(gè)實(shí)現(xiàn)的使用,推薦使用注解方式注入的方式來(lái)指定注入的類型或name,使用setter注入指定類型。這是spring官方博客對(duì)setter注入方式和構(gòu)造器注入的比較。

謝謝大家看完了,以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如果有描述不對(duì)的地方歡迎指正,與大家共同進(jìn)步!

相關(guān)文章

  • 基于resty?security的Api權(quán)限控制與事務(wù)支持

    基于resty?security的Api權(quán)限控制與事務(wù)支持

    這篇文章主要為大家介紹了基于resty?security的Api權(quán)限控制與事務(wù)支持讓數(shù)據(jù)操作處于事務(wù)控制下,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-03-03
  • Java?SpringTask定時(shí)自動(dòng)化處理方法

    Java?SpringTask定時(shí)自動(dòng)化處理方法

    這篇文章主要介紹了Java?SpringTask定時(shí)自動(dòng)化處理,通過(guò)自動(dòng)化,不僅可以提高工作效率和準(zhǔn)確性,還可以釋放人力資源以專注于更高價(jià)值的工作,需要的朋友可以參考下
    2024-08-08
  • springboot+redis 實(shí)現(xiàn)分布式限流令牌桶的示例代碼

    springboot+redis 實(shí)現(xiàn)分布式限流令牌桶的示例代碼

    這篇文章主要介紹了springboot+redis 實(shí)現(xiàn)分布式限流令牌桶 ,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼

    Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼

    這篇文章主要介紹了Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼,實(shí)現(xiàn)Callable和實(shí)現(xiàn)Runnable類似,但是功能更強(qiáng)大,具體表現(xiàn)在可以在任務(wù)結(jié)束后提供一個(gè)返回值,Runnable不行,call方法可以拋出異,Runnable的run方法不行,需要的朋友可以參考下
    2023-08-08
  • MyBatis字段名和屬性名不一致的解決方法

    MyBatis字段名和屬性名不一致的解決方法

    本文主要介紹了MyBatis字段名和屬性名不一致的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • java集合類ArrayList和Vector的區(qū)別面試精講

    java集合類ArrayList和Vector的區(qū)別面試精講

    這篇文章主要為大家介紹了java集合類ArrayList和Vector的區(qū)別面試全面講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 詳解Spring Boot實(shí)戰(zhàn)之Rest接口開發(fā)及數(shù)據(jù)庫(kù)基本操作

    詳解Spring Boot實(shí)戰(zhàn)之Rest接口開發(fā)及數(shù)據(jù)庫(kù)基本操作

    本篇文章主要介紹了Spring Boot實(shí)戰(zhàn)之Rest接口開發(fā)及數(shù)據(jù)庫(kù)基本操作,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • SpringBoot超詳細(xì)講解多數(shù)據(jù)源集成

    SpringBoot超詳細(xì)講解多數(shù)據(jù)源集成

    今天分享下SpringBoot多數(shù)據(jù)源集成,我怕麻煩,這里我覺得我的集成也應(yīng)該是最簡(jiǎn)單的,清晰明了
    2022-05-05
  • Java?使用geotools讀取tiff數(shù)據(jù)的示例代碼

    Java?使用geotools讀取tiff數(shù)據(jù)的示例代碼

    這篇文章主要介紹了Java?通過(guò)geotools讀取tiff,一般對(duì)于tiff數(shù)據(jù)的讀取,都會(huì)借助于gdal,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • 深入理解JAVA多線程之線程間的通信方式

    深入理解JAVA多線程之線程間的通信方式

    下面小編就為大家?guī)?lái)一篇深入理解JAVA多線程之線程間的通信方式。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-05-05

最新評(píng)論

池州市| 万荣县| 苏州市| 中西区| 洛宁县| 望江县| 神农架林区| 九台市| 合江县| 西藏| 永仁县| 东至县| 江安县| 漾濞| 高阳县| 胶南市| 东阿县| 阿巴嘎旗| 南城县| 南召县| 乌鲁木齐市| 田东县| 新巴尔虎左旗| 潞西市| 黔江区| 涟源市| 临潭县| 文成县| 大庆市| 从化市| 福安市| 敦化市| 涿州市| 正定县| 格尔木市| 武功县| 渝中区| 尼玛县| 江安县| 临邑县| 鄂尔多斯市|