之前写过的很多spring文章,都是基于应用方面的,这次的话,就带大家来一次对spring的源码追踪,看一看spring到底是怎么进行的初始化,如何创建的bean,相信很多刚刚接触spring的朋友,或者没什么时间的朋友都很想知道spring到底是如何工作的。
首先,按照博主一贯的作风,当然是使用最新的spring版本,这次就使用spring4.2.5...其次,也是为了方便,采用spring-boot-1.3.3进行追踪,和spring 4.2.5是相同的。
不用担心框架不同,大家如果是使用的xml方式进行配置的话,可以去你的ContextListener里面进行追踪,spring-boot只是对 spring所有框架进行了一个集成,如果实在进行不了前面几个步骤的话,可以从文章第6步的AbstractApplicationContext开始看起, 这里就是spring最最重要的部分。
1、默认的spring启动器,DemoApplication:
该方法是spring-boot的启动器,我们进入。
2、进入了SpringApplication.java:
这里创建了一个SpringApplication,执行run方法,返回的是一个ConfigurableApplicationContext,这只是一个接口而已,根据名称来看,称作可配置的应用程序上下文。
3、我们不看new SpringApplication(Sources)过程了,有兴趣可以自己研究一下,里面主要是判断了当前的运行环境是否为web,当然,博主这次的环境是web,然后看run:
try语句块内的内容最为重要,因为创建了我们的context对象,此时需要进入的方法为
context = createAndRefreshContext(listeners, applicationArguments)
4、 接着往下看,看到context = createApplicationContext这行,进入,因为我们刚刚在创建SpringApplication时并没有给 this.applicationContextClass赋值,所以此时this.applicationContextClass = null,那么便会创建指定的两个applicationContext中的一个,返回一个刚刚创建的context,这个context便是我们的基 础,因为门现在为web环境,所以创建的context为 AnnotationConfigEmbeddedWebApplicationContext。
5、第4步创建了一个context,需要指出的是,context里面默认带有一个beanFactory,而这个beanFactory的类型为DefaultListableBeanFactory。
然后继续看我们的createAndRefreshContext方法,忽略别的代码,最重要的地方为refresh(context):
6、进入refresh(context),不管你进入那个实现类,最终进入的都是AbstractApplicationContext.java:
该方法中,我们这次需要注意的地方有两个:
1、invokeBeanFactoryPostProcessors(beanFactory);
2、finishBeanFactoryInitialization(beanFactory);
两处传入的beanFactory为上面的context中的DefaultListableBeanFactory。
7、进入invokeBeanFactoryPostProcessors(beanFactory):
然后找到第98行的invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry),该方法看名字就是注册bean,进入。
8、 该方法内部有一个for循环,进入内部方法 postProcessor.postProcesBeanDefinitionRegistry(registry),此时传入的registry就是我们context中的beanfactory,因为其实现了BeanDefinitionRegistry接口。而此时的postProcessor实现类为ConfigurationClassPostProcessor.java。
9、进入之后直接看最后面的一个方法,名称为processConfigBeanDefinitions(registry),翻译过来就是配置beanDefinitions的流程。
10、在processConfigBeanDefinitions(registry)里,314行创建了一个parser解析器,用来解析bean。并在第321行进行了调用,那么我们进入parse方法。
11、进入parse方法之后,会发现内层还有parse方法,不要紧,继续进入内层的parse,然后会发现它们均调用了processConfigurationClass(ConfigurationClass configClass)方法:
12、 在processConfigurationClass(ConfigurationClass configClass)方法内,找到do循环,然后进入doProcessConfigurationClass方法,此时,便会出现许多我们常用的注 解了,spring会找到这些注解,并对它们进行解析。例如第268行的componentScanParser.parse方法,在这里会扫描我们的注 解类,并将带有@bean注解的类进行registry。
13、进入 componentScanParser.parse,直接进入结尾的scannner.doScan,然后便会扫描basepackages,并将扫描 到的bean生成一个一个BeanDefinitionHolder,BeanDefinitionHolder中包含有我们bean的一些相关信息、以 及spring赋予其的额外信息,例如别名:
14、 虽然已经创建了BeanDefinitionHolder,但并没有添加到我们的beanFactory中,所以需要执行263行的 registerBeanDefinition(definitionHolder, this.registry),进入后继续跳转:
然后看registry.registerBeanDefinition方法,因为我们的beanFactory为DefaultListableBeanFactory,所以进入对应的实现类。
15、在进入的registry.registerBeanDefinition方法中,关键点在851行或871行:
this.beanDefinitionMap.put(beanName, beanDefinition);
这个方法将扫描到的bean存放到了一个beanName为key、beanDefinition为value的map中,以便执行DI(dependency inject)。
16、现在我们回到第6步的第二条分支,此处是非懒加载的bean初始化位置,注意,我们之前只是对bean的信息进行了获取,然后创建的对象为BeanDefinition,却不是bean的实例,而现在则是创建bean的实例。
进入方法后找到829行的getBean(weaverAwareName):
17、getBean => getBeanFactory.getBean => doGetBean,然后找到306行的createBean,这里不讲语法,不要奇怪为什么这个createBean不能进入实现代码。
18、这之后的代码都比较容易追踪,直接给一条调用链:
doCreateBean(482) => createBeanInstance(510) => autowireConstructor(1034,1046) => autowireConstructor(1143) => instantiate(267) => instantiateClass(122) => newInstance(147)
括号内的数字代表行号,方便大家进行追踪,最后看到是反射newInstance取得的对象实例:
平时总说spring反射获取bean,其实也就是听别人这么说而已,还是自己见到才踏实,万一别人问你是不是通过Class.forName获取的呢?
19、属性注入,位于第18条的doCreateBean方法内,找到第543行,populateBean便译为填充Bean,进入后便能看到和我们平时代码对应的条件了,例如byType注入、byName注入:
这里还没有进行依赖注入,仅仅是准备一些必要的信息,找到1214行的ibp.postProcessPropertyValues方法
相关推荐
Spring Bean 加载过程是 Spring 框架中最核心的部分之一,涉及到 ApplicationContext 的初始化、Bean 的加载和注册等过程。在 Spring Boot 应用程序中,SpringApplication 负责加载和管理 Bean。 SpringApplication...
在本篇文章中,我们将深入探讨Spring源码中关于Bean初始化的过程,特别是`finishBeanFactoryInitialization()`方法和`preInstantiateSingletons()`方法。 首先,`finishBeanFactoryInitialization(Confi...
本篇文章主要分析了Spring如何通过`ClassPathXmlApplicationContext`来启动和初始化Bean的过程。 首先,`ClassPathXmlApplicationContext`是Spring的一种ApplicationContext实现,用于从类路径下的XML配置文件加载...
### Spring的IoC容器初始化源码解析 #### 一、Spring框架的核心——IoC容器 Spring框架是一个开源的轻量级Java开发框架,其核心功能是IoC(Inversion of Control,控制反转)容器和AOP(Aspect Oriented ...
在bean初始化时,`BeanFactory`会根据`BeanDefinition`中的依赖关系,自动将其他bean注入到当前bean的属性中。这种过程称为属性设置,可以通过setter方法、构造函数或者字段注入实现。源码中的`...
Spring源码深度解析第二版 Spring是一款广泛应用于Java企业级应用程序的开源框架,旨在简化Java应用程序的开发和部署。Spring框架的核心主要包括了IoC容器、AOP、MVC框架等模块。 第1章 Spring整体架构和环境搭建 ...
但是,这并不总是可靠的,因为Spring通常会延迟初始化Bean,除非显式要求或存在依赖关系。 2. **依赖注入**:Spring容器会根据Bean之间的依赖关系来决定实例化顺序。如果一个Bean依赖于另一个Bean,那么被依赖的...
7. **Bean的生命周期**:从bean的实例化、属性注入、初始化方法调用到销毁,Spring管理着bean的整个生命周期。`InitializingBean`和`DisposableBean`接口,以及`@PostConstruct`和`@PreDestroy`注解,是用来控制生命...
最后,深入理解Spring源码不仅可以帮助你解决实际开发中的问题,还能让你更好地掌握Java企业级应用的开发技巧,为你的职业生涯增色添彩。因此,花时间研究这个源码jar包是非常值得的投资。祝你在学习Spring的道路...
本文将深入探讨如何在Spring容器初始化Bean和销毁Bean前后执行自定义的操作,以便于进行日志记录、资源清理等任务。 首先,我们需要了解Spring中Bean的生命周期。Bean的生命周期大致分为以下阶段: 1. 实例化:...
7. **Bean生命周期源码解析**:"05-Spring之Bean生命周期源码解析下-周瑜"将详细阐述Bean从创建到销毁的整个过程,包括初始化、后置处理、正常运行和销毁等阶段,使我们能更好地控制和管理Bean的状态。 8. **模拟...
属性值可以用于初始化Bean的成员变量,或者作为构造函数参数。 Spring源码手写篇旨在帮助开发者理解Spring内部的工作原理,通过模仿Spring的核心功能,如Bean工厂和Bean定义,我们可以更好地掌握Spring框架的精髓。...
在解析BeanDefinition时,Spring会根据属性值和构造参数解析依赖,并在实例化Bean后进行注入。 5. **Bean的生命周期管理** Spring提供了对Bean生命周期的完整控制,包括初始化、正常运行以及销毁阶段。Bean可以...
这个问题可能是由多种原因引起的,涉及到Spring的初始化过程和容器的行为。以下是对该问题的详细分析: 首先,我们需要理解Spring Bean的生命周期。在Spring容器初始化时,它会根据配置加载Bean的定义,并根据需要...
Spring框架是Java开发中最常用的轻量级开源框架之一,它...以上是对Spring框架的一些核心概念和关键点的介绍,深入研究Spring源码可以帮助我们更好地理解其实现细节,提高开发效率,并为定制化开发和性能优化提供基础。
容器负责初始化、配置、装配以及管理Bean。Bean的定义通常包含在XML、Java注解或Java配置类中。 4. **面向切面编程(Aspect-Oriented Programming, AOP)**:AOP允许开发者定义“切面”,即关注点的模块化,如日志...
在深入Spring源码的学习过程中,我们主要关注BeanDefinition的装载过程。BeanDefinition是Spring框架的核心概念,它包含了关于Bean的所有元数据,如类名、属性、依赖关系等。在Spring初始化时,会读取XML配置文件,...
在Spring框架中,Bean生命周期是核心概念之一,它涉及到Bean的创建、初始化、使用和销毁等阶段。了解和掌握Bean生命周期对于开发高质量的Spring应用至关重要。以下是对Spring Bean生命周期的详细解析。 首先,Bean...
文档可能将深入探讨Spring IoC容器初始化、Bean生命周期管理、依赖注入等关键概念,并以2021年的开源版本为背景进行分析。 从提供的部分文档内容来看,我们可以提炼出以下几个知识点: 1. **BeanFactory与...