如何理解IoC的依賴注入

這篇文章主要講解了“如何理解IoC的依賴注入”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“如何理解IoC的依賴注入”吧!

海豐網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,海豐網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為海豐超過千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營銷網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的海豐做網(wǎng)站的公司定做!

 一、注解驅(qū)動IoC

xml驅(qū)動的IoC容器使用的是ClassPathXmlApplicationContext讀取xml內(nèi)bean信息

注解驅(qū)動的IoC容器使用的是AnnotationConfigApplicationContext讀取Java類中的bean信息

1. AnnotationConfigApplicationContext 的注冊使用

相比于xml文件作為驅(qū)動, 注解驅(qū)動需要指明配置類 一個配置類可以理解為"相當(dāng)于"一個xml 配置類只需要在類上標(biāo)注注解  @Configuration

@Configuration public class DemoConfiguration { }

在xml中聲明bean的方式

在配置類中使用的是@Bean注解

<bean id="person" class="com.huodd.bean.Person"></bean>

說明: 向IoC容器注冊一個類型為Persion,id為Person的Bean

方法名表示的是bean的id 返回值表示的是注冊的bean的類型

@Bean注解也可以顯示的聲明bean的id  如 @Bean("person1")

@Bean public Person person() {     return new Person(); }

2. 注解IoC容器的初始化

public class AnnotationConfigApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoConfiguration.class);         Person person = ctx.getBean(Person.class);         System.out.println(person);     } }

運(yùn)行后Person控制臺打印結(jié)果

com.huodd.bean.Person@55536d9e

3. 組件的注冊和掃描

上述初始化時 我們在使用AnnotationConfigApplicationContext時傳遞了參數(shù) Class...  componentClasses

翻看AnnotationConfigApplicationContext的構(gòu)造方法可以發(fā)現(xiàn)還可以傳遞參數(shù)的參數(shù)類型還有 String...  basePackages

這里就涉及到組件的注冊和掃描

  • 這里可以思考一個問題, 如果我們要注冊的組件特別多, 那進(jìn)行編寫這些@Bean的時候代碼工作量也會特別多,這時候該如何解決呢?

Spring 給我們提供了幾個注解,可以幫助我們快速注冊需要的組件, 這些注解被稱為模式注解(stereotype annotations)

@Component

@Component可以說是所有組件注冊的根源 在類上標(biāo)注 @Component 代表該類被注冊到IoC容器中作為一個Bean

@Component public class Person { }

如果未指定 Bean 的名稱 默認(rèn)規(guī)則是 "類名稱首字母小寫" 上面的bean名稱默認(rèn)會是 person

如果要自定義bean的名稱 可以在@Component聲明value的值即可 如

@Component("person1") public class Person { }

在xml中相當(dāng)于

<bean id="person1" class="com.huodd.bean.Person"/>

@ComponentScan

這個時候 如果我們直接運(yùn)行啟動類 獲取Person的bean對象,會報錯NoSuchBeanDefinitionException 這是為什么呢?

因?yàn)槲覀冎皇锹暶髁私M件,而后直接啟動了IoC容器,這樣容器是感知不到有@Component存在的,

解決方案1:

我們需要在寫配置類時再額外標(biāo)注一個新的注解@ComponentScan

目的是告訴IoC容器 我要掃描哪個包下面的帶有@Component注解的類

@Configuration @ComponentScan("com.huodd.bean") public class DemoComponentScanConfiguration { }

: 如果不指定掃描路徑, 則默認(rèn)掃描本類所在包及所有子包下帶有@Component的組件

啟動類代碼如下:

public class AnnotationConfigApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoComponentScanConfiguration.class);         Person person = ctx.getBean(Person.class);         System.out.println(person);     } }

解決方案2:

這里也可以不寫@ComponentScan  而直接在AnnotationConfigApplicationContext方法參數(shù)內(nèi)傳入String類型的包掃描路徑 代碼如下

public class AnnotationConfigApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext("com.huodd.bean");         Person person = ctx.getBean(Person.class);         System.out.println(person);     } }

PS: 組件掃描并非是注解驅(qū)動IoC所特有的, 其實(shí)在xml驅(qū)動的IoC模式下 同樣可以啟用組件掃描, 只需要在xml中聲明一個標(biāo)簽即可

<context:component-scan base-package="com.huodd.bean"/>

這里需要注意下: 如需要掃描多個路徑,需要寫多個標(biāo)簽 也就是 一個標(biāo)簽只能聲明一個根包

組件注冊的補(bǔ)充

SpringFramework 提供了在進(jìn)行Web開發(fā)三層架構(gòu)時的擴(kuò)展注解: 分別為 @Controller、 @Service 、@Repository  小伙伴有沒有很熟悉?

分別代表 表現(xiàn)層、業(yè)務(wù)層、持久層這三個注解的作用與 @Component完全一樣 扒開源碼我們可以看到 底層在這三個注解類上又添加了  @Component

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { }

這樣 我們在進(jìn)行符合三層架構(gòu)的開發(fā)時 對于相應(yīng)的如 ServiceImpl等 就可以直接標(biāo)注 @Service 等注解了

@Configuration

@Configuration 底層也有標(biāo)注@Component

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { ... }

由此可以說明,配置類不是向我們所想的那樣,只是單純的做一個配置而已, 它也會被視為 bean,也被注冊到IoC容器里面

4. 注解驅(qū)動與xml驅(qū)動互相引用

4.1 xml引用注解

需開啟注解配置 再注冊相應(yīng)配置類

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xmlns:context="http://www.springframework.org/schema/context"        xsi:schemaLocation="http://www.springframework.org/schema/beans         https://www.springframework.org/schema/beans/spring-beans.xsd          http://www.springframework.org/schema/context          https://www.springframework.org/schema/context/spring-context.xsd">      <!-- 開啟注解配置 -->     <context:annotation-config />     <!-- 注冊配置類 -->     <bean class="com.huodd.config.AnnotationConfigConfiguration"/> </beans>

4.2 注解引用XMl

@Configuration @ImportResource("classpath:annotation/demo-beans.xml") public class ImportXmlAnnotationConfiguration {  }

二、IoC的依賴注入

1.Setter屬性注入

創(chuàng)建對象 將屬性值set進(jìn)去 之后返回對象

@Bean public Person person() {     Person person = new Person();     person.setId(1);     person.setName("PoXing");     person.setAge(18);     return person; }

xml中的setter注入

<bean id="person" class="com.huodd.bean.Person">     <property name="id" value="1"/>     <property name="name" value="PoXing"/>     <property name="age" value="18"/> </bean>

2. 構(gòu)造器注入

使用構(gòu)造器注入,需要在bean本身添加有參構(gòu)造方法, 如在Person中添加有參構(gòu)造方法如下

public Person(Integer id, String name, Integer age) {         this.id = id;         this.name = name;         this.age = age; }

注解驅(qū)動中,我們創(chuàng)建bean的時候注入屬性時 就需要同時指定參數(shù)值

@Bean public Person person() {     return new Person(1, "PoXing", 18); }

xml驅(qū)動中如下

<bean id="person" class="com.huodd.bean.Person">     <!--    index: 表示構(gòu)造器的參數(shù)索引   value: 表示對應(yīng)的參數(shù)值  -->     <constructor-arg index="0" value="1"/>     <constructor-arg index="1" value="PoXing"/>     <constructor-arg index="2" value="18"/> </bean>

3. 注解式屬性注入

這里先說明一下,為何會有注解式屬性值注入. 細(xì)心的小伙伴可能會發(fā)現(xiàn) 上面我們談到的 Setter屬性注入、構(gòu)造器注入好像在只能是在使用  @Bean注解的時候時候使用, 但是 如果是通過標(biāo)注  @Component注解的組件呢(像前面我們的Person類中標(biāo)注了@Component注解),怎么給它設(shè)定屬性值, 該節(jié)主要就是說一下這部分

@Component 下的屬性注入

這里我們使用Dog類做為演示(這里我悄悄的添加了@Component注解 自己嘗試的小伙伴要注意哦 否則會報錯的)

@Component public class Dog {     private Integer id;     private String name;     private Integer age;     ... 省略 Getter、Setter    ... 省略 toString  }

這里要實(shí)現(xiàn)注解式屬性注入,可以直接在要注入的字段上標(biāo)注 @Value注解 如

@Value("1") private Integer id;  @Value("wangcai") private String name;  @Value("3") private Integer age;

啟動類代碼如下

public class DiApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext("com.huodd.bean");         Dog dog = ctx.getBean(Dog.class);         System.out.println(dog);     } }

控制臺打印結(jié)果

Dog{id=1, name='wangcai', age=3}

外部配置文件(@PropertySource)

這里主要是解決上面的@Value中注入 我們把屬性值直接固定寫死了,如果要修改 還要去Java代碼中去修改,很不符合開發(fā)規(guī)范,

SpringFramework為我們擴(kuò)展了新的注解@PropertySource 主要用來導(dǎo)入外部配置文件

1.這里我們創(chuàng)建一個 dog.properties

dog.id=1 dog.name=wangcai dog.age=3

2.引入配置文件

@PropertySource("classpath:di/dog.properties") @ComponentScan("com.huodd.bean") @Configuration public class DemoComponentScanConfiguration { }

3.Dog類中屬性注入 這里@Value需要配合占位符 來獲取properties配置文件中的內(nèi)容

@Value("${dog.id}") private Integer id;  @Value("${dog.name}") private String name;  @Value("${dog.age}") private Integer age;

4.修改一下啟動類

public class DiApplication {     public static void main(String[] args) {         ApplicationContext ctx = new AnnotationConfigApplicationContext(DemoComponentScanConfiguration.class);         Dog dog = ctx.getBean(Dog.class);         System.out.println(dog);     } }

控制臺打印結(jié)果如下

Dog{id=1, name='wangcai', age=3}

此時配置文件的屬性已經(jīng)注入成功

4.自動注入

在xml模式中有ref屬性 可以將一個bean注入到另外一個bean中, 注解模式中也同樣可以

@Autowired

給Dog的bean中注入 Person的Bean (即 給dog指定它的主人)

方法1 &rarr; 在屬性上標(biāo)注

@Component public class Dog {     // ......     @Autowired     private Person person; }

方法2 &rarr; 使用構(gòu)造器注入方式

@Component public class Dog {     // ......     private Person person;      @Autowired     public Dog(Person person) {      this.person = person;     } }

方法3 &rarr; 使用setter方法注入

@Component public class Dog {     // ......     private Person person;          @Autowired     public void setPerson(Person person) {         this.person = person;     } }

JSR250規(guī)范下的@Resource

@Resource也是用來屬性注入的注解

它與@Autowired的區(qū)別是:

  • @Autowired是按照類型注入

  • @Resource是按照屬性名(也就是bean的名稱)注入

@Resource 注解相當(dāng)于標(biāo)注@Autowired @Qualifier

@Qualifier這里簡要說明下,為指定bean的名稱而存在,如果存在多個相同的bean,而bean的名稱不同,我們可以使用@Autowired 配置  @Qualifier注解

如: 下面表示該Dog類注入的主人Bean是名稱為 xiaowang的, 而當(dāng)前容器內(nèi)可能存在多個 主人bean對象 比如 xiaoli、xiaoming  ....

@Component public class Dog {     // ......     @Autowired     @Qualifier("xiaowang")     private Person person; }

下面如果使用@Resource 可以更方便些 代碼如下

@Component public class Dog {     // ......     @Resource(name="xiaowang")     private Person person; }

JSR330規(guī)范下的@Inject

@Inject注解也是按照類型注入,與@Autowire的策略一樣, 不過如要使用@Inject 需要額外的導(dǎo)入依賴

<!-- jsr330 --> <dependency>     <groupId>javax.inject</groupId>     <artifactId>javax.inject</artifactId>     <version>1</version> </dependency>

后面的使用方法就與SpringFramework 原生的 @Autowire + @Qualifier 相同了

@Component public class Dog {          @Inject // 等同于@Autowired     @Named("xiaowang") // 等同于@Qualifier     private Person person;

它與@Autowired的區(qū)別是:

  • @Autowired所在的包為 org.springframework.beans.factory.annotation.Autowired 即為  SpringFramework 提供的

  • @Inject所在的包為 javax.inject.Inject 屬于JSR的規(guī)范  也就是說如果不使用SpringFramework時可以使用該注解

5. 復(fù)雜類型注入

Array注入

<property name="names">     <array>         <value>PoXing</value>         <value>LaoWang</value>     </array> </property>

List注入

<property name="tels">     <list>         <value>13000000000</value>         <value>13000000001</value>     </list> </property>

Set注入-

<!-- 已經(jīng)提前聲明好的Dog --> <bean id="wangcai" class="com.huodd.bean.ext.Dog"/> ---  <property name="dogs">     <set>         <bean class="com.huodd.bean.Dog"/>         <ref bean="wangcai"/>     </set> </property>

Map注入

<property name="homesMap">     <map>         <entry key="1" value="main">          <ref bean="myHome1" />         </entry>         <entry key="2" value="other">              <ref bean="myHome2" />         </entry>     </map> </property>

Properties注入

<property name="props">     <props>         <prop key="sex">男</prop>         <prop key="age">18</prop>     </props> </property>

面試題

1.@Autowired注入原理是什么?

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 先拿屬性對應(yīng)的類型,去IoC容器中找相應(yīng)的Bean

  3. 如果沒有找到 直接拋出NoUniqueBeanDefinitionException異常

  4. 如果找到一個 直接返回

  5. 如果找到多個相同類型的bean 再拿屬性名去與這多個bean的id進(jìn)行對比

  6. 如果有多個或者沒有 則會拋出NoUniqueBeanDefinitionException異常

  7. 如果只有一個 直接返回

2.依賴注入的方式有哪些,都有什么區(qū)別

如何理解IoC的依賴注入

3.自動注入的注解對比

如何理解IoC的依賴注入

@Qualifier :如果被標(biāo)注的成員/方法在根據(jù)類型注入時發(fā)現(xiàn)有多個相同類型的 Bean ,則會根據(jù)該注解聲明的 name 尋找特定的  bean

@Primary :如果有多個相同類型的 Bean 同時注冊到 IOC 容器中,使用 “根據(jù)類型注入” 的注解時會注入標(biāo)注 @Primary 注解的  bean 即默認(rèn)策略

4.使用依賴注入有什么優(yōu)缺點(diǎn)

依賴注入作為 IOC 的實(shí)現(xiàn)方式之一,目的就是解耦,我們不需要直接去 new 那些依賴的類對象就可以直接從容器中去取來使用,  如果組件存在多級依賴,依賴注入可以將這些依賴的關(guān)系簡化。

依賴對象的可配置:通過 xml 或者注解聲明,可以指定和調(diào)整組件注入的對象,借助 Java  的多態(tài)特性,可以不需要大批量的修改就完成依賴注入的對象替換

感謝各位的閱讀,以上就是“如何理解IoC的依賴注入”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對如何理解IoC的依賴注入這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

分享名稱:如何理解IoC的依賴注入
鏈接地址:http://muchs.cn/article0/gecgoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、網(wǎng)站設(shè)計、動態(tài)網(wǎng)站、品牌網(wǎng)站設(shè)計用戶體驗(yàn)、虛擬主機(jī)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作