Spring初步學習——Spring IOC/DI

   秋招10月底結束後,自己就又恢復之前的墮落了,沒有了秋招的那股勁和上進心,最近也開始要畢設了,自己還是一樣的渣,決定站起來,馬上都快就業的人什麼都不會有點說不過去了!站起來,我還能學!於是乎爲畢設做點準備,開始着手學習框架,首先讓我們從萬能的spring開始着手學起。

——>spring設計的領域有:

               移動開發、社交API集成、NoSQL數據庫、雲計算以及大數據都是spring正在涉足和創新的領域

——>spring的常用術語:

               1、框架:是能夠完成一定功能的半成品

               2、非侵入式設計:從框架的角度理解,就是無需繼承提供的任何類

               3、輕量級和重量級:輕量級相對於重量級而言的,輕量級一般就是非侵入性的、所 依賴的東西非常少、資源佔用非常                      少、部署簡單等等;即比較容易使用。

               4、JavaBean:符合javaBean規範的類

              5、pojo:(Plain Old Java Object),簡單老式java對象

              6、容器:裝對象的對象,並且管理對象的生命週期

一、首先我們來了解一下什麼是spring?

1、spring是一個輕量級的DI/IOC和AOP容器的開源框架

2、spring提倡以“最少侵入“的方式來管理應用中的代碼

3、spring的根本使命:簡化java開發

二、讓我們對spring的整體框架有個瞭解:

  • Data Access/Integration層包含:JDBC、ORM、OXM、JMS和Transaction模塊
  • Web層包含:Web、Web-Servlet、WebSocket、Web-Porlet模塊
  • AOP模塊:提供了一個符合AOP聯盟標準的面向切面編程的實現
  • Core Container(核心容器) :包含Beans、Core、Context和SpEL模塊
  • Test模塊:支持使用Junit和TestING對Spring組件進行測試

三、Spring的優勢有哪些?

  • 低侵入/低耦合:降低組件之間的耦合度,實現軟件各層之間的解耦 
  • 聲明式事務管理:基於切面和慣例
  • 方便集成其他框架:如mybatis、Hibernate
  • 降低java開發難度
  • Spring框架包括了J2EE三層的每一層的解決方案(一站式)

 四、Spring能幫我們做什麼?

1、能夠幫助我們根據配置文件創建及組裝對象之間的依賴關係

2、能夠幫助我們無耦合的實現日誌記錄,性能統計,安全控制

3、能非常簡單的幫我們管理數據庫事務

4、能提供第三方數據訪問框架無縫集成,而且自己也提供了一套JDBC訪問模塊來方便數據庫訪問

5、提供與第三方Web框架無縫集成,而且自己也提供了一套Spring MVC框架,來方便web層的搭建

6、spring能方便的與java EE(如Java Mail、任務調度)整合,與更多技術整合比如緩存框架

 

接下來我們步入Spring的正式學習階段:

Spring IOC和DI簡介 

IOC:Inverse of Control,控制反轉,就是原來在程序中我們採取手動創建對象,現在是交給Spring來創建對象,我們只需要獲取對象,而不過問出處。也就是將對象的控制權交給了Spring框架

Spring IOC容器的設計主要是基於以下兩個接口的:

  • BeanFactory
  • ApplicationContext

      ApplicationContext是BeanFactory的子接口之一,BeanFactory是Spring IOC容器所定義的最底層接口,大部分情況下都會使用ApplicationContext作爲Spring IOC的容器,接下來我們來看一下BeanFactory的一些常見方法:

1》【getBean】對應了多個方法來獲取Spring  IOC容器的Bean

     ①按照類型拿bean:bean =(Bean)factory.getBean(Bean.class);//要求實例唯一,否則無法確定

     ②按照bean的名字拿bean:bean =(Bean)factory.getBean("BeanName");//不太安全,IDE不會檢查其安全性

     ③按照bean的名字和類型拿:bean =(Bean)factory.getBean("beanName",Bean.class);//推薦使用

2》 【isSingleton】用於判斷是否是單例,如果判斷爲真,其意思是該Bean在容器中作爲唯一一個單例存在的,而【isPrototype】則相反,如果判斷爲真,意思是當你從容器中獲取bean時,容器會爲你重新生成一個新的實例

3》【getAliases】方法是獲取別名的方法

接下來我們來認識一個 ApplicationContext 的一些常見實現類

1、ClassPathXmlApplicationContext——讀取classpath中的資源

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

2、FileSystemXmlApplicationContext——讀取指定路徑的資源

ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");

3、XmlWebApplicationContext——需要在Web的環境下才可以運行

XmlWebApplicationContext ac  = new XmlWebApplicationContext();//初始化容器

ac.setService(servletContext) ;//需要指定ServletContext對象

ac.setConfigLocation("/WEB-INF/applicationContext.xml");//指定配置文件路徑,開頭斜線表示web應用的根目錄

ac.refresh();//初始化容器

現在,馬上,立刻——我們舉例實戰嘍(我採用的是IDEA進行操作),學習一個ApplicationContext的子類ClassPathXmlApplicationContext

1、編寫spring框架的首要任務是將需要用到的jar包導入項目,設置依賴

1.1、在Package,【src】->【pojo】下新建一個【Source】類:

package pojo; 

public class Source { 

    private String fruit; // 類型 

    private String sugar; // 糖分描述 

    private String size; // 大小杯 

    /* setter and getter */ 

}

 1.2、再在【src】目錄下新建一個【applicationContext.xml】文件,用於配置Spring,通過xml文件配置的方式裝配我們的bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="source" class="pojo.Source">
        <property name="fruit" value="橙子"/>
        <property name="sugar" value="多糖"/>
        <property name="size" value="超大杯"/>
    </bean>
</beans>

1.3、再在【test】下新建一個【TestSpring】類:

package test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Source;

public class TestSpring {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"applicationContext.xml"}
        );

        Source source = (Source) context.getBean("source");
        System.out.println(source.getFruit());
        System.out.println(source.getSugar());
        System.out.println(source.getSize());
    }
}

 1.4、測試運行:即可以正常拿到通過xml配置的bean,Source

運行結果如下:

橙子
多糖
超大杯

Spring IOC的容器的初始化和依賴注入:

Bean的定義和初始化在Spring IOC容器是兩大步驟

Bean的定義分爲3步:

1、Resource定位,通過xml配置或者註解的方式

2、BeanDefinition的載入,此時還不會創建Bean的實例

3、BeanDefinition的註冊,這個過程就是將BeanDefinition的信息發佈到Spring IOC容器中

這個時候還只是被定義,沒有對應的實例,沒有完成依賴注入,此時還不能夠完全使用,Spring Bean還有一個配置選項【lazy-init】,其含義就是是否初始化Spring Bean,在沒有任何配置的情況下,他的默認值爲default,實際值爲false,也就是Spring IOC默認會自動初始化Bean。如果將其設置爲true,那麼只有當我們使用Spring IOC容器的getBean()方法獲取它時,纔會進行Bean的初始化,完成依賴注入

裝配Spring Bean詳解

Spring中提供了3中方法進行配置:

  1. 在xml文件中顯式配置(最後,簡單易懂,當時用第三方類的時候,就只能採取這種方式了)
  2. 在java的接口和類中實現配置(其次採取,避免了xml配置的泛濫,也較爲容易)
  3. 隱式Bean、的發現機制和自動裝配原則(優先使用,減少程序開發者的決定權,簡單而不失靈活)

1》通過XML、配置裝配Bean

使用xml裝配Bean需要定義對應的XML,這裏需要引入對應的XML模式(XSD)文件,這些文件會定義配置Spring Bean的一些元素,當我們在IDEA中創建XML文件時,會有友好的提示

先來一個最簡單的裝配:

<bean id="c" class="pojo.Category">
    <property name="name" value="測試" />
</bean>
  • 【id 屬性是 Spring 能找到當前 Bean 的一個依賴的編號,遵守 XML 語法的 ID 唯一性約束。必須以字母開頭,可以使用字母、數字、連字符、下劃線、句號、冒號不能以 / 開頭
    不過 id 屬性不是一個必需的屬性name 屬性也可以定義 bean 元素的名稱,能以逗號或空格隔開起多個別名,並且可以使用很多的特殊字符,比如在 Spring 和 Spring MVC 的整合中,就得使用 name 屬性來定義 bean 的名稱,並且使用 / 開頭。
    注意: 從 Spring 3.1 開始,id 屬性也可以是 String 類型了,也就是說 id屬性也可以使用 / 開頭,而 bean 元素的 id 的唯一性由容器負責檢查。
    如果 id 和 name 屬性都沒有聲明的話,那麼 Spring 將會採用 “全限定名#{number}” 的格式生成編號。 例如這裏,如果沒有聲明 “id="c"” 的話,那麼 Spring 爲其生成的編號就是 “pojo.Category#0”,當它第二次聲明沒有 id屬性的 Bean 時,編號就是 “pojo.Category#1”,以此類推。
  • 【class】 屬性顯然就是一個類的全限定名
  • 【property】元素是定義類的屬性,其中的 name 屬性定義的是屬性的名稱,而 value 是它的值。
  • 【ref】屬性注入對象,引用自己定義的類對應的bean

當然也可以裝配集合,例如:Set,Map,List,Array和Properties等,具體我們舉例看一下

package pojo;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class ComplexAssembly {
    
    private Long id;
    private List<String> list;
    private Map<String, String> map;
    private Properties properties;
    private Set<String> set;
    private String[] array;

    /* setter and getter */
}
<bean id="complexAssembly" class="pojo.ComplexAssembly">
    <!-- 裝配Long類型的id -->
    <property name="id" value="1"/>
    
    <!-- 裝配List類型的list -->
    <property name="list">
        <list>
            <value>value-list-1</value>
            <value>value-list-2</value>
            <value>value-list-3</value>
        </list>
    </property>
    
    <!-- 裝配Map類型的map -->
    <property name="map">
        <map>
            <entry key="key1" value="value-key-1"/>
            <entry key="key2" value="value-key-2"/>
            <entry key="key3" value="value-key-2"/>
        </map>
    </property>
    
    <!-- 裝配Properties類型的properties -->
    <property name="properties">
        <props>
            <prop key="prop1">value-prop-1</prop>
            <prop key="prop2">value-prop-2</prop>
            <prop key="prop3">value-prop-3</prop>
        </props>
    </property>
    
    <!-- 裝配Set類型的set -->
    <property name="set">
        <set>
            <value>value-set-1</value>
            <value>value-set-2</value>
            <value>value-set-3</value>
        </set>
    </property>
    
    <!-- 裝配String[]類型的array -->
    <property name="array">
        <array>
            <value>value-array-1</value>
            <value>value-array-2</value>
            <value>value-array-3</value>
        </array>
    </property>
</bean>

總結:

  • List屬性爲對應的<list>元素進行裝配,然後通過多個<value>元素設值
  • Map屬性爲對應的<map>元素進行裝配,然後通過多個<entry>元素設值,只是<entry>包含一個鍵值對(key-vlue)的設置
  • Properties屬性爲對應的<properties>元素進行裝配,通過多個<properties>元素設指,只是<properties>元素有一個必填的屬性【key】,然後可以設置值
  • Set屬性對應的<set>元素進行裝配,然後通過多個<value>元素設值
  • 對於數組而言,可以使用<array>設置值,然後通過多個<value>元素設置值

命名空間裝配

Spring還提供了對應的命名空間的定義,只是在使用命名空間的時候要先引入對應的命名空間和XML模式(XSD)文件

1》【c-命名空間】(是通過構造器參數的方式)

是在Spring3.0中引入的,它在XML中更爲簡潔的描述構造器參數的方式,要使用它的話,必須在XML的頂部生命其模式

假設現在有這樣一個類:

package pojo;

public class Student {

    int id;
    String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
    // setter and getter
}

在c-命名空間和模式聲明之後,我們就可以使用他來聲明構造器參數了

<!-- 引入 c-命名空間之前 -->
<bean name="student1" class="pojo.Student">
    <constructor-arg name="id" value="1" />
    <constructor-arg name="name" value="學生1"/>
</bean>

<!-- 引入 c-命名空間之後 -->
<bean name="student2" class="pojo.Student"
      c:id="2" c:name="學生2"/>

c-命名空間屬性名以 “c:” 開頭,也就是命名空間的前綴。接下來就是要裝配的構造器參數名,在此之後如果需要注入對象的話則要跟上 -ref(如c:card-ref="idCard1",則對 card 這個構造器參數注入之前配置的名爲 idCard1 的 bean)

很顯然,使用 c-命名空間屬性要比使用 <constructor-arg> 元素精簡,並且會直接引用構造器之中參數的名稱,這有利於我們使用的安全性。

我們有另外一種替代方式:(索引的方式)

<bean name="student2" class="pojo.Student"
      c:_0="3" c:_1="學生3"/>

2》【p-命名空間】(採用setter的注入方式)

再引入聲明之後,我們就可以通過p-命名空間來設置屬性(這個例子需要先刪除構造函數,不然要配置<constructor-arg>元素)

<!-- 引入p-命名空間之前 -->
<bean name="student1" class="pojo.Student">
    <property name="id" value="1" />
    <property name="name" value="學生1"/>
</bean>

<!-- 引入p-命名空間之後 -->
<bean name="student2" class="pojo.Student" 
      p:id="2" p:name="學生2"/>
<!--如果屬性需要注入其他Bean的話,也可以在後面跟上-ref-->
<bean name="student2" class="pojo.Student"
      p:id="2" p:name="學生2" p:cdCard-ref="cdCard1"/>

3》【util-命名空間】

我們來看一下引入前後的變化:

<!-- 引入util-命名空間之前 -->
<property name="list">
    <list>
        <ref bean="bean1"/>
        <ref bean="bean2"/>
    </list>
</property>

<!-- 引入util-命名空間之後 -->
<util:list id="list">
    <ref bean="bean1"/>
    <ref bean="bean2"/>
</util:list>

4》【import】(引入其他配置文件)

<import resource="bean.xml" />

2》通過註解裝配Bean

     上面我們學習了通過XML文件的方式來裝配Bean,接下來我們來學使用註解(annotation)的方式裝配Bean

在Spring中提供了兩種方式讓Spring IOC容器發現Bean:

  • 組件掃描:通過定義資源的方式,讓Spring IOC容器掃描對應的包,從而把bean裝配進來
  • 自動裝配:通過註解定義,使得一些依賴關係可以通過註解完成

【使用@Component裝配Bean】

package pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "student1")
public class Student {

    @Value("1")
    int id;
    @Value("student_name_1")
    String name;

    // getter and setter
}

@Component註解:表示Spring IOC會把這個類掃描成一個bean實例,而其中的value屬性代表這個類在Spring中的id

<bean id="student1" class="pojo.Student" />
相當於
@Component("student1"),甚至直接寫成@Component,Spring IOC容器默認以類名來命名,作爲id,只不過首字母小寫

 @Value註解:表示值的注入,和XML中寫的value屬性是一致的

這個時候我們聲明瞭這個類,但是Spring IOC並不知道有這個Bean,所以我們就可以使用一個StudentConfig類去告訴Spring IOC:

package pojo;//該類和Student類位於同一個包名下
import org.springframework.context.annotation.ComponentScan;

@ComponentScan//代表進行掃描,默認是掃描當前包的路徑,掃描所有帶有@Component註解的POJO
public class StudentConfig {
}

接下來我們通過Spring IOC容器的實現類——AnnotationConfigApplicationContext去生成IOC容器:

ApplicationContext context = new 
    AnnotationConfigApplicationContext(StudentConfig.class);//使用AnnotationConfigApplicationContext類去初始化Spring IOC容器,他的配置項是StudentConfig類,
Student student = (Student) context.getBean("student1",
    Student.class);
student.printInformation();

【弊端】:

  • 對於@Component註解,他只是掃描所在包的java類,但是更多的時候我們希望的是可以掃描我們指定的類
  • 通過@Value不能夠注入對象

關於@Component的兩個配置項:basePackages、basePackageClasses,均是爲其包和子包進行掃描裝配對應配置的Bean

【自動裝配——@Autowired】

自動裝配技術是一種由Spring自己發現對應的Bean,自動完成裝配工作的方式,通過@Autowired,這個時候spring會根據類型去尋找定義的Bean然後將其注入,接下來看實例:

1、在Package【service】下創建一個StudentService接口:

package service;

public interface StudentService {
    public void printStudentInfo();
}

2、爲上面的接口創建一個StudentServiceImpl實現類

 

package service;

import org.springframework.beans.factory.annotation.Autowired;
import pojo.Student;

@Component("studentService")
public class StudentServiceImp implements StudentService {

    @Autowired//表示在Spring IOC定位所有的Bean後,這個字段需要按類型注入,這樣IOC容器就會尋找資源,然後注入
    private Student student = null;

     // getter and setter

    public void printStudentInfo() {
        System.out.println("學生的 id 爲:" + student.getName());
        System.out.println("學生的 name 爲:" + student.getName());
    }
}

3、編寫測試類

// 第一步:修改 StudentConfig 類,告訴 Spring IoC 在哪裏去掃描它:
package pojo;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = {"pojo", "service"})
public class StudentConfig {
}

// 或者也可以在 XML 文件中聲明去哪裏做掃描
<context:component-scan base-package="pojo" />
<context:component-scan base-package="service" />

// 第二步:編寫測試類:
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import pojo.StudentConfig;
import service.StudentService;
import service.StudentServiceImp;

public class TestSpring {

    public static void main(String[] args) {
        // 通過註解的方式初始化 Spring IoC 容器
        ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class);
        StudentService studentService = context.getBean("studentService", StudentServiceImp.class);
        studentService.printStudentInfo();
    }
}

過程:定義Bean——>初始化Bean,掃描——>根據屬性需要從Spring IOC容器中搜尋滿足要求的Bean——>滿足要求則注入

但是自動裝配也有一定的歧義,當我們同時有兩個實例,那麼Spring IOC就會不知所措,該引入哪一個Bean,爲了消除歧義,Spring提供了兩個註解:

@Primary註解:代表首要的,會優先注入使用該註解的類

@Qualifier註解:指定注入名稱Bean的資源

3》【使用@Bean裝配Bean】

當引入第三方包的(jar文件),往往沒有這些包的資源,就無法通過@Component註解,這時候就需要使用@Bean註解,註解到方法上,使之成爲Spring中返回對象爲Spring的Bean資源

首先我們在Package【pojo】下新建一個類,用來測試@Bean註解

package pojo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration//該註解相當於XML文件的根元素,必須要有才能夠解析@Bean註解
public class BeanTester {

    @Bean(name = "testBean")
    public String test() {
        String str = "測試@Bean註解";
        return str;
    }
}

然後在測試類中編寫代碼,從Spring IOC容器中獲取這個Bean

// 在 pojo 包下掃描
ApplicationContext context = new AnnotationConfigApplicationContext("pojo");
// 因爲這裏獲取到的 Bean 就是 String 類型所以直接輸出
System.out.println(context.getBean("testBean"));

@Bean 的配置項中包含 4 個配置項:

  • name: 是一個字符串數組,允許配置多個 BeanName
  • autowire: 標誌是否是一個引用的 Bean 對象,默認值是 Autowire.NO
  • initMethod: 自定義初始化方法
  • destroyMethod: 自定義銷燬方法

使用@Bean註解的好處就是能夠動態獲取一個Bean對象,能夠根據環境不同得到不同的Bean對象,或者說將Spring與其他組件分離

【Bean的作用域】

通過這些例子,想必我們已經認識Bean了,那麼Bean的作用域範圍究竟多大呢?

在默認情況下,Spring IOC容器只會對一個Bean創建實例,但是有時候我們希望可以獲取多個實例,這個時候我們就可以通過@Scope註解或者<bean>元素中的scope屬性來設置,例如:

// XML 中設置作用域
<bean id="" class="" scope="prototype" />
// 使用註解設置作用域
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Spring提供了5種作用域,他會根據情況來決定是否生成新的對象:

作用域類別 描述
singleton(單例) 在Spring IoC容器中僅存在一個Bean實例 (默認的scope)
prototype(多例) 每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時 ,相當於執行new XxxBean():不會在容器啓動時創建對象
request(請求) 用於web開發,將Bean放入request範圍 ,request.setAttribute("xxx") , 在同一個request 獲得同一個Bean
session(會話) 用於web開發,將Bean 放入Session範圍,在同一個Session 獲得同一個Bean
globalSession(全局會話) 一般用於 Porlet 應用環境 , 分佈式系統存在全局 session 概念(單點登錄),如果不是 porlet 環境,globalSession 等同於 Session

注:在開發中主要使用scope=“singlen”、scope=“prototype“,對於MVC中的Action使用prototype類型,其他使用singleton,Spring容器會管理Action對象的創建,此時把Action的作用域設置爲prototype

【Spring表達式語言簡要說明】

Spring還提供了更加靈活的·注入方式,那就是Spring表達式,實際上,Spring EL遠比以上注入方式要強大,他擁有很多功能

  • 使用Bean的id來引用Bean
  • 調用指定對象的方法和訪問對象的屬性
  • 進行運算
  • 提供正則表達式進行匹配
  • 集合配置

我們來看一個Spring表達式的例子

package pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("elBean")
public class ElBean {
    // 通過 beanName 獲取 bean,然後注入 
    @Value("#{role}")
    private Role role;
    
    // 獲取 bean 的屬性 id
    @Value("#{role.id}")
    private Long id;
    
    // 調用 bean 的 getNote 方法
    @Value("#{role.getNote().toString()}")
    private String note;
    /* getter and setter */
}

DI:Dependency Injection,依賴注入,指Spring創建對象的過程,將對象依賴屬性(簡單值,集合,對象)通過配置設值給對象,即通過另外一種方式爲對象設置屬性

2.1、在Package【pojo】下新建一個【JuiceMaker】類:

package pojo;

public class JuiceMaker {

    // 唯一關聯了一個 Source 對象
    private Source source = null;

    /* setter and getter */

    public String makeJuice(){
        String juice = "xxx用戶點了一杯" + source.getFruit() + source.getSugar() + source.getSize();
        return juice;
    }
}

 2.2在xml文件中配置JuiceMaker對象,這裏我們通過ref來注入另一個對象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="source" class="pojo.Source">
        <property name="fruit" value="橙子"/>
        <property name="sugar" value="多糖"/>
        <property name="size" value="超大杯"/>
    </bean>
    <bean name="juickMaker" class="pojo.JuiceMaker">
        <property name="source" ref="source" />
    </bean>
</beans>

 2.3在【TestSpring】中添加如下代碼:

package test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.JuiceMaker;
import pojo.Source;

public class TestSpring {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"applicationContext.xml"}
        );

        Source source = (Source) context.getBean("source");
        System.out.println(source.getFruit());
        System.out.println(source.getSugar());
        System.out.println(source.getSize());

        JuiceMaker juiceMaker = (JuiceMaker) context.getBean("juickMaker");
        System.out.println(juiceMaker.makeJuice());
    }
}

2.4運行結果 如下:

橙子
多糖
超大杯
xxx用戶點了一杯橙子多糖超大杯

 總結:IOC和DI其實是同一個概念的不同角度的描述,DI相對於IOC而言,

            明確描述了”被注入對象依賴IOC容器,IOC容器配置依賴對象“

IOC如何實現的?

設想一下,我們如果自己來實現這個依賴注入功能,該怎麼做?

1、讀取標註或者配置文件,看看JuiceMaker依賴的是哪個Source,拿到類名

2、使用反射的API,基於類名實例化對應的對象實例

3、將對象實例,通過構造函數或者setter,傳遞給JuiceMaker

          可以看出來,IOC其實就是一個工廠模式的升級版。

與傳統方式對比:

    我們之前創建對象都是通過new關鍵字主動創建一個對象,上面我們是通過IOC方式,對象的生命週期由Spring來管理,直接從Spring那裏獲取一個對象,IOC(控制反轉),將控制權轉交給Spring

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章