您好,登錄后才能下訂單哦!
什么是IOC容器設(shè)計(jì)理念以及源碼怎么寫,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
?、IOC核?理論回顧
知識(shí)點(diǎn):
1. Ioc理念概要
2. 實(shí)體Bean的創(chuàng)建
3. Bean的基本特性
4. 依賴注?
1、Ioc理論概要
在JAVA的世界中,?個(gè)對(duì)象A怎么才能調(diào)?對(duì)象B?通常有以下?種?法。
類別描述時(shí)間點(diǎn)
外部傳?
構(gòu)造?法傳?創(chuàng)建引?對(duì)象時(shí)
屬性設(shè)置傳?設(shè)置對(duì)象狀態(tài)時(shí)
運(yùn)?時(shí)做為參數(shù)傳?調(diào)?時(shí)
內(nèi)部創(chuàng)建
屬性中直接創(chuàng)建創(chuàng)建引?對(duì)象時(shí)
初始化?法創(chuàng)建創(chuàng)建引?對(duì)象時(shí)
運(yùn)?時(shí)動(dòng)態(tài)創(chuàng)建調(diào)?時(shí)
上表可以看到, 引??個(gè)對(duì)象可以在不同地點(diǎn)(其它引?者)、不同時(shí)間由不同的?法完
成。如果B只是?個(gè)?常簡(jiǎn)單的對(duì)象 如直接new B(),怎樣都不會(huì)覺得復(fù)雜,?如你從來(lái)不會(huì)
覺得創(chuàng)建?個(gè)St ring 是?個(gè)件復(fù)雜的事情。但如果B 是?個(gè)有著復(fù)雜依賴的Service對(duì)象,這
時(shí)在不同時(shí)機(jī)引?B將會(huì)變得很復(fù)雜。
?時(shí)?刻都要維護(hù)B的復(fù)雜依賴關(guān)系,試想B對(duì)象如果項(xiàng)?中有上百過,系統(tǒng)復(fù)雜度將會(huì)成陪
數(shù)增加。
IOC容器的出現(xiàn)正是為解決這?問題,其可以將對(duì)象的構(gòu)建?式統(tǒng)?,并且?動(dòng)維護(hù)對(duì)象的依
賴關(guān)系,從?降低系統(tǒng)的實(shí)現(xiàn)成本。前提是需要提前對(duì)?標(biāo)對(duì)象基于XML進(jìn)?聲明。
2、實(shí)體Bean的構(gòu)建
a. 基于Class構(gòu)建
b. 構(gòu)造?法構(gòu)建
c. 靜態(tài)???法創(chuàng)建
d. Fact oryBean創(chuàng)建
1、基于ClassName構(gòu)建
這是最常規(guī)的?法,其原理是在spring底層會(huì)基于class 屬性 通過反射進(jìn)?構(gòu)建。
2、構(gòu)造?法構(gòu)建
如果需要基于參數(shù)進(jìn)?構(gòu)建,就采?構(gòu)造?法構(gòu)建,其對(duì)應(yīng)屬性如下:
name:構(gòu)造?法參數(shù)變量名稱
t ype:參數(shù)類型
index:參數(shù)索引,從0開始
value:參數(shù)值,spring 會(huì)?動(dòng)轉(zhuǎn)換成參數(shù)實(shí)際類型值
ref :引?容串的其它對(duì)象
3、靜態(tài)???法創(chuàng)建
<bean class="com.tuling.spring.1 HelloSpring"></bean>
1 <bean class="com.tuling.spring.HelloSpring">
2 <constructor-arg name="name" type="java.lang.String" value="luban"/>
3 <constructor-arg index="1" type="java.lang.String" value="sex" />
4 </bean>
1 <bean class="com.tuling.spring.HelloSpring" factory-method="build">
2 <constructor-arg name="type" type="java.lang.String" value="B"/>
3 </bean>
如果你正在對(duì)?個(gè)對(duì)象進(jìn)?A/B測(cè)試 ,就可以采?靜態(tài)???法的?式創(chuàng)建,其于策略
創(chuàng)建不同的對(duì)像或填充不同的屬性。
該模式下必須創(chuàng)建?個(gè)靜態(tài)???法,并且?法返回該實(shí)例,spring 會(huì)調(diào)?該靜態(tài)?法
創(chuàng)建對(duì)象。
4、Fact oryBean創(chuàng)建
指定?個(gè)Bean??來(lái)創(chuàng)建對(duì)象,對(duì)象構(gòu)建初始化 完全交給該??來(lái)實(shí)現(xiàn)。配置Bean時(shí)指定該
??類的類名。
3、bean的基本特性
???? 作?范圍
???? ?命周期
???? 裝載機(jī)制
public static HelloSpring build(1 String type) {
2 if (type.equals("A")) {
3 return new HelloSpring("luban", "man");
4 } else if (type.equals("B")) {
5 return new HelloSpring("diaocan", "woman");
6 } else {
7 throw new IllegalArgumentException("type must A or B");
8 }
9 }
1 <bean class="com.tuling.spring.DriverFactoryBean">
2 <property name="jdbcUrl" value="jdbc:mysql://localhost:3306"/>
3 </bean>
1 public class DriverFactoryBean implements FactoryBean {
2 private String jdbcUrl;
3 public Object getObject() throws Exception {
4 return DriverManager.getDriver(jdbcUrl);
5 }
6 public Class<?> getObjectType() {
7 return Driver.class;
8 }
9 public boolean isSingleton() {
10 return true;
11 }
12 public String getJdbcUrl() {
13 return jdbcUrl;
14 }
15 public void setJdbcUrl(String jdbcUrl) {
16 this.jdbcUrl = jdbcUrl;
17 }
18 }
a、作?范圍
很多時(shí)候Bean對(duì)象是?狀態(tài)的 ,?有些?是有狀態(tài)的 ?狀態(tài)的對(duì)象我們采?單例即可,?有
狀態(tài)則必須是多例的模式,通過scope 即可創(chuàng)建
scope=“prot ot ype”
scope=“singlet on”
如果?個(gè)Bean設(shè)置成 prot ot ype 我們可以 通過BeanFact oryAware 獲取 BeanFact ory 對(duì)象
即可每次獲取的都是新對(duì)像。
b、?命周期
Bean對(duì)象的創(chuàng)建、初始化、銷毀即是Bean的?命周期。通過 init -met hod、dest roymet
hod 屬性可以分別指定期構(gòu)建?法與初始?法。
如果覺得麻煩,可以讓Bean去實(shí)現(xiàn) Init ializingBean.af t erPropert iesSet ()、
DisposableBean.dest roy()?法。分別對(duì)應(yīng) 初始和銷毀?法
c、加載機(jī)制
指示Bean在何時(shí)進(jìn)?加載。設(shè)置lazy-init 即可,其值如下:
t rue: 懶加載,即延遲加載
f alse:?懶加載,容器啟動(dòng)時(shí)即創(chuàng)建對(duì)象
def ault :默認(rèn),采?def ault -lazy-init 中指定值,如果def ault -lazy-init 沒指定就是
f alse
什么時(shí)候使?懶加載?
懶加載會(huì)容器啟動(dòng)的更快,??懶加載可以容器啟動(dòng)時(shí)更快的發(fā)現(xiàn)程序當(dāng)中的錯(cuò)誤 ,選擇哪
?個(gè)就看追求的是啟動(dòng)速度,還是希望更早的發(fā)現(xiàn)錯(cuò)誤,?般我們會(huì)選 擇后者。
4、依賴注?
試想IOC中如果沒有依賴注?,那這個(gè)框架就只能幫助我們構(gòu)建?些簡(jiǎn)單的Bean,?之前所說
的復(fù)雜Bean的構(gòu)建問題將?法解決,spring這個(gè)框架不可能會(huì)像現(xiàn)在這樣成功。 spring 中
ioc 如何依賴注?呢。有以下?種?式:
1. set?法注?
2. 構(gòu)造?法注?
3. ?動(dòng)注?(byName、byT ype)
4. ?法注?(lookup-met hod)
1、set?法注?
1 scope=“prototype
2 <bean class="com.tuling.spring.HelloSpring" scope="prototype">
3 </bean>
<bean class="com.tuling.spring.HelloSpring" init-method="init" destroymethod="
destroy"></bean>
1
1 <beans xmlns="http://www.springframework.org/schema/beans"
2 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"
3
4 default-lazy-init="true">
2、構(gòu)造?法注?
3、?動(dòng)注?(byName\byT ype\const ruct or)
byName:基于變量名與bean 名稱相同作為依據(jù)插?
byT ype:基于變量類別與bean 名稱作
const ruct or:基于IOC中bean 與構(gòu)造?法進(jìn)?匹配(語(yǔ)義模糊,不推薦)
4、依賴?法注?(lookup-met hod)
當(dāng)?個(gè)單例的Bean,依賴于?個(gè)多例的Bean,?常規(guī)?法只會(huì)被注??次,如果每次都
想要獲取?個(gè)全新實(shí)例就可以采?lookup-met hod ?法來(lái)實(shí)現(xiàn)。
該操作的原理是基于動(dòng)態(tài)代理技術(shù),重新?成?個(gè)繼承??標(biāo)類,然后重寫抽像?法到達(dá)注?
?的。
前?說所單例Bean依賴多例Bean這種情況也可以通過實(shí)現(xiàn) Applicat ionCont ext Aware 、
BeanFact oryAware 接?來(lái)獲取BeanFact ory 實(shí)例,從?可以直接調(diào)?get Bean?法獲取新實(shí)
例,推薦使?該?法,相?lookup-met hod語(yǔ)義邏輯更清楚?些。
?、IOC 設(shè)計(jì)原理與實(shí)現(xiàn)
<bean class="com.tuling.1 spring.HelloSpring">
2 <property name="fine" ref="fineSpring"/>
3 </bean>
1 <bean class="com.tuling.spring.HelloSpring">
2 <constructor-arg name="fine">
3 <bean class="com.tuling.spring.FineSpring"/>
4 </constructor-arg>
5 </bean>
<bean id="helloSpringAutowireConstructor"
class="com.tuling.spring.HelloSpring" autowire="byName">
1
2 </bean>
1 #編寫一個(gè)抽像類
2 public abstract class MethodInject {
3 public void handlerRequest() {
4 // 通過對(duì)該抽像方法的調(diào)用獲取最新實(shí)例
5 getFine();
6 }
7 # 編寫一個(gè)抽像方法
8 public abstract FineSpring getFine();
9 }
10 // 設(shè)定抽像方法實(shí)現(xiàn)
11 <bean id="MethodInject" class="com.tuling.spring.MethodInject">
12 <lookup-method name="getFine" bean="fine"></lookup-method>
13 </bean>
知識(shí)點(diǎn):
1、源碼學(xué)習(xí)的?標(biāo)
2、Bean的構(gòu)建過程
3、BeanFact ory與Applicat ionCont ext區(qū)別
1、源碼學(xué)習(xí)?標(biāo):
不要為了讀書?讀書,同樣不要為了閱讀源碼?讀源碼。沒有?的?頭扎進(jìn)源碼的?森林
當(dāng)中很快就迷路了。到時(shí)就不是我們讀源碼了,?是源碼‘毒’我們。畢竟?個(gè)框架是由專業(yè)團(tuán)
隊(duì),歷經(jīng)N次版本迭代的產(chǎn)物,我們不能指望像讀?本書的?式去閱讀它。 所以必須在讀源碼
之前找到?標(biāo)。是什么呢?
?家會(huì)想,讀源碼的?標(biāo)不就是為了學(xué)習(xí)嗎?這種?標(biāo)太過抽像,?標(biāo)?法驗(yàn)證。通常我
們會(huì)設(shè)定兩類型?標(biāo):?種是對(duì)源碼進(jìn)?改造,?如添加修改某些功能,在實(shí)現(xiàn)這種?標(biāo)的過
程當(dāng)中?然就會(huì)慢慢熟悉了解該項(xiàng)?。但然這個(gè)難度較?,耗費(fèi)的成本也?。另?個(gè)做法是
??提出?些問題,閱讀源碼就是為這些問題尋找答案。以下就是我們要?起在源碼中尋找答
案的問題:
1. Bean??是如何?產(chǎn)Bean的?
2. Bean的依賴關(guān)系是由誰(shuí)解來(lái)決的?
3. Bean??和應(yīng)?上?的區(qū)別?
2、Bean的構(gòu)建過程
spring.xml ?件中保存了我們對(duì)Bean的描述配置,BeanFact ory 會(huì)讀取這些配置然后?
成對(duì)應(yīng)的Bean。這是我們對(duì)ioc 原理的?般理解。但在深??些我們會(huì)有更多的問題?
1. 配置信息最后是誰(shuí)JAVA中哪個(gè)對(duì)象承載的?
2. 這些承載對(duì)象是誰(shuí)業(yè)讀取XML?件并裝載的?
3. 這些承載對(duì)象?是保存在哪??
BeanDefinit ion (Bean定義)
ioc 實(shí)現(xiàn)中 我們?cè)趚ml 中描述的Bean信息最后 都將保存?BeanDefinit ion (定義)對(duì)象中,
其中xml bean 與BeanDefinit ion 程?對(duì)?的關(guān)系。
由此可?,xml bean中設(shè)置的屬性最后都會(huì)體現(xiàn)在BeanDefinit ion中。如:
演示查看 BeanDefinit ion 屬性結(jié)構(gòu)
BeanDefinit ionRegist ry(Bean注冊(cè)器)
在上表中我們并沒有看到 xml bean 中的 id 和name屬性沒有體現(xiàn)在定義中,原因是ID 其作
為當(dāng)前Bean的存儲(chǔ)key注冊(cè)到了BeanDefinit ionRegist ry 注冊(cè)器中。name 作為別名key 注冊(cè)
到了 AliasRegist ry 注冊(cè)中?。其最后都是指向其對(duì)應(yīng)的BeanDefinit ion。
演示查看 BeanDefinit ionRegist ry屬性結(jié)構(gòu)
XML-bean BeanDefinit ion
class beanClassName
scope scope
lazy-init lazyInit
const ruct or-arg Const ruct orArgument
propert y MutablePropertyValues
f act ory-met hod f actoryMethodName
dest roy-met hod Abst ract BeanDefinit ion.dest royMet hodName
init -met hod Abst ract BeanDefinit ion.init Met hodName
aut owire Abst ract BeanDefinit ion.aut owireMode
id
name
????
????
BeanDefinit ionReader(Bean定義讀?。?br/> ?此我們學(xué)習(xí)了 BeanDefinit ion 中存儲(chǔ)了Xml Bean信息,?BeanDefinit ionRegist er 基于ID
和name 保存了Bean的定義。接下要學(xué)習(xí)的是從xml Bean到BeanDefinit ion 然后在注冊(cè)?
BeanDefinit ionRegist er 整個(gè)過程。
上圖中可以看出Bean的定義是由BeanDefinit ionReader 從xml 中讀取配置并構(gòu)建出
BeanDefinit ionReader,然后在基于別名注冊(cè)到BeanDefinit ionRegist er中。
查看BeanDefinit ???? ionReader結(jié)構(gòu)
?法說明:
???? loadBeanDefinit ions(Resource resource)
???? 基于資源裝載Bean定義并注冊(cè)?注冊(cè)器
???? int loadBeanDefinit ions(St ring locat ion)
???? 基于資源路徑裝載Bean定義并注冊(cè)?注冊(cè)器
???? BeanDefinit ionRegist ry get Regist ry()
???? 獲取注冊(cè)器
???? ResourceLoader get ResourceLoader()
???? 獲取資源裝載器
基于示例演示BeanDefinit ionReader裝載過程
Beanf act ory(bean ??)
有了Bean的定義就相當(dāng)于有了產(chǎn)品的配?,接下來(lái)就是要把這個(gè)配?送到??進(jìn)??產(chǎn)了。
在ioc當(dāng)中Bean的構(gòu)建是由BeanFact ory 負(fù)責(zé)的。其結(jié)構(gòu)如下:
????
1 //創(chuàng)建一個(gè)簡(jiǎn)單注冊(cè)器
2 BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
3 //創(chuàng)建bean定義讀取器
4 BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
5 // 創(chuàng)建資源讀取器
6 DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
7 // 獲取資源
8 Resource xmlResource = resourceLoader.getResource("spring.xml");
9 // 裝載Bean的定義
10 reader.loadBeanDefinitions(xmlResource);
11 // 打印構(gòu)建的Bean 名稱
12 System.out.println(Arrays.toString(register.getBeanDefinitionNames());
?法說明:
???? get Bean(St ring)
???? 基于ID或name 獲取?個(gè)Bean
???? <T > T get Bean(Class<T > requiredT ype)
???? 基于Bean的類別獲取?個(gè)Bean(如果出現(xiàn)多個(gè)該類的實(shí)例,將會(huì)報(bào)錯(cuò)。但可以指定
primary=“t rue” 調(diào)整優(yōu)先級(jí)來(lái)解決該錯(cuò)誤 )
???? Object get Bean(St ring name, Object ... args)
???? 基于名稱獲取?個(gè)Bean,并覆蓋默認(rèn)的構(gòu)造參數(shù)
???? boolean isT ypeMat ch(St ring name, Class<?> t ypeT oMat ch)
???? 指定Bean與指定Class 是否匹配
`
以上?法中重點(diǎn)要關(guān)注get Bean,當(dāng)?戶調(diào)?get Bean的時(shí)候就會(huì)觸發(fā) Bean的創(chuàng)建動(dòng)作,其
是如何創(chuàng)建的呢?
演示基???? 本BeanFactory獲取?個(gè)Bean
1 #創(chuàng)建Bean堆棧
2 // 其反射實(shí)例化Bean
3 java.lang.reflect.Constructor.newInstance(Unknown Source:-1)
4 BeanUtils.instantiateClass()
5 //基于實(shí)例化策略 實(shí)例化Bean
6 SimpleInstantiationStrategy.instantiate()
7 AbstractAutowireCapableBeanFactory.instantiateBean()
8 // 執(zhí)行Bean的實(shí)例化方法
9 AbstractAutowireCapableBeanFactory.createBeanInstance()
10 AbstractAutowireCapableBeanFactory.doCreateBean()
11 // 執(zhí)行Bean的創(chuàng)建
12 AbstractAutowireCapableBeanFactory.createBean()
13 // 緩存中沒有,調(diào)用指定Bean工廠創(chuàng)建Bean
14 AbstractBeanFactory$1.getObject()
15 // 從單例注冊(cè)中心獲取Bean緩存
16 DefaultSingletonBeanRegistry.getSingleton()
17 AbstractBeanFactory.doGetBean()
Bean創(chuàng)建時(shí)序圖:
從調(diào)?過程可以總結(jié)出以下?點(diǎn):
1. 調(diào)?BeanFact ory.get Bean() 會(huì)觸發(fā)Bean的實(shí)例化。
2. Def ault Singlet onBeanRegist ry 中緩存了單例Bean
3. Bean的創(chuàng)建與初始化是由Abst ract Aut owireCapableBeanFact ory 完成的。
3、BeanFactory 與 ApplicationContext區(qū)別
BeanFact ory 看下去可以去做IOC當(dāng)中的?部分事情,為什么還要去定義?個(gè)
Applicat ionCont ext 呢?
Applicat ionCont ext 結(jié)構(gòu)圖
從圖中可以看到 Applicat ionCont ext 它由BeanFact ory接?派??來(lái),因?提供了
BeanFact ory所有的功能。除此之外cont ext包還提供了以下的功能:
1. MessageSource, 提供國(guó)際化的消息訪問
2. 資源訪問,如URL和?件
3. 事件傳播,實(shí)現(xiàn)了Applicat ionList ener接?的bean
4. 載?多個(gè)(有繼承關(guān)系)上下? ,使得每?個(gè)上下?都專注于?個(gè)特定的層次,?如應(yīng)?
的web層
總結(jié)回顧:
BeanDefinit ion
Def ault ResourceLoader
XmlBeanDefinit ionReader
BeanDefinit ionRegist ry
18 // 獲取Bean
19 AbstractBeanFactory.getBean()
20 // 調(diào)用的客戶類
21 com.tuling.spring.BeanFactoryExample.main()
BeanFact ory
Def ault List ableBeanFact ory
Aut owireCapableBeanFact ory
Abst ract Aut owireCapableBeanFact ory
Singlet onBeanRegist ry
Def ault Singlet onBeanRegist ry
看完上述內(nèi)容,你們掌握什么是IOC容器設(shè)計(jì)理念以及源碼怎么寫的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。