您好,登錄后才能下訂單哦!
今天小編給大家分享一下spring初始化源碼之關(guān)鍵類和擴(kuò)展接口怎么應(yīng)用的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
該類核心功能:
1、提供注冊(cè)、獲取等等與BeanDefinition對(duì)象操作相關(guān)的方法,BeanDefinition緩存在DefaultListableBeanFactory的beanDefinitionMap變量(ConcurrentHashMap類型)
2、提供創(chuàng)建、注冊(cè)、獲取、單例等等跟bean對(duì)象操作相關(guān)的方法供ApplicationContext使用,bean對(duì)象緩存在DefaultSingletonBeanRegistry的singletonObjects 變量(ConcurrentHashMap類型)
類關(guān)系圖如下:
從類圖中看到DefaultListableBeanFactory實(shí)現(xiàn)了很多接口,spring 根據(jù)該類的功能定義了不同層次的接口。接口核心功能主要分兩類:1、AliasRegistry、BeanDefinitionRegistry接口主要提供BeanDefinition和alias注冊(cè)、獲取的方法,2、左半部分*BeanFactory相關(guān)接口、SingletonBeanRegistry接口提供對(duì)象的創(chuàng)建、緩存和獲取等方法
該類負(fù)責(zé)分析xml中bean的定義,并解析成BeanDefinition對(duì)象,然后調(diào)用DefaultListableBeanFactory的注冊(cè)方法緩存到DefaultListableBeanFactory中
先上類關(guān)系圖:
這個(gè)就是spring上下文,是spring啟動(dòng)的入口類,從父類AbstractApplicationContext的refresh()方法中可以看出該類的主要功能:設(shè)置springContext.xml路徑、創(chuàng)建DefaultListableBeanFactory、提供對(duì)象創(chuàng)建過程中的各種擴(kuò)展點(diǎn)、事件的注冊(cè)和分發(fā)等等。
1、BeanNameAware:void setBeanName(String name);
該bean獲取自己在DefaultListableBeanFactory中的id或name ,在spring框架里用的多,我們一般很少用到。
2、BeanFactoryAware:void setBeanFactory(BeanFactory beanFactory)
獲取創(chuàng)建該bean的DefaultListableBeanFactory對(duì)象,可以從該對(duì)象中回去bean對(duì)象,不過絕大多數(shù)時(shí)候我們是從ApplicationContext中來獲取。
3、ApplicationContextAware:void setApplicationContext(ApplicationContext applicationContext)
獲取該bean所屬的applicationContext,從而可以獲取到該上下文的bean對(duì)象。自己寫一個(gè)工具類實(shí)現(xiàn)該接口然后在配置文件中配置或加上@Component注解,通過這個(gè)工具類就很方便的在應(yīng)用中動(dòng)態(tài)獲取bean對(duì)象,這種工具類在很多老的項(xiàng)目中幾乎是一個(gè)標(biāo)配。
4、InitializingBean:void afterPropertiesSet()
spring提供兩中方式來對(duì)bean初始化后的擴(kuò)展,一種是實(shí)現(xiàn)InitializingBean接口,一種是使用通過init-method方法指定,spring初始化bean時(shí)在執(zhí)行InitializingBean接口的afterPropertiesSet方法后就緊接著執(zhí)行init-method指定的方法。使用init-method不會(huì)對(duì)spring產(chǎn)生依賴因此使用頻率較高,但由于這種方式使用反射方式來調(diào)用所以性能上低于直接調(diào)用 InitializingBean接口的afterPropertiesSet方法,后面會(huì)有相應(yīng)的代碼分析。
5、指定init-method
用的較多,可以理解為spring在bean對(duì)象初始化完后會(huì)通過反射的方式來執(zhí)行該bean中init-method指定的方法。通過在xml文件中的bean標(biāo)簽配置init-method或在該bean的方法上使用@PostConstruct注解達(dá)到效果。
6、BeanFactoryPostProcessor:void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
從后面的代碼分析中我們發(fā)現(xiàn),實(shí)現(xiàn)BeanFactoryPostProcessor接口的bean的創(chuàng)建及接口方法的調(diào)用時(shí)間早于普通bean的創(chuàng)建。實(shí)現(xiàn)該接口可以拿到beanFactory對(duì)象,然后就看可以在普通bean對(duì)象創(chuàng)建之前進(jìn)行干預(yù)調(diào)整,PropertyPlaceholderConfigurer類大家應(yīng)該比較熟悉,該類實(shí)現(xiàn)BeanFactoryPostProcessor接口,在postProcessBeanFactory方法中將beanDefinitionMap中所有的BeanDefinition中的含有占位符的值修改為指定屬性文件中的值,這樣在創(chuàng)建對(duì)象的時(shí)候就能獲取到真實(shí)值。
7、BeanPostProcessor:Object postProcessBeforeInitialization(Object bean, String beanName);
BeanPostProcessor:Object postProcessAfterInitialization(Object bean, String beanName);
該接口需要注意與BeanFactoryPostProcessor接口的區(qū)別:
BeanFactoryPostProcessor接口:A實(shí)現(xiàn)了該接口,spring啟動(dòng)的時(shí)候,在所有普通bean對(duì)象創(chuàng)建之前會(huì)先創(chuàng)建A對(duì)象并調(diào)用其postProcessBeanFactory方法,方法參數(shù)為beanFactory。
BeanPostProcessor接口:A實(shí)現(xiàn)了該接口,spring在創(chuàng)建普通的bean 對(duì)象B時(shí),在B對(duì)象初始化之前將B對(duì)象的實(shí)例和beanname作為入?yún)⒄{(diào)用A的前置方法postProcessBeforeInitialization,在B對(duì)象初始化之后將B對(duì)象的實(shí)例和beanname作為入?yún)⒄{(diào)用A的后置方法postProcessAfterInitialization。由此也可知實(shí)現(xiàn)該接口bean的創(chuàng)建時(shí)間早于普通bean的創(chuàng)建。
通過實(shí)現(xiàn)該接口也可以完成對(duì)bean對(duì)象的調(diào)整,但與BeanFactoryPostProcessor還是有本質(zhì)的區(qū)別,實(shí)現(xiàn)BeanFactoryPostProcessor可以理解為對(duì)創(chuàng)建的模板的調(diào)整,是對(duì)BeanDefinition對(duì)象的調(diào)整,而BeanPostProcessor則是在對(duì)象過程中做的臨時(shí)的調(diào)整,是對(duì)創(chuàng)建好的bean對(duì)象的調(diào)整
使用BeanPostProcessor需要注意:
①、前置、后置方法需要將修改后的bean對(duì)象返回這樣getbean時(shí)才能獲取到正確的bean對(duì)象
②、針對(duì)layz的bean對(duì)象創(chuàng)建則不會(huì)回調(diào)該接口的方法
8、ApplicationListener:void onApplicationEvent(E event)
spring上下文啟動(dòng)完成后回調(diào)該接口,比較常用。
1、HelloWorldService bean對(duì)象
public class HelloWorldService implements BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor, BeanPostProcessor,InitializingBean , ApplicationListener<ContextRefreshedEvent>,ApplicationContextAware { private String name; private AtomicInteger count = new AtomicInteger(1); private String getSeq(){ return count.getAndIncrement()+"->"; } public HelloWorldService(){ System.err.println(getSeq()+"HelloWorldService constructor"); } public void initMethod(){ System.err.println(getSeq()+"init method"); } public void sayHello(){ System.err.println(getSeq()+name+"say:hello,world"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setBeanName(String name) { System.err.println(getSeq()+"BeanNameAware.setBeanName:"+name); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.err.println(getSeq()+"BeanFactoryAware.setBeanFactory:"+beanFactory); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.err.println(getSeq()+"ApplicationContextAware.setApplicationContext:->"+applicationContext); } public void afterPropertiesSet() { System.err.println(getSeq()+"InitializingBean.afterPropertiesSet"); } public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("peopleService"); beanDefinition.getPropertyValues(); MutablePropertyValues m = beanDefinition.getPropertyValues(); m.addPropertyValue("content", "i am ok"); System.err.println(getSeq()+"BeanFactoryPostProcessor.postProcessBeanFactory 將peopleService的content屬性修改為i am ok"); } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.err.println(getSeq()+"BeanPostProcessor.postProcessBeforeInitialization->"+beanName); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.err.println(getSeq()+"BeanPostProcessor.postProcessAfterInitialization->"+beanName); return bean; } public void onApplicationEvent(ContextRefreshedEvent event) { System.err.println(getSeq()+"ApplicationListener.onApplicationEvent: Refreshed->"+event.getApplicationContext()); } }
2 、非lazy的普通bean對(duì)象,PeopleService
public class PeopleService{ private String content=""; public PeopleService(){ System.err.println("PeopleService constructor"); } public void say(){ System.err.println("PeopleService say:["+content+"]"); } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
3、啟動(dòng)類
public class AppMain { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); System.err.println("==============================================="); HelloWorldService helloWorldService = applicationContext.getBean("helloWorldService",HelloWorldService.class); helloWorldService.sayHello(); PeopleService peopleService = applicationContext.getBean("peopleService",PeopleService.class); peopleService.say(); } }
代碼執(zhí)行結(jié)果:
從輸入結(jié)果中我們得到以下信息:
1、HelloWorldService 實(shí)現(xiàn) BeanFactoryPostProcessor接口所以創(chuàng)建時(shí)間早于普通非lazy的bean對(duì)象PeopleService
2、1-7為HelloWorldService 創(chuàng)建過程輸出的日志,可以看到各擴(kuò)展接口的執(zhí)行順序
3、第7步之后開始創(chuàng)建PeopleService對(duì)象,創(chuàng)建過程中回調(diào)用HelloWorldService(實(shí)現(xiàn)了BeanPostProcessor接口) 的前置和后置方法
4、spring上下文啟動(dòng)完成后發(fā)布ContextRefreshedEvent事件,輸出第10步日志
以上就是“spring初始化源碼之關(guān)鍵類和擴(kuò)展接口怎么應(yīng)用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(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)容。