秋招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中方法進行配置:
- 在xml文件中顯式配置(最後,簡單易懂,當時用第三方類的時候,就只能採取這種方式了)
- 在java的接口和類中實現配置(其次採取,避免了xml配置的泛濫,也較爲容易)
- 隱式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