成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring IoC是如何進(jìn)行依賴注入的

開發(fā) 前端
DI(Dependency Injection),Spring IoC 不是一種技術(shù),而是一種思想,通過這種思想,能夠指導(dǎo)我們?cè)O(shè)計(jì)出松耦合的程序代碼。

一、依賴注入(DI)

DI(Dependency Injection),Spring IoC 不是一種技術(shù),而是一種思想,通過這種思想,能夠指導(dǎo)我們?cè)O(shè)計(jì)出松耦合的程序代碼。而Spring IoC這個(gè)思想的作用體現(xiàn)在兩個(gè)方面,一是如何將Bean裝配到容器中去以及如何從容器中獲取Bean,二是如何解決Bean之間的依賴關(guān)系,換句話說,就是如果由IoC容器來管理依賴關(guān)系,當(dāng)一個(gè)Bean需要依賴另外一個(gè)Bean時(shí),IoC容器如何實(shí)現(xiàn)這樣的依賴關(guān)系。

解決Spring中Bean之間的依賴的實(shí)現(xiàn)方式,在Spring的概念中就被稱之為依賴注入(Dependency Injection,DI)。普遍認(rèn)為的Spring依賴注入的實(shí)現(xiàn)方式有三種:構(gòu)造方法注入、setter方法注入、注解注入。但,就我而言,我認(rèn)為應(yīng)該劃分為兩種形式——基于XML注入和基于注解注入,然后再細(xì)分為下面的形式:

Spring IoC是如何進(jìn)行依賴注入的

基于XML的注入方式是我們最先學(xué)習(xí)和使用的方式,也是最熟悉的方式,就簡(jiǎn)單的做個(gè)介紹,舉個(gè)例子。

1. 通過構(gòu)造方法注入

  1. public class UserServiceImpl implements UserService { 
  2.  
  3.     private UserDao userDao; 
  4.  
  5.     public UserServiceImpl(UserDao userDao) { 
  6.         this.userDao = userDao; 
  7.     } 
  8.  
  9.     /**繼承自UserService的方法**/ 

首先定義一個(gè)服務(wù)層UserServiceImpl,然后在其內(nèi)部增加對(duì)dao層的引用userDao。

接下來就是添加一個(gè)構(gòu)造方法public UserServiceImpl(UserDao userDao)以待Spring通過這個(gè)方法為userDao注入實(shí)例。

  1. <!--注冊(cè)u(píng)serDao--> 
  2. <bean id="userDao" class="com.klasdq.sb.c1.di.dao.impl.UserDaoImpl"></bean> 
  3.  
  4. <!--注冊(cè)u(píng)serService 并注入userDao--> 
  5. <bean id="userService" class="com.klasdq.sb.c1.di.service.impl.UserServiceImpl"> 
  6.         <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
  7. </bean> 

最后在Spring XML配置文件中注入相應(yīng)的bean實(shí)例。

通過構(gòu)造方法的注入,必須要注入類中具有對(duì)應(yīng)的構(gòu)造方法,若沒有對(duì)應(yīng)的構(gòu)造方法,會(huì)出現(xiàn)報(bào)錯(cuò)。

2. 通過setter方法注入

修改UserServiceImpl.java為:

  1. public class UserServiceImpl implements UserService { 
  2.  
  3.     private UserDao userDao; 
  4.  
  5.     public void setUserDao(UserDao userDao) { 
  6.         this.userDao = userDao; 
  7.     } 
  8.  
  9.     /**繼承自UserService的方法**/ 

再修改XML文件內(nèi)容為:

  1. <!--注冊(cè)u(píng)serDao--> 
  2. <bean id="userDao" class="com.klasdq.sb.c1.di.dao.impl.UserDaoImpl"></bean> 
  3.  
  4. <!--注冊(cè)u(píng)serService 并注入userDao--> 
  5. <bean id="userService" class="com.klasdq.sb.c1.di.service.impl.UserServiceImpl"> 
  6.         <property name="userDao" ref="userDao"></property> 
  7. </bean> 

這兩種方式的區(qū)別在于,一、UserServiceImpl.java可以不用添加構(gòu)造方法,但是必須存在一個(gè)無參構(gòu)造方法(如public UserServiceImpl(),示例里面沒寫,是因?yàn)閖ava默認(rèn)會(huì)提供一個(gè)無參構(gòu)造方法)以供Spring 容器注冊(cè)生成Bean(如userService)。二、XML文件中,采用構(gòu)造方法注入時(shí),需要使用這對(duì)標(biāo)簽;而在setter方法注入時(shí),使用 標(biāo)簽。

在XML注入過程中,除了使用ref=""引用之外,還可以使用value=""設(shè)定具體的值,其效果和使用注解@Value差不多。

二、基于注解的依賴注入

三、Autowired

源碼:

  1. @Target({ElementType.CONSTRUCTOR, 
  2.          ElementType.METHOD, 
  3.          ElementType.PARAMETER, 
  4.          ElementType.FIELD, 
  5.          ElementType.ANNOTATION_TYPE}) 
  6. @Retention(RetentionPolicy.RUNTIME) 
  7. @Documented 
  8. public @interface Autowired { 
  9.     boolean required() default true; 

@Autowired是基于注解的依賴注入的關(guān)鍵點(diǎn),它的源碼非常簡(jiǎn)單,只有一個(gè)參數(shù)request(),這個(gè)參數(shù)的作用是標(biāo)識(shí)注入Bean是否一定要注入,也就是說,在Spring容器沒有找到相應(yīng)Bean時(shí),如果其值為true,就會(huì)報(bào)出異常;如果其值為false,就不會(huì)出現(xiàn)異常,但在使用過程中,如果容器一直不對(duì)Bean進(jìn)行注入,那么有可能出現(xiàn)空指針異常。

另外一點(diǎn)就是,源碼當(dāng)中的@Target所包含的參數(shù)正好就是基于注解的依賴注入的注入方式種類,@Target決定了@Autowired能夠標(biāo)注在哪些類型上面。

1. 通過構(gòu)造方法注入:

  1. @Service("userService") 
  2. public class UserServiceImpl implements UserService { 
  3.  
  4.     private UserDao userDao; 
  5.  
  6.     @Autowired 
  7.     public UserServiceImpl(UserDao userDao) { 
  8.         this.userDao = userDao; 
  9.     } 
  10.     /**繼承自UserService的方法**/ 

根據(jù)開發(fā)文檔的說法,這種只有一個(gè)構(gòu)造方法的情況,自Spring4.3以后,就不再需要添加@Autowired標(biāo)注,也可以。但是,如果有多個(gè)構(gòu)造方法時(shí),是必須要對(duì)其中一個(gè)方法標(biāo)注@Autowired,不然Spring會(huì)報(bào)出異常。

2. 通過setter方法注入

  1. @Service("userService") 
  2. public class UserServiceImpl implements UserService { 
  3.  
  4.     private UserDao userDao; 
  5.  
  6.     @Autowired 
  7.     public void setUserDao(UserDao userDao) { 
  8.         this.userDao = userDao; 
  9.     } 
  10.     /**繼承自UserService的方法**/ 

3. 通過字段注入

  1. @Service("userService") 
  2. public class UserServiceImpl implements UserService { 
  3.  
  4.     @Autowired 
  5.     private UserDao userDao; 
  6.  
  7.     /**繼承自UserService的方法**/ 

4. 通過方法入?yún)⒆⑷?/strong>

上面三種注入方式,都是比較熟悉的就不再多做闡述了。重點(diǎn)說一下參數(shù)注入,其實(shí)方法入?yún)⒆⑷敕绞礁杏X上是和構(gòu)造方法、setter方法注入形式差不多,相當(dāng)于將構(gòu)造方法、setter方法上的注解@Autowired放到入?yún)⒌奈恢谩Uf起來可能有些抽象,直接看例子:

  1. @Component 
  2. public class UserDaoImpl implements UserDao { 
  3.     //簡(jiǎn)單返回一個(gè)User,模擬數(shù)據(jù)庫查找過程 
  4.     @Override 
  5.     public User getUser(Long id, String name){ 
  6.         User user = new User(); 
  7.         user.setId(id); 
  8.         user.setName(name); 
  9.         user.setAccount("12345678911"); 
  10.         user.setPassword("******"); 
  11.         user.setOtherInfo("this is a test account"); 
  12.         return user; 
  13.     } 
  1. //UserService類 
  2. @Service("userService") 
  3. public class UserServiceImpl implements UserService { 
  4.  
  5.     private UserDao userDao; 
  6.  
  7.    public UserServiceImpl(@Autowired UserDao userDao, 
  8.                           @Autowired User user) { 
  9.        System.out.println("UserServiceImpl: "+user); 
  10.        this.userDao = userDao; 
  11.    } 
  12.  
  13.     @Override 
  14.     public User getUser(Long id, String name){ 
  15.         return userDao.getUser(id,name); 
  16.     } 
  1. //簡(jiǎn)單的配置類 
  2. //作用就是為標(biāo)有@Componet(@Service也算)注解的類 生成Bean 
  3. //同時(shí) 為@Autowired標(biāo)識(shí)下的Bean(對(duì)象) 注入實(shí)例 
  4. @Configuration 
  5. @ComponentScan 
  6. public class DIConfig { 
  7.  
  8.     //用于Service類中入?yún)ser的注入 
  9.     @Bean 
  10.     public User getUser(){ 
  11.         User u = new User(); 
  12.         u.setName("user inject into service"); 
  13.         return u; 
  14.     } 
  1. //測(cè)試類 
  2. //注意:使用JUnit4測(cè)試時(shí),如果需要使用@Autowired注入那么必須添加 
  3. //@RunWith    標(biāo)注使用Spring方式啟動(dòng)(或者SpringBootRunner) 
  4. //@ContextConfiguration  掃描配置類 
  5. @RunWith(SpringRunner.class) 
  6. @ContextConfiguration(classes = DIConfig.class) 
  7. public class DITest { 
  8.  
  9.     //如果不添加測(cè)試類上兩個(gè)注解,會(huì)注入失敗 
  10.     @Autowired 
  11.     private UserService userService; 
  12.  
  13.     @Test 
  14.     public void testAutowired(){ System.out.println(userService.getUser(1L,"name")); 
  15.     } 

運(yùn)行測(cè)試方法之后就得到以下結(jié)果:

public UserServiceImpl(@Autowired UserDao userDao,@Autowired User user)中的輸出結(jié)果:

Spring IoC是如何進(jìn)行依賴注入的

public void testAutowired()測(cè)試方法中的輸出結(jié)果:

Spring IoC是如何進(jìn)行依賴注入的

注意這里public UserServiceImpl(@Autowired UserDao userDao,@Autowired User user)的入?yún)ⅲ?/p>

userDao是UserServiceImpl的字段,但user不是。也就是說,我們可以在構(gòu)造方法中添加任意參數(shù),只要是我們需要的,不一定要求該參數(shù)是類中屬性字段。

此外還有需要注意的是,這里所說的方法,不是任意的方法,而是構(gòu)造方法或setter方法,這種public void initService(@Autowired UserDao userDao)自定義的方法是無法完成注入的。

四、@Primary 和 @Qualifier

在上面的例子中,我們注入使用到的bean,都只是容器中只有一個(gè)Bean實(shí)例的情況。那么當(dāng)容器當(dāng)中出現(xiàn)多個(gè)同類型的Bean時(shí),如何處理呢?

修改配置類代碼如下:

  1. @Configuration 
  2. @ComponentScan 
  3. public class DIConfig { 
  4.  
  5.     @Bean 
  6.     public User getUser(){ 
  7.         User u = new User(); 
  8.         u.setName("this is user"); 
  9.         return u; 
  10.     } 
  11.  
  12.     @Bean 
  13.     public User getUser2(){ 
  14.         User u = new User(); 
  15.         u.setName("this is user2"); 
  16.         return u; 
  17.     } 

修改測(cè)試類:

  1. @RunWith(SpringRunner.class) 
  2. @ContextConfiguration(classes = DIConfig.class) 
  3. public class DITest { 
  4.  
  5.     @Autowired 
  6.     private User user; 
  7.  
  8.     @Test 
  9.     public void testAutowiredPriamry(){ 
  10.         System.out.println(user); 
  11.     } 

當(dāng)不做其他處理時(shí),結(jié)果為:

Spring IoC是如何進(jìn)行依賴注入的

因?yàn)橛袃蓚€(gè)User Bean(getUser , getUser2 ,@Bean未注明的情況下,默認(rèn)方法名為Bean Name)的存在,所以Spring無法確定使用那個(gè)進(jìn)行注入。

修改方式:

  • 在@Bean中設(shè)置name,如@Bean(name="user"),當(dāng)名字能夠匹配上private User user;時(shí),也能完成注入。
  • 將private User user改寫成getUser或getUser2任意一個(gè),也能完成注入。道理和上面一樣,Spring首先會(huì)按照type進(jìn)行匹配,如果無法匹配,再按照名字匹配,都匹配不上時(shí),自然拋出異常。

除此之外呢,Spring為我們提供了兩個(gè)注解來消除依賴注入時(shí)的歧義問題。

  • @Primary
    1. @Target({ElementType.TYPE,    // 類、接口、枚舉類型 
    2.          ElementType.METHOD})// 方法 
    3. @Retention(RetentionPolicy.RUNTIME) 
    4. @Documented 
    5. public @interface Primary { 

@Primary是一個(gè)設(shè)定相同類型Bean優(yōu)先級(jí)的注解,也就是說,一旦在某個(gè)類型上添加@Priamry,當(dāng)注入時(shí),沒有明確指定Bean時(shí),就會(huì)注入被@Priamry標(biāo)識(shí)的Bean。

  1. @Configuration 
  2. @ComponentScan 
  3. public class DIConfig { 
  4.  
  5.     @Primary 
  6.     @Bean 
  7.     public User getUser(){ 
  8.         User u = new User(); 
  9.         u.setName("this is user"); 
  10.         return u; 
  11.     } 
  12.  
  13.     @Bean 
  14.     public User getUser2(){ 
  15.         User u = new User(); 
  16.         u.setName("this is user2"); 
  17.         return u; 
  18.     } 

比如上面這樣,在getUser()上添加相應(yīng)注解,測(cè)試方法也能正常運(yùn)行。

但是這種方法的問題就在于@Priamry可以用在很多類上,如果同一類型有多個(gè)Bean被標(biāo)注了@Primary,那么@Priamry就失去了應(yīng)有的效果。

  • @Qualifier

因此,Spring又提供了@Qualifier這個(gè)注解,直接標(biāo)注在@Autowired注入的Bean上,為其明確指定注入某個(gè)Bean。

  1. @Target({ElementType.FIELD,  
  2.          ElementType.METHOD,  
  3.          ElementType.PARAMETER,  
  4.          ElementType.TYPE,  
  5.          ElementType.ANNOTATION_TYPE}) 
  6. @Retention(RetentionPolicy.RUNTIME) 
  7. @Inherited 
  8. @Documented 
  9. public @interface Qualifier { 
  10.     String value() default ""; 

@Qualifier可以出現(xiàn)任何@Autowired能夠出現(xiàn)的地方,與之配套使用。比如下面這樣:

  1. @RunWith(SpringRunner.class) 
  2. @ContextConfiguration(classes = DIConfig.class) 
  3. public class DITest {  
  4.  
  5.     //直接指定使用getUser2進(jìn)行注入 
  6.     @Autowired 
  7.     @Qualifier("getUser2") 
  8.     private User user; 
  9.  
  10.     @Test 
  11.     public void testAutowiredPriamry(){ 
  12.         System.out.println(user); 
  13.     } 

這兩種注解都可以消除歧義,推薦使用@Bean(name="xxx")和@Qualifier(value="xxx")組合使用的方式`。但是如果開發(fā)環(huán)境中沒有歧義的存在,自然也就不需要使用這些了。

當(dāng)然,上面只是對(duì)于@Autowired一些常用介紹,如果想要了解更多,可以查看Annotation-based Container Configuration。這個(gè)參考文檔當(dāng)中有著更加詳細(xì)、豐富的介紹。

總結(jié)

總得來說,Spring是如何實(shí)現(xiàn)IoC的呢?首先,Spring提供了一個(gè)獲取和管理Bean的IoC容器。然后,再提供了一套依賴注入的機(jī)制去幫助IoC容器更好地管理各個(gè)Bean之間的依賴關(guān)系,從而更好地實(shí)現(xiàn)IoC的思想。一個(gè)Bean不可能完全脫離其他Bean的依賴關(guān)系而獨(dú)立存在,當(dāng)一個(gè)Bean需要其他Bean的引入才能初始化時(shí),就需要依賴注入這個(gè)機(jī)制。

舉例來說,假如存在一個(gè)A類想要去調(diào)用B接口的方法或者說需要B接口的一個(gè)實(shí)例。

傳統(tǒng)的程序流程是,使用一個(gè)C類實(shí)現(xiàn)B接口,然后A類創(chuàng)建一個(gè)C類的實(shí)例,從而調(diào)用其方法。

在Spring的依賴注入過程中就變成了,A類只需要在自己的內(nèi)部添加一個(gè)注入接口(廣義上的接口,不是interface這個(gè)接口),這個(gè)接口可以是構(gòu)造方法,也可以是setter方法或者說其他形式;同時(shí)添加一個(gè)對(duì)B接口的引用(private B b;)。

當(dāng)真正需要生成A類的實(shí)例時(shí),Spring IoC容器根據(jù)A類提供的接口,為其注入相應(yīng)的Bean,而這個(gè)Bean可以是C類(class C implements B{}),也可以D類(class D implements B{})等等;具體是誰,根據(jù)Bean的裝配策略和IoC容器中的Bean來確定,不再由開發(fā)人員管理。

本文授權(quán)轉(zhuǎn)載自公眾號(hào)「良許Linux」。良許,世界500強(qiáng)外企Linux開發(fā)工程師,公眾號(hào)里分享大量Linux干貨,歡迎關(guān)注!

 

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2011-05-31 10:00:21

Android Spring 依賴注入

2013-04-15 17:55:12

Windows認(rèn)證安全認(rèn)證

2013-04-16 10:33:58

Windows 安全認(rèn)微軟

2024-05-08 08:16:11

2023-10-17 00:01:34

Linux操作系統(tǒng)

2021-05-06 07:58:57

Spring BeanIOCAOP

2021-01-22 06:35:44

IoCxml驅(qū)動(dòng)技術(shù)

2010-08-02 16:33:11

Flex Spring

2022-04-30 08:50:11

控制反轉(zhuǎn)Spring依賴注入

2016-03-21 17:08:54

Java Spring注解區(qū)別

2020-12-29 08:34:08

spring循環(huán)依賴開發(fā)

2011-03-29 09:51:58

GuiceIOC

2014-09-19 10:46:36

LuaCC++

2017-08-16 16:00:05

PHPcontainer依賴注入

2009-09-08 15:22:20

Spring依賴注入

2020-04-06 14:50:43

MySQLSQL數(shù)據(jù)庫

2021-03-15 10:23:44

IT支出技術(shù)投資CIO

2024-05-13 11:12:08

FO-DICOM開源應(yīng)用開發(fā)

2020-07-14 14:59:00

控制反轉(zhuǎn)依賴注入容器

2011-03-01 13:45:41

Spring3Annotation
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲第一成年免费网站 | 黄色毛片在线看 | 另类视频区 | 亚洲综合色丁香婷婷六月图片 | 亚洲美女在线视频 | 欧美成人激情 | 国产99久久精品一区二区永久免费 | 欧美一区二区在线看 | 操久久| 偷拍自拍第一页 | 拍真实国产伦偷精品 | 91精品国产乱码麻豆白嫩 | 久久亚洲一区二区三 | 成人av观看 | 日韩中文视频 | 91精品国产91久久久久久丝袜 | 亚洲精彩视频 | 日本三级在线网站 | 亚洲欧美一区二区三区1000 | 成人伊人网 | 久久综合成人精品亚洲另类欧美 | 精品国产欧美一区二区三区不卡 | 亚洲欧美日韩在线 | 成年人在线观看 | 五月天综合网 | 国产午夜精品久久久 | www,黄色,com| 青青久久 | 黄色网页在线 | 日本黄色免费片 | 91在线观看| 亚洲一区二区三区欧美 | 国产精品一区二区不卡 | 亚洲91视频 | 欧美国产中文字幕 | 91欧美| 久久久久av | 久久精品av | 午夜一区二区三区在线观看 | 欧美一级大黄 | 精品欧美视频 |