關(guān)于Spring啟動(dòng)時(shí)Context加載源碼分析
前言
本文主要給大家介紹了關(guān)于Spring啟動(dòng)時(shí)Context加載的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。
測(cè)試源碼下載test-annotation.zip
有如下的代碼
@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方法簡(jiǎn)單的返回name的值, BootStrap.main方法中使用AnnotationConfigApplicationContext 構(gòu)造一個(gè)上下文對(duì)象, 為了演示的方便, 顯示的聲明了DefaultListableBeanFactory和InstantiationStrategy實(shí)例。通過(guò)applicationContext.getBean()獲取bean的引用,并調(diào)用 service.getHelloMessage() 方法。
上下文的加載主要發(fā)生在applicationContext.register方法和applicationContext.refresh方法中,
applicationContext.register方法的作用是為參數(shù)(使用@Configuration注解的class)生成BeanDefinition 對(duì)象并調(diào)用DefaultListableBeanFactory.registerBeanDefinition將BeanDefinition注冊(cè)到DefaultListableBeanFactory中。
applicationContext.refresh()的功能要更多,主要功能一的是調(diào)用PostProcessor為@Configuration類(lèi)中的@Bean標(biāo)注的方法生成對(duì)應(yīng)的BeanDefinition對(duì)象,并注冊(cè)到DefaultListableBeanFactory中,功能二是遍歷DefaultListableBeanFactory中BeanDefinition, 產(chǎn)生真正的對(duì)象。
為@Configuration類(lèi)中@Bean標(biāo)注的方法生成BeanDefinition對(duì)象詳細(xì)過(guò)程如下
步驟1、找到合適的BeanDefinitionRegistryPostProcessor處理器
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() {
...
//獲取適用的BeanDefinitionRegistryPostProcessor bean名稱(chēng)
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
...
//根據(jù)beanName獲取PostProcessor, 處理@Configuration標(biāo)注類(lèi)的beanName為
//org.springframework.context.annotation.internalConfigurationAnnotationProcessor
//實(shí)現(xiàn)為org.springframework.context.annotation.ConfigurationClassPostProcessor
ConfigurationClassPostProcessor postProcessor =beanFactory.getBean(postProcessorNames[0], BeanDefinitionRegistryPostProcessor.class)
}
步驟2、為@Configuration產(chǎn)生ConfigurationClass對(duì)象
//使用ConfigurationClassParser解析@Configuration標(biāo)注的類(lèi),
//每一個(gè)@Configuration標(biāo)注的類(lèi)產(chǎn)生一個(gè)ConfigurationClass對(duì)象,
//ConfigurationClass.getBeanMethods()能獲得該類(lèi)中所有使用@Bean標(biāo)注的方法,
//@Bean標(biāo)注的方法使用BeanMethod對(duì)象表示
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標(biāo)注的方法產(chǎn)生BeanDefinition并注入到DefaultListableBeanFactory中
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(metadata.getMethodName());
//registry 是DefaultListableBeanFactory的實(shí)例
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
此過(guò)程的調(diào)用棧:

根據(jù)BeanDefinition生成實(shí)例過(guò)程的調(diào)用棧:

總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
SpringBoot分布式文件存儲(chǔ)數(shù)據(jù)庫(kù)mongod
MongoDB是一個(gè)基于分布式文件存儲(chǔ)的NoSQL數(shù)據(jù)庫(kù),由C++語(yǔ)言編寫(xiě),旨在為Web應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。MongoDB是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫(kù)中功能最豐富最像關(guān)系數(shù)據(jù)庫(kù)的2023-02-02
詳解如何將已有項(xiàng)目改造為Spring Boot項(xiàng)目
本篇文章主要介紹了如何將已有項(xiàng)目改造為Spring Boot項(xiàng)目,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
springboot日志文件名稱(chēng)叫l(wèi)ogback-spring.xml的原因解析
這篇文章主要介紹了springboot日志文件名稱(chēng)為什么叫l(wèi)ogback-spring.xml,本文給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
Java實(shí)體類(lèi)實(shí)現(xiàn)鏈?zhǔn)讲僮鲗?shí)例解析
這篇文章主要介紹了Java實(shí)體類(lèi)實(shí)現(xiàn)鏈?zhǔn)讲僮鲗?shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12

