一、Spring創(chuàng)建Bean流程
1.讀取Bean的定義信息
通過BeanDefinitionReader這個(gè)接口解析xml配置、配置類或其他的一些方式定義的類,得到BeanDefinition(Bean定義信息)
2.實(shí)例化Bean
通過BeanPostProcessor這個(gè)接口(增強(qiáng)器)可以對(duì)我們的BeanDefinition進(jìn)行一些修改,然后BeanFactory通過反射實(shí)例化Bean對(duì)象,但是此時(shí)的Bean對(duì)象還沒有進(jìn)行初始化,沒有填充屬性等操作。
3.初始化Bean
(1)自定義屬性賦值是用 set 方法賦值(populateBean())
(2)容器對(duì)象的屬性賦值是用實(shí)現(xiàn)Aware接口的方式來賦值(invokeAwareMethods()),如BeanNameAware
(3)調(diào)用BeanPostProcessor的前置處理方法
(4)調(diào)用init初始化方法:init-method
(5)調(diào)用BeanPostProcessor的后置處理方法(AOP在這里實(shí)現(xiàn))
(6)獲得一個(gè)完整的對(duì)象,并將對(duì)象放入map中(通過Context.getBean()可以獲取到Bean對(duì)象并使用)
4.銷毀Bean
Spring容器關(guān)閉時(shí)會(huì)調(diào)用DisposableBean的Destory()方法
如果你在這個(gè)Bean中配置了destory-method屬性,會(huì)自動(dòng)調(diào)用指定的銷毀方法
二、Bean的整體創(chuàng)建流程
- 1.利用該類的構(gòu)造方法來實(shí)例化得到一個(gè)對(duì)象(但是如果一個(gè)類中有多個(gè)構(gòu)造方法, Spring則會(huì)進(jìn)行選擇,這個(gè)叫做推斷構(gòu)造方法,下文在詳細(xì)介紹)
- 2.得到一個(gè)對(duì)象后,Spring會(huì)判斷該對(duì)象中是否存在被@Autowired注解了的屬 性,把這些屬性找出來并由Spring進(jìn)行賦值(依賴注入)
- 3.依賴注入后,Spring會(huì)判斷該對(duì)象是否實(shí)現(xiàn)了BeanNameAware接口、 BeanClassLoaderAware接口、BeanFactoryAware接口,如果實(shí)現(xiàn)了,就表示當(dāng)前 對(duì)象必須實(shí)現(xiàn)該接口中所定義的setBeanName()、setBeanClassLoader()、 setBeanFactory()方法,那Spring就會(huì)調(diào)用這些方法并傳入相應(yīng)的參數(shù)
- 4.Aware回調(diào)后,Spring會(huì)判斷該對(duì)象中是否存在某個(gè)方法被@PostConstruct注解 了,如果存在,Spring會(huì)調(diào)用當(dāng)前對(duì)象的此方法(初始化前),上面的代碼中初始化了一個(gè)adminUser的數(shù)據(jù)。
- 5.緊接著,Spring會(huì)判斷該對(duì)象是否實(shí)現(xiàn)了InitializingBean接口,如果實(shí)現(xiàn)了,就 表示當(dāng)前對(duì)象必須實(shí)現(xiàn)該接口中的afterPropertiesSet()方法,那Spring就會(huì)調(diào)用當(dāng)
前對(duì)象中的afterPropertiesSet()方法(初始化) - 6.最后,Spring會(huì)判斷當(dāng)前對(duì)象需不需要進(jìn)行AOP,如果不需要那么Bean就創(chuàng)建完 了,如果需要進(jìn)行AOP,則會(huì)進(jìn)行動(dòng)態(tài)代理并生成一個(gè)代理對(duì)象做為Bean(初始化 后)
關(guān)于第6步控制臺(tái)沒辦法打出日志,因?yàn)槌跏己笊婕暗絪pring的源碼操作,但是可以通過斷點(diǎn)看一下,提一句例子中UserService是被LogAspect切面切的。
這樣,一個(gè)Bean就創(chuàng)建完了,如果當(dāng)前Bean是單例Bean,那么會(huì)把該Bean對(duì)象存入一個(gè)Map<String, Object>,Map的key為beanName,value為Bean對(duì)象。這樣下次getBean時(shí)就可 以直接從Map中拿到對(duì)應(yīng)的Bean對(duì)象了。(實(shí)際上,在Spring源碼中,這個(gè)Map就 是單例池)
如果當(dāng)前Bean是原型Bean,那么后續(xù)沒有其他動(dòng)作,不會(huì)存入一個(gè)Map,下次 getBean時(shí)會(huì)再次執(zhí)行上述創(chuàng)建過程,得到一個(gè)新的Bean對(duì)象。
三、推斷構(gòu)造方法
至此,我們清楚了Bean的創(chuàng)建流程,那如果UserService中有多個(gè)構(gòu)造函數(shù)呢?第一步還能順利的創(chuàng)建一個(gè)普通對(duì)象嗎?這里面涉及到一個(gè)概念推斷構(gòu)造方法,就是spring會(huì)去推斷用哪個(gè)構(gòu)造方法來創(chuàng)建出普通對(duì)象。
總結(jié)下:
- 如果一個(gè)類只有一個(gè)構(gòu)造方法,那么沒得選擇,只能用這個(gè)構(gòu)造方法。但是有參的構(gòu)造方法,參數(shù)必須是spring的Bean這樣spring才能拿到進(jìn)行賦值。
- 如果一個(gè)類存在多個(gè)構(gòu)造方法,Spring不知道如何選擇,就會(huì)看是否有無參的構(gòu) 造方法,因?yàn)闊o參構(gòu)造方法本身表示了一種默認(rèn)的構(gòu)造方法。
- 如果都沒有構(gòu)造方法,就是用默認(rèn)的無參構(gòu)造方法來創(chuàng)建。
- 其實(shí)多個(gè)構(gòu)造函數(shù),也可以手動(dòng)指定告訴spring用哪個(gè)構(gòu)造函數(shù)來創(chuàng)建,那就是加了@Autowired注解
四、依賴注入流程
不管是屬性注入還是構(gòu)造方法注入,能提供的信息只有兩個(gè)一個(gè)是類型OrderService ,一個(gè)是名字orderService。那到底是根據(jù)類型注入的還是根據(jù)名字注入的呢?
假設(shè)根據(jù)名字注入的那剛好有一個(gè)其他類型的Bean名字也叫orderService那注入的時(shí)候豈不是會(huì)類型不匹配異常。比如說剛好有一個(gè)OrderBaseService類但是beanName也叫orderService,如果根據(jù)名字注入的話拿到的是OrderBaseService對(duì)象顯然類型不匹配。所以注入通常是先根據(jù)類型來查找的:
- 先根據(jù)入?yún)㈩愋驼?,如果只找到一個(gè)不用管name,那就直接用來作為入?yún)?/li>
- 如果根據(jù)類型找到多個(gè),則再根據(jù)入?yún)⒚謥泶_定唯一
- 最終如果沒有找到,則會(huì)報(bào)錯(cuò),無法創(chuàng)建當(dāng)前Bean對(duì)象
五、代理對(duì)象生成
代理對(duì)象通常是AOP的時(shí)候會(huì)生成代理對(duì)象還有一種就是開啟事務(wù)的時(shí)候也會(huì)生成代理對(duì)象。否則的話Bean都是直接根據(jù)構(gòu)造函數(shù)生成對(duì)象在進(jìn)行依賴注入和初始化等流程。
1.AOP代理對(duì)象生成
AOP就是進(jìn)行動(dòng)態(tài)代理,在創(chuàng)建一個(gè)Bean的過程中,Spring在最后一步會(huì)去判斷當(dāng)前正在 創(chuàng)建的這個(gè)Bean是不是需要進(jìn)行AOP,如果需要?jiǎng)t會(huì)進(jìn)行動(dòng)態(tài)代理。
如何判斷當(dāng)前Bean對(duì)象需不需要進(jìn)行AOP:
- 1.找出所有的切面Bean
- 2.遍歷切面中的每個(gè)方法,看是否寫了@Before、@After等注解
- 3.如果寫了,則判斷所對(duì)應(yīng)的Pointcut是否和當(dāng)前Bean對(duì)象的類是否匹配
- 4.如果匹配則表示當(dāng)前Bean對(duì)象有匹配的的Pointcut,表示需要進(jìn)行AOP
利用cglib進(jìn)行AOP的大致流程:
- 1.生成代理類UserServiceProxy,代理類繼承UserService
- 2.代理類中重寫了父類的方法,比如UserService中的test()方法
- 3.代理類中還會(huì)有一個(gè)target屬性,該屬性的值為被代理對(duì)象(也就是通過 UserService類推斷構(gòu)造方法實(shí)例化出來的對(duì)象,進(jìn)行了依賴注入、初始化等步驟的 對(duì)象)
- 4.代理類中的test()方法被執(zhí)行時(shí)的邏輯如下:
- a. 執(zhí)行切面邏輯(@Before)
- b. 調(diào)用target.test()
當(dāng)我們從Spring容器得到UserService的Bean對(duì)象時(shí),拿到的就是UserServiceProxy所生 成的對(duì)象,也就是代理對(duì)象。
UserService代理對(duì)象.test()—>執(zhí)行切面邏輯—>target.test(),注意target對(duì)象不是代理 對(duì)象,而是被代理對(duì)象。
2.事務(wù)代理對(duì)象生成
Spring事務(wù) 當(dāng)我們?cè)谀硞€(gè)方法上加了@Transactional注解后,就表示該方法在調(diào)用時(shí)會(huì)開啟Spring事 務(wù),而這個(gè)方法所在的類所對(duì)應(yīng)的Bean對(duì)象會(huì)是該類的代理對(duì)象。
Spring事務(wù)的代理對(duì)象執(zhí)行某個(gè)方法時(shí)的步驟:
- 1.判斷當(dāng)前執(zhí)行的方法是否存在@Transactional注解
- 2.如果存在,則利用事務(wù)管理器(TransactionMananger)新建一個(gè)數(shù)據(jù)庫(kù)連接,
- 3.修改數(shù)據(jù)庫(kù)連接的autocommit為false
- 4.執(zhí)行target.test(),執(zhí)行程序員所寫的業(yè)務(wù)邏輯代碼,也就是執(zhí)行sql
- 5.執(zhí)行完了之后如果沒有出現(xiàn)異常,則提交,否則回滾
注意:Spring事務(wù)是否會(huì)失效的判斷標(biāo)準(zhǔn):某個(gè)加了@Transactional注解的方法被調(diào)用時(shí),要判 斷到底是不是直接被代理對(duì)象調(diào)用的,如果是則事務(wù)會(huì)生效,如果不是則失效。
總結(jié)
Spring中Bean的創(chuàng)建過程其實(shí)就是從一個(gè)普通對(duì)象蛻變成Bean的一個(gè)過程,蛻變包括依賴注入,初始化等步驟。最后在看下這個(gè)類是否有被AOP或開啟事務(wù)有的話會(huì)額外生成代理對(duì)象作為Bean。文章來源:http://www.zghlxwxcb.cn/news/detail-455097.html
其他
參考:https://www.jianshu.com/p/57ed586e258c
https://www.csdn.net/tags/MtjaYgxsOTU3NTMtYmxvZwO0O0OO0O0O.html文章來源地址http://www.zghlxwxcb.cn/news/detail-455097.html
到了這里,關(guān)于Spring: Bean的創(chuàng)建原理解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!