前言
本文主要給大家介紹了關(guān)于Spring啟動時Context加載的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細的介紹吧。
測試源碼下載test-annotation.zip
有如下的代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
@Component public class HelloWorldService { @Value ( "${name:World}" ) private String name; public String getHelloMessage() { return "Hello " + this .name; } } @Configuration public class BootStrap { @Bean public static HelloWorldService helloService() { return new HelloWorldService(); } public static void main(String[] args) { InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy(); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.setInstantiationStrategy(instantiationStrategy); AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(beanFactory); applicationContext.register(BootStrap. class ); applicationContext.refresh(); HelloWorldService service = applicationContext.getBean(HelloWorldService. class ); System.out.println(service.getHelloMessage()); applicationContext.close(); } } |
HelloWorldService.getHelloMessage
方法簡單的返回name的值, BootStrap.main
方法中使用AnnotationConfigApplicationContext 構(gòu)造一個上下文對象, 為了演示的方便, 顯示的聲明了DefaultListableBeanFactory和InstantiationStrategy實例。通過applicationContext.getBean()獲取bean的引用,并調(diào)用 service.getHelloMessage()
方法。
上下文的加載主要發(fā)生在applicationContext.register
方法和applicationContext.refresh
方法中,
applicationContext.register方法的作用是為參數(shù)(使用@Configuration注解的class)生成BeanDefinition 對象并調(diào)用DefaultListableBeanFactory.registerBeanDefinition
將BeanDefinition注冊到DefaultListableBeanFactory中。
applicationContext.refresh()
的功能要更多,主要功能一的是調(diào)用PostProcessor為@Configuration類中的@Bean標注的方法生成對應(yīng)的BeanDefinition對象,并注冊到DefaultListableBeanFactory中,功能二是遍歷DefaultListableBeanFactory中BeanDefinition, 產(chǎn)生真正的對象。
為@Configuration類中@Bean標注的方法生成BeanDefinition對象詳細過程如下
步驟1、找到合適的BeanDefinitionRegistryPostProcessor處理器
1
2
3
4
5
6
7
8
9
10
11
|
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() { ... //獲取適用的BeanDefinitionRegistryPostProcessor bean名稱 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor. class , true , false ); ... //根據(jù)beanName獲取PostProcessor, 處理@Configuration標注類的beanName為 //org.springframework.context.annotation.internalConfigurationAnnotationProcessor //實現(xiàn)為org.springframework.context.annotation.ConfigurationClassPostProcessor ConfigurationClassPostProcessor postProcessor =beanFactory.getBean(postProcessorNames[ 0 ], BeanDefinitionRegistryPostProcessor. class ) } |
步驟2、為@Configuration產(chǎn)生ConfigurationClass對象
//使用ConfigurationClassParser解析@Configuration標注的類,
//每一個@Configuration標注的類產(chǎn)生一個ConfigurationClass對象,
//ConfigurationClass.getBeanMethods()
能獲得該類中所有使用@Bean標注的方法,
//@Bean標注的方法使用BeanMethod對象表示
1
2
3
4
5
6
7
8
|
org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(BeanDefinitionRegistry registry) { ConfigurationClassParser parser = new ConfigurationClassParser( this .metadataReaderFactory, this .problemReporter, this .environment, this .resourceLoader, this .componentScanBeanNameGenerator, registry); parser.parse(configCandidates); parser.validate(); this .reader.loadBeanDefinitions(parser.getConfigurationClasses()); } |
步驟3、@Bean標注的方法產(chǎn)生BeanDefinition并注入到DefaultListableBeanFactory中
1
2
3
4
5
6
7
|
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass); beanDef.setBeanClassName(configClass.getMetadata().getClassName()); beanDef.setFactoryMethodName(metadata.getMethodName()); //registry 是DefaultListableBeanFactory的實例 this .registry.registerBeanDefinition(beanName, beanDefToRegister); } |
此過程的調(diào)用棧:
根據(jù)BeanDefinition生成實例過程的調(diào)用棧:
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:http://www.javacoder.cn/?p=1174