关于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生成实例过程的调用栈:

总结

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

(0)

相关推荐

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

    前言 本文主要给大家介绍了关于Spring启动时Context加载的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 测试源码下载test-annotation.zip 有如下的代码 @Component public class HelloWorldService { @Value("${name:World}") private String name; public String getHelloMessage() { return "Hell

  • 详解springMVC容器加载源码分析

    springmvc是一个基于servlet容器的轻量灵活的mvc框架,在它整个请求过程中,为了能够灵活定制各种需求,所以提供了一系列的组件完成整个请求的映射,响应等等处理.这里我们来分析下springMVC的源码. 首先,spring提供了一个处理所有请求的servlet,这个servlet实现了servlet的接口,就是DispatcherServlet.把它配置在web.xml中,并且处理我们在整个mvc中需要处理的请求,一般如下配置: <servlet> <servlet-name

  • Spring Web项目spring配置文件随服务器启动时自动加载

    前言:其实配置文件不随服务器启动时加载也是可以的,但是这样操作的话,每次获取相应对象,就会去读取一次配置文件,从而降低程序的效率,而Spring中已经为我们提供了监听器,可监听服务器是否启动,然后在启动时,加载spring的配置文件,并且只加载一次,从而提高程序效率. 实现:其配置需要在web.xml中进行,具体实现如下: <!--配置监听器 --> <!--以便在服务器启动的时候,加载spring配置文件--> <listener> <listener-clas

  • 在CentOS启动时自动加载内核模块overlayfs操作

    在CentOS中自动加载内核模块,可以在/etc/sysconfig/modules/目录中增加一个脚本,在此脚本中加载所需的模块. 下面是我所用的一个名为overlayfs.modules的脚本,用来在我的CentOS 7.X中自动加载overlayfs模块: #! /bin/sh /sbin/modinfo -F filename overlayfs> /dev/null 2>&1 if [ $? -eq 0 ]; then /sbin/modprobe overlayfs fi

  • 详解SpringBoot启动代码和自动装配源码分析

    目录 一.SpringBoot启动代码主线分析 二.SpringBoot自动装配原理分析 1.自动装配的前置知识@Import 2.@SpringApplication注解分析 2.1@SpringBootConfiguration 2.2@EnableAutoConfiguration ​随着互联网的快速发展,各种组件层出不穷,需要框架集成的组件越来越多.每一种组件与Spring容器整合需要实现相关代码.SpringMVC框架配置由于太过于繁琐和依赖XML文件:为了方便快速集成第三方组件和减少

  • spring @Conditional的使用与扩展源码分析

    目录 @Conditional的使用 WindowsCondition LinuxCondition Conditional的扩展 ConditionalOnBean ConditionalOnProperty 源码分析 @Conditional的使用 @Conditional可以根据条件来判断是否注入某些Bean. package com.morris.spring.config; import com.morris.spring.condition.LinuxCondition; impor

  • Netty分布式Server启动流程服务端初始化源码分析

    目录 第一节:服务端初始化 group方法 初始化成员变量 初始化客户端Handler 第一节:服务端初始化 首先看下在我们用户代码中netty的使用最简单的一个demo: //创建boss和worker线程(1) EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); //创建ServerBootstrap(2) ServerBootst

  • Netty分布式server启动流程Nio创建源码分析

    目录 NioServerSocketChannel创建 继承关系 绑定端口 端口封装成socket地址对象 跟进initAndRegister()方法 创建channel 父类的构造方法 将jdk的channel设置为非阻塞模式 前文传送门 Netty分布式Server启动流程服务端初始化源码分析 NioServerSocketChannel创建 我们如果熟悉Nio, 则对channel的概念则不会陌生, channel在相当于一个通道, 用于数据的传输 Netty将jdk的channel进行了

  • lazy init控制加载在Spring中如何实现源码分析

    目录 一.lazy-init说明 二.lazy-init 属性被设置的地方 三.lazy-init发挥作用的地方 四.问答 一.lazy-init说明 ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化(也就是依赖注入). 提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean. 通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小

  • spring boot启动加载数据原理分析

    实际应用中,我们会有在项目服务启动的时候就去加载一些数据或做一些事情这样的需求. 为了解决这样的问题,spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRunner 来实现. 创建实现接口 CommandLineRunner 的类,通过@Component注解,就可以实现启动时加载数据项.使用@Order 注解来定义执行顺序. IndexStartupRunner.Java类: import org.springframework.boot.CommandLine

随机推荐