关于Spring启动时Context加载源码分析

 更新时间:2018年01月15日 11:22:02   作者:Nix.Huang  
这篇文章通过源码分析主要给大家介绍了关于Spring启动时Context加载的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

前言

本文主要给大家介绍了关于Spring启动时Context加载的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

测试源码下载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方法简单的返回name的值, BootStrap.main方法中使用AnnotationConfigApplicationContext 构造一个上下文对象, 为了演示的方便, 显示的声明了DefaultListableBeanFactory和InstantiationStrategy实例。通过applicationContext.getBean()获取bean的引用,并调用 service.getHelloMessage() 方法。

上下文的加载主要发生在applicationContext.register方法和applicationContext.refresh方法中,
applicationContext.register方法的作用是为参数(使用@Configuration注解的class)生成BeanDefinition 对象并调用DefaultListableBeanFactory.registerBeanDefinition将BeanDefinition注册到DefaultListableBeanFactory中。

applicationContext.refresh()的功能要更多,主要功能一的是调用PostProcessor为@Configuration类中的@Bean标注的方法生成对应的BeanDefinition对象,并注册到DefaultListableBeanFactory中,功能二是遍历DefaultListableBeanFactory中BeanDefinition, 产生真正的对象。

为@Configuration类中@Bean标注的方法生成BeanDefinition对象详细过程如下

步骤1、找到合适的BeanDefinitionRegistryPostProcessor处理器

org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() {
 ...
 //获取适用的BeanDefinitionRegistryPostProcessor bean名称
 String[] postProcessorNames =
  beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
 ...
 //根据beanName获取PostProcessor, 处理@Configuration标注类的beanName为
 //org.springframework.context.annotation.internalConfigurationAnnotationProcessor 
 //实现为org.springframework.context.annotation.ConfigurationClassPostProcessor
 ConfigurationClassPostProcessor postProcessor =beanFactory.getBean(postProcessorNames[0], BeanDefinitionRegistryPostProcessor.class)
}

步骤2、为@Configuration产生ConfigurationClass对象

//使用ConfigurationClassParser解析@Configuration标注的类,

//每一个@Configuration标注的类产生一个ConfigurationClass对象,

//ConfigurationClass.getBeanMethods()能获得该类中所有使用@Bean标注的方法,

//@Bean标注的方法使用BeanMethod对象表示

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标注的方法产生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的实例
 this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

此过程的调用栈:

根据BeanDefinition生成实例过程的调用栈:

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • Java中的StringTokenizer实现字符串切割详解

    Java中的StringTokenizer实现字符串切割详解

    这篇文章主要介绍了Java中的StringTokenizer实现字符串切割详解,java.util工具包提供了字符串切割的工具类StringTokenizer,Spring等常见框架的字符串工具类(如Spring的StringUtils),需要的朋友可以参考下
    2024-01-01
  • Spring Cloud gateway 网关如何拦截Post请求日志

    Spring Cloud gateway 网关如何拦截Post请求日志

    这篇文章主要介绍了Spring Cloud gateway 网关如何拦截Post请求日志的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Java中SSM+Shiro系统登录验证码的实现方法

    Java中SSM+Shiro系统登录验证码的实现方法

    这篇文章主要介绍了 SSM+Shiro系统登录验证码的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02
  • SpringBoot注解@Import原理之关于ConfigurationClassPostProcessor源码解析

    SpringBoot注解@Import原理之关于ConfigurationClassPostProcessor源码解析

    这篇文章主要介绍了SpringBoot注解@Import原理之关于ConfigurationClassPostProcessor源码解析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Java代码为例讲解堆的性质和基本操作以及排序方法

    Java代码为例讲解堆的性质和基本操作以及排序方法

    堆数据结构可以看作一颗完全二叉树,因而又被成为二叉堆,这里我们以Java代码为例讲解堆的性质和基本操作以及排序方法,需要的朋友可以参考下
    2016-06-06
  • springboot redis分布式锁代码实例

    springboot redis分布式锁代码实例

    这篇文章主要介绍了springboot redis分布式锁代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • spring 定时任务@Scheduled详解

    spring 定时任务@Scheduled详解

    这篇文章主要介绍了spring 定时任务@Scheduled的相关资料,文中通过示例代码介绍的很详细,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面来一起看看吧。
    2017-01-01
  • 将java程序打成jar包在cmd命令行下执行的方法

    将java程序打成jar包在cmd命令行下执行的方法

    这篇文章主要给大家介绍了关于将java程序打成jar包在cmd命令行下执行的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • Java中锁的分类与使用方法

    Java中锁的分类与使用方法

    这篇文章主要给大家介绍了关于Java中锁分类与使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 详解Java多线程编程中CountDownLatch阻塞线程的方法

    详解Java多线程编程中CountDownLatch阻塞线程的方法

    在Java中和ReadWriteLock.ReadLock一样,CountDownLatch的本质也是一个"共享锁",这里我们就来详解Java多线程编程中CountDownLatch阻塞线程的方法:
    2016-07-07

最新评论