當前位置:首頁 > IT技術 > 編程語言 > 正文

spring框架-認識IOC(二)
2021-12-13 17:52:03

??

IOC是什么

IoC(Inversion of Control)控制反轉,包含了兩個方面:一、控制。二、反轉

類與類依賴關系交給容器處理。IoC不是一種技術,只是一種思想,一個重要的面向對象編程的法則,它能指導我們?nèi)绾卧O計出松耦合、更優(yōu)良的程序。

IOC不夠開門見山,于是Martin Fowler提出了DI(dependency injection)依賴注入來替代IoC,即讓調(diào)用類對某一接口實現(xiàn)類的依賴關系由第三方(容器或協(xié)作類)注入,以移除調(diào)用類對某一接口實現(xiàn)類的依賴。

IOC有兩種方式:DI(依賴注入)和DL (依賴查找)


IOC的優(yōu)點


  1. ?減少了對象的創(chuàng)建和管理 ,使代碼層次更加清晰。
  2. Spring 的IOC容器是一個輕量級的容器 ,沒有侵入性(不依賴容器的API) ,不需要實現(xiàn)一些特殊接口。
  3. 鼓勵我們面向接口編程。
  4. 減少了代碼的耦合,將耦合的部分推到了配置文件中 ,如果他們的關系發(fā)生了改變,只需要修改配置文件。


DL (依賴查找)

程序提供查找方式,交給容器去查找(回調(diào)函數(shù))

容器提供回調(diào)接口和上下文環(huán)境給組件。EJB和Apache Avalon都使用這種方式

下面代碼展示了基于JNDI實現(xiàn)的依賴查找機制。

 public class MyBusniessObject{
private DataSource ds;
private MyCollaborator myCollaborator;

public MyBusnissObject(){
Context ctx = null;
try{
ctx = new InitialContext();
ds = (DataSource) ctx.lookup(“java:comp/env/dataSourceName”);
myCollaborator =
(MyCollaborator) ctx.lookup(“java:comp/env/myCollaboratorName”);
}……

但是日常開發(fā)中,EJB類似的已經(jīng)很少用到了,所以很多同學沒聽過DL(依賴查找),這很正常,大家更熟悉的是DI(依賴注入)。

不過這兩個查找大家應該用過:


  1. 名稱查找 - autowireByName
  2. 類型查找 - autowireByType

名稱查找 - autowireByName

直接從 BeanFactory 中取出這個 bean 就可以了,常用的就是@Qualifier?

類型查找 - autowireByType

常用的就是@autowire

如果容器中存在一個與指定屬性類型相同的bean,那么將與該屬性自動裝配。如果存在多個該類型的bean,那么將會拋出異常

簡單的理解就是通過類名去匹配


?DI(依賴注入)

一個對象需要另外一個對象時,無需在代碼中創(chuàng)建被調(diào)用者,而是依賴于外部容器,由外部容器創(chuàng)建后傳遞給程序

用圖例說明一下,傳統(tǒng)程序設計如下圖1,都是主動去創(chuàng)建相關對象然后再組合起來:



spring框架-認識IOC(二)_spring

圖1


當有了IoC/DI的容器后,在客戶端類中不再主動去創(chuàng)建這些對象了,如圖2所示



spring框架-認識IOC(二)_spring_02

圖2



IOC容器

IOC容器其實就是一個大工廠,它用來管理我們所有的對象以及依賴關系。


  • 原理就是通過Java的反射技術來實現(xiàn)的!通過反射我們可以獲取類的所有信息(成員變量、類名等等等)!
  • 再通過配置文件(xml)或者注解來描述類與類之間的關系
  • 我們就可以通過這些配置信息和反射技術來構建出對應的對象和依賴關系了!

Spring容器(Bean工廠)?


  1. BeanFactory:這是最基礎、面向Spring的
  2. ApplicationContext:這是在BeanFactory基礎之上,面向使用Spring框架的開發(fā)者。提供了一系列的功能!

ApplicationContext這個大家就很熟悉了吧,spring絕大部分應用都是使用ApplicationContext

BeanFactory和ApplicationContext區(qū)別

BeanFactory?可以理解為含有bean集合的工廠類。BeanFactory?包含了種bean的定義,以便在接收到客戶端請求時將對應的bean實例化。

BeanFactory還能在實例化對象的時生成協(xié)作類之間的關系。此舉將bean自身與bean客戶端的配置中解放出來。BeanFactory還包含了bean生命周期的控制,調(diào)用客戶端的初始化方法(initialization methods)和銷毀方法(destruction methods)。

applicationcontext是beanFactory的子接口,擁有BeanFactory的所有功能,但applicationcontext在此基礎上還提供了其他的功能。


  1. 提供了支持國際化的文本消息
  2. 統(tǒng)一的資源文件讀取方式
  3. 已在監(jiān)聽器中注冊的bean的事件
    且beanFactory是延遲加載,需要類的時候才創(chuàng)建類的實例,而ApplicationContext在初始化時就加載完成了所有的單例bean

以下是三種較常見的?ApplicationContext?實現(xiàn)方式:

1、ClassPathXmlApplicationContext:從classpath的XML配置文件中讀取上下文,并生成上下文定義。應用程序上下文從程序環(huán)境變量中取得

    ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);  

2、FileSystemXmlApplicationContext :由文件系統(tǒng)中的XML配置文件讀取上下文。

??ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);???

3、XmlWebApplicationContext:由Web應用的XML文件讀取上下文。

Spring Bean的生命周期?

Spring Bean的生命周期簡單易懂。在一個bean實例被初始化時,需要執(zhí)行一系列的初始化操作以達到可用的狀態(tài)。同樣的,當一個bean不在被調(diào)用時需要進行相關的析構操作,并從bean容器中移除。

Spring bean factory 負責管理在spring容器中被創(chuàng)建的bean的生命周期。Bean的生命周期由兩組回調(diào)(call back)方法組成。


  1. 初始化之后調(diào)用的回調(diào)方法。
  2. 銷毀之前調(diào)用的回調(diào)方法。

Spring框架提供了以下四種方式來管理bean的生命周期事件:


  • InitializingBean和DisposableBean回調(diào)接口
  • 針對特殊行為的其他Aware接口
  • Bean配置文件中的Custom init()方法和destroy()方法
  • @PostConstruct和@PreDestroy注解方式 使用??customInit()??和???customDestroy()????方法管理????bean????生命周期的代碼樣例如下:????<beans> <bean id="demoBean" class="com.somnus.task.DemoBean" init-method="customInit" destroy-method="customDestroy"> </bean> </beans> ???


?裝配Bean方式?

Spring4.x開始IOC容器裝配Bean有4種方式:


  1. XML配置
  2. 注解
  3. JavaConfig
  4. 基于Groovy DSL配置(這種很少見)

日常開發(fā)中,常用到的是XML配置+注解。

剩下的兩種有興趣的可以自行百度+google


依賴注入方式

依賴注入的方式有3種方式:


  1. 屬性注入-->通過??setter()??方法注入
  2. 構造方法注入
  3. 工廠方法注入

構造方法注入和屬性注入有什么區(qū)別?


  1. 在屬性注入方法支持大部分的依賴注入,如果我們僅需要注入int、string和long型的變量,我們不要用設值的方法注入。對于基本類型,如果我們沒有注入的話,可以為基本類型設置默認值。在構造方法注入不支持大部分的依賴注入,因為在調(diào)用構造方法中必須傳入正確的構造參數(shù),否則的話為報錯。
  2. 屬性注入不會重寫構造方法的值。如果我們對同一個變量同時使用了構造方法注入又使用了設置方法注入的話,那么構造方法將不能覆蓋由設值方法注入的值。很明顯,因為構造方法盡在對象被創(chuàng)建時調(diào)用。
  3. 在使用屬性注入時有可能還不能保證某種依賴是否已經(jīng)被注入,也就是說這時對象的依賴關系有可能是不完整的。而在另一種情況下,構造器注入則不允許生成依賴關系不完整的對象。
  4. 在屬性注入時如果對象A和對象B互相依賴,在創(chuàng)建對象A時Spring會拋出s??ObjectCurrentlyInCreationException異常,因為在B對象被創(chuàng)建之前A對象是不能被創(chuàng)建的,反之亦然。所以Spring用設值注入的方法解決了循環(huán)依賴的問題,因對象的設值方法是在對象被創(chuàng)建之前被調(diào)用的。??


Bean的作用域

Spring容器中的bean可以分為5個范圍。所有范圍的名稱都是自說明的,但是為了避免混淆,還是讓我們來解釋一下:

使用3,4,5作用域的,需要手動設置代理


  1. singleton:這種bean范圍是默認的,這種范圍確保不管接受到多少個請求,每個容器中只有一個bean的實例,單例的模式由bean factory自身來維護。
  2. prototype:多例范圍與單例范圍相反,為每一個bean請求提供一個實例。
  3. request:在請求bean范圍內(nèi)會每一個來自客戶端的網(wǎng)絡請求創(chuàng)建一個實例,在請求完成以后,bean會失效并被垃圾回收器回收。
  4. Session:與請求范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效。
  5. global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那么這全局變量需要存儲在global-session中。全局作用域與Servlet中的session作用域效果相同。


bean的自動裝配

使用bean元素的autowire屬性來指定Bean定義的自動裝配,共有5中模式:


  1. no ? 默認的方式是不進行自動裝配,通過手工設置ref 屬性來進行裝配bean
  2. byName ? 依賴的 bean 名稱需要與類中引用的名稱一致? ,就會匹配依賴關系,我們在類中的引用的名稱是 userAutowireDao 所以就會去匹配我們的 userAutowireDao 方法
  3. byType ? 通過參數(shù)的數(shù)據(jù)類型自動自動裝配,如果一個bean的數(shù)據(jù)類型和另外一個bean的property屬性的數(shù)據(jù)類型兼容,就自動裝配,簡單的理解就是通過類名去匹配
  4. construct ? 構造方法中的參數(shù)通過byType的形式,自動裝配。
  5. default 由上級標簽<beans>的default-autowire屬性確定。
    ?


常用注解詳解

注解注入就是用注解標簽的方式來替換掉我們 xml 配置文件里面 bean 的注冊和依賴

@Component

用于類上

所有的類上面都可以這么寫,通用注解,這是不規(guī)范的寫法,哈哈哈

spring框架-認識IOC(二)_IOC_03

@Repository

用于類上

這個注解主要是聲明 dao 的類組件

spring框架-認識IOC(二)_依賴注入_04

@Service?

這個注解主要是聲明 service 服務類

spring框架-認識IOC(二)_構造方法_05

@Controller

主要是聲明控制類 (springmvc/struts2 action/controller)

spring框架-認識IOC(二)_IOC_06

@Resource?

用于類內(nèi)

javaEE 的注解 ,默認是以 byName 方式注入,byName 找不到的話,再用 byType 去匹配

效果跟Autowired一樣,查找順序相反

@Resource有兩個屬性是比較重要的,分是name和type,Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。

spring框架-認識IOC(二)_構造方法_07

spring框架-認識IOC(二)_IOC_08

spring框架-認識IOC(二)_構造方法_09

@Autowired?

用于類內(nèi)

spring 的注解,默認是以 byType 注入,-如果有多個實現(xiàn)類,他再用 byName 的方式(@Qualifier)去匹配

效果跟Resource一樣,查找順序相反

Autowired和Qualifier一起用,

eg:

@Autowired

@Qualifier(value = "TestService2")

private TestService testService;

//實現(xiàn)類

@Service("TestService1")

public class TestServiceImpl implements TestService {...}

//實現(xiàn)類

@Service("TestService2")

public class TestServiceImpl implements TestService {...}

spring框架-認識IOC(二)_spring_10

?@Qualifier

spring的注解,可以指定實現(xiàn)的方法名稱

spring框架-認識IOC(二)_構造方法_11

@Scope?

bean的作用域,可以查看上面的概念,這里就不再重復了


總結

借鑒了其他博主的思路:會整理出Spring思維導圖出來,等AOP寫好一并放出來。

今天的spring介紹就寫到這里,再見!

?


本文摘自 :https://blog.51cto.com/u

開通會員,享受整站包年服務立即開通 >