??
IOC是什么
IoC(Inversion of Control)控制反轉(zhuǎn),包含了兩個(gè)方面:一、控制。二、反轉(zhuǎn)
類與類依賴關(guān)系交給容器處理。IoC不是一種技術(shù),只是一種思想,一個(gè)重要的面向?qū)ο缶幊痰姆▌t,它能指導(dǎo)我們?nèi)绾卧O(shè)計(jì)出松耦合、更優(yōu)良的程序。
IOC不夠開(kāi)門見(jiàn)山,于是Martin Fowler提出了DI(dependency injection)依賴注入來(lái)替代IoC,即讓調(diào)用類對(duì)某一接口實(shí)現(xiàn)類的依賴關(guān)系由第三方(容器或協(xié)作類)注入,以移除調(diào)用類對(duì)某一接口實(shí)現(xiàn)類的依賴。
IOC有兩種方式:DI(依賴注入)和DL (依賴查找)
IOC的優(yōu)點(diǎn)
- ?減少了對(duì)象的創(chuàng)建和管理 ,使代碼層次更加清晰。
- Spring 的IOC容器是一個(gè)輕量級(jí)的容器 ,沒(méi)有侵入性(不依賴容器的API) ,不需要實(shí)現(xiàn)一些特殊接口。
- 鼓勵(lì)我們面向接口編程。
- 減少了代碼的耦合,將耦合的部分推到了配置文件中 ,如果他們的關(guān)系發(fā)生了改變,只需要修改配置文件。
DL (依賴查找)
程序提供查找方式,交給容器去查找(回調(diào)函數(shù))
容器提供回調(diào)接口和上下文環(huán)境給組件。EJB和Apache Avalon都使用這種方式
下面代碼展示了基于JNDI實(shí)現(xiàn)的依賴查找機(jī)制。
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”);
}……
但是日常開(kāi)發(fā)中,EJB類似的已經(jīng)很少用到了,所以很多同學(xué)沒(méi)聽(tīng)過(guò)DL(依賴查找),這很正常,大家更熟悉的是DI(依賴注入)。
不過(guò)這兩個(gè)查找大家應(yīng)該用過(guò):
- 名稱查找 - autowireByName
- 類型查找 - autowireByType
名稱查找 - autowireByName
直接從 BeanFactory 中取出這個(gè) bean 就可以了,常用的就是@Qualifier?
類型查找 - autowireByType
常用的就是@autowire
如果容器中存在一個(gè)與指定屬性類型相同的bean,那么將與該屬性自動(dòng)裝配。如果存在多個(gè)該類型的bean,那么將會(huì)拋出異常
簡(jiǎn)單的理解就是通過(guò)類名去匹配
?DI(依賴注入)
一個(gè)對(duì)象需要另外一個(gè)對(duì)象時(shí),無(wú)需在代碼中創(chuàng)建被調(diào)用者,而是依賴于外部容器,由外部容器創(chuàng)建后傳遞給程序
用圖例說(shuō)明一下,傳統(tǒng)程序設(shè)計(jì)如下圖1,都是主動(dòng)去創(chuàng)建相關(guān)對(duì)象然后再組合起來(lái):
圖1
當(dāng)有了IoC/DI的容器后,在客戶端類中不再主動(dòng)去創(chuàng)建這些對(duì)象了,如圖2所示
圖2
IOC容器
IOC容器其實(shí)就是一個(gè)大工廠,它用來(lái)管理我們所有的對(duì)象以及依賴關(guān)系。
- 原理就是通過(guò)Java的反射技術(shù)來(lái)實(shí)現(xiàn)的!通過(guò)反射我們可以獲取類的所有信息(成員變量、類名等等等)!
- 再通過(guò)配置文件(xml)或者注解來(lái)描述類與類之間的關(guān)系
- 我們就可以通過(guò)這些配置信息和反射技術(shù)來(lái)構(gòu)建出對(duì)應(yīng)的對(duì)象和依賴關(guān)系了!
Spring容器(Bean工廠)?
- BeanFactory:這是最基礎(chǔ)、面向Spring的
- ApplicationContext:這是在BeanFactory基礎(chǔ)之上,面向使用Spring框架的開(kāi)發(fā)者。提供了一系列的功能!
ApplicationContext這個(gè)大家就很熟悉了吧,spring絕大部分應(yīng)用都是使用ApplicationContext
BeanFactory和ApplicationContext區(qū)別
BeanFactory?可以理解為含有bean集合的工廠類。BeanFactory?包含了種bean的定義,以便在接收到客戶端請(qǐng)求時(shí)將對(duì)應(yīng)的bean實(shí)例化。
BeanFactory還能在實(shí)例化對(duì)象的時(shí)生成協(xié)作類之間的關(guān)系。此舉將bean自身與bean客戶端的配置中解放出來(lái)。BeanFactory還包含了bean生命周期的控制,調(diào)用客戶端的初始化方法(initialization methods)和銷毀方法(destruction methods)。
applicationcontext是beanFactory的子接口,擁有BeanFactory的所有功能,但applicationcontext在此基礎(chǔ)上還提供了其他的功能。
- 提供了支持國(guó)際化的文本消息
- 統(tǒng)一的資源文件讀取方式
- 已在監(jiān)聽(tīng)器中注冊(cè)的bean的事件
且beanFactory是延遲加載,需要類的時(shí)候才創(chuàng)建類的實(shí)例,而ApplicationContext在初始化時(shí)就加載完成了所有的單例bean
以下是三種較常見(jiàn)的?ApplicationContext?實(shí)現(xiàn)方式:
1、ClassPathXmlApplicationContext:從classpath的XML配置文件中讀取上下文,并生成上下文定義。應(yīng)用程序上下文從程序環(huán)境變量中取得
ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);
2、FileSystemXmlApplicationContext :由文件系統(tǒng)中的XML配置文件讀取上下文。
??ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);??
?
3、XmlWebApplicationContext:由Web應(yīng)用的XML文件讀取上下文。
Spring Bean的生命周期?
Spring Bean的生命周期簡(jiǎn)單易懂。在一個(gè)bean實(shí)例被初始化時(shí),需要執(zhí)行一系列的初始化操作以達(dá)到可用的狀態(tài)。同樣的,當(dāng)一個(gè)bean不在被調(diào)用時(shí)需要進(jìn)行相關(guān)的析構(gòu)操作,并從bean容器中移除。
Spring bean factory 負(fù)責(zé)管理在spring容器中被創(chuàng)建的bean的生命周期。Bean的生命周期由兩組回調(diào)(call back)方法組成。
- 初始化之后調(diào)用的回調(diào)方法。
- 銷毀之前調(diào)用的回調(diào)方法。
Spring框架提供了以下四種方式來(lái)管理bean的生命周期事件:
- InitializingBean和DisposableBean回調(diào)接口
- 針對(duì)特殊行為的其他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開(kāi)始IOC容器裝配Bean有4種方式:
- XML配置
- 注解
- JavaConfig
- 基于Groovy DSL配置(這種很少見(jiàn))
日常開(kāi)發(fā)中,常用到的是XML配置+注解。
剩下的兩種有興趣的可以自行百度+google
依賴注入方式
依賴注入的方式有3種方式:
- 屬性注入-->通過(guò)?
?setter()?
?方法注入 - 構(gòu)造方法注入
- 工廠方法注入
構(gòu)造方法注入和屬性注入有什么區(qū)別?
- 在屬性注入方法支持大部分的依賴注入,如果我們僅需要注入int、string和long型的變量,我們不要用設(shè)值的方法注入。對(duì)于基本類型,如果我們沒(méi)有注入的話,可以為基本類型設(shè)置默認(rèn)值。在構(gòu)造方法注入不支持大部分的依賴注入,因?yàn)樵谡{(diào)用構(gòu)造方法中必須傳入正確的構(gòu)造參數(shù),否則的話為報(bào)錯(cuò)。
- 屬性注入不會(huì)重寫構(gòu)造方法的值。如果我們對(duì)同一個(gè)變量同時(shí)使用了構(gòu)造方法注入又使用了設(shè)置方法注入的話,那么構(gòu)造方法將不能覆蓋由設(shè)值方法注入的值。很明顯,因?yàn)闃?gòu)造方法盡在對(duì)象被創(chuàng)建時(shí)調(diào)用。
- 在使用屬性注入時(shí)有可能還不能保證某種依賴是否已經(jīng)被注入,也就是說(shuō)這時(shí)對(duì)象的依賴關(guān)系有可能是不完整的。而在另一種情況下,構(gòu)造器注入則不允許生成依賴關(guān)系不完整的對(duì)象。
- 在屬性注入時(shí)如果對(duì)象A和對(duì)象B互相依賴,在創(chuàng)建對(duì)象A時(shí)Spring會(huì)拋出s?
?ObjectCurrentlyInCreationException異常,因?yàn)樵贐對(duì)象被創(chuàng)建之前A對(duì)象是不能被創(chuàng)建的,反之亦然。所以Spring用設(shè)值注入的方法解決了循環(huán)依賴的問(wèn)題,因?qū)ο蟮脑O(shè)值方法是在對(duì)象被創(chuàng)建之前被調(diào)用的。?
?
Bean的作用域
Spring容器中的bean可以分為5個(gè)范圍。所有范圍的名稱都是自說(shuō)明的,但是為了避免混淆,還是讓我們來(lái)解釋一下:
使用3,4,5作用域的,需要手動(dòng)設(shè)置代理
- singleton:這種bean范圍是默認(rèn)的,這種范圍確保不管接受到多少個(gè)請(qǐng)求,每個(gè)容器中只有一個(gè)bean的實(shí)例,單例的模式由bean factory自身來(lái)維護(hù)。
- prototype:多例范圍與單例范圍相反,為每一個(gè)bean請(qǐng)求提供一個(gè)實(shí)例。
- request:在請(qǐng)求bean范圍內(nèi)會(huì)每一個(gè)來(lái)自客戶端的網(wǎng)絡(luò)請(qǐng)求創(chuàng)建一個(gè)實(shí)例,在請(qǐng)求完成以后,bean會(huì)失效并被垃圾回收器回收。
- Session:與請(qǐng)求范圍類似,確保每個(gè)session中有一個(gè)bean的實(shí)例,在session過(guò)期后,bean會(huì)隨之失效。
- global-session:global-session和Portlet應(yīng)用相關(guān)。當(dāng)你的應(yīng)用部署在Portlet容器中工作時(shí),它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲(chǔ)變量的話,那么這全局變量需要存儲(chǔ)在global-session中。全局作用域與Servlet中的session作用域效果相同。
bean的自動(dòng)裝配
使用bean元素的autowire屬性來(lái)指定Bean定義的自動(dòng)裝配,共有5中模式:
- no ? 默認(rèn)的方式是不進(jìn)行自動(dòng)裝配,通過(guò)手工設(shè)置ref 屬性來(lái)進(jìn)行裝配bean
- byName ? 依賴的 bean 名稱需要與類中引用的名稱一致? ,就會(huì)匹配依賴關(guān)系,我們?cè)陬愔械囊玫拿Q是 userAutowireDao 所以就會(huì)去匹配我們的 userAutowireDao 方法
- byType ? 通過(guò)參數(shù)的數(shù)據(jù)類型自動(dòng)自動(dòng)裝配,如果一個(gè)bean的數(shù)據(jù)類型和另外一個(gè)bean的property屬性的數(shù)據(jù)類型兼容,就自動(dòng)裝配,簡(jiǎn)單的理解就是通過(guò)類名去匹配
- construct ? 構(gòu)造方法中的參數(shù)通過(guò)byType的形式,自動(dòng)裝配。
- default 由上級(jí)標(biāo)簽<beans>的default-autowire屬性確定。
?
常用注解詳解
注解注入就是用注解標(biāo)簽的方式來(lái)替換掉我們 xml 配置文件里面 bean 的注冊(cè)和依賴
@Component
用于類上
所有的類上面都可以這么寫,通用注解,這是不規(guī)范的寫法,哈哈哈
@Repository
用于類上
這個(gè)注解主要是聲明 dao 的類組件
@Service?
這個(gè)注解主要是聲明 service 服務(wù)類
@Controller
主要是聲明控制類 (springmvc/struts2 action/controller)
@Resource?
用于類內(nèi)
javaEE 的注解 ,默認(rèn)是以 byName 方式注入,byName 找不到的話,再用 byType 去匹配
效果跟Autowired一樣,查找順序相反
@Resource有兩個(gè)屬性是比較重要的,分是name和type,Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動(dòng)注入策略,而使用type屬性時(shí)則使用byType自動(dòng)注入策略。如果既不指定name也不指定type屬性,這時(shí)將通過(guò)反射機(jī)制使用byName自動(dòng)注入策略。
@Autowired?
用于類內(nèi)
spring 的注解,默認(rèn)是以 byType 注入,-如果有多個(gè)實(shí)現(xiàn)類,他再用 byName 的方式(@Qualifier)去匹配
效果跟Resource一樣,查找順序相反
Autowired和Qualifier一起用,
eg:
@Autowired
@Qualifier(value = "TestService2")
private TestService testService;
//實(shí)現(xiàn)類
@Service("TestService1")
public class TestServiceImpl implements TestService {...}
//實(shí)現(xiàn)類
@Service("TestService2")
public class TestServiceImpl implements TestService {...}
?@Qualifier
spring的注解,可以指定實(shí)現(xiàn)的方法名稱
@Scope?
bean的作用域,可以查看上面的概念,這里就不再重復(fù)了
總結(jié)
借鑒了其他博主的思路:會(huì)整理出Spring思維導(dǎo)圖出來(lái),等AOP寫好一并放出來(lái)。
今天的spring介紹就寫到這里,再見(jiàn)!
?
本文摘自 :https://blog.51cto.com/u