Spring5源码 - 01 BeanDefination源码分析

简介: Spring5源码 - 01 BeanDefination源码分析

20200914143739548.png

引入

Spring 是如何生成一个Bean的?

我们先看个例子


2020091108493851.png


我们有个Configuration类AppConfig ,通过ComponentScan定义了扫描com.artisan目录下所有表了标注了注解的Bean

package com.artisan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.artisan")
public class AppConfig {
}

同时com.artisan目录下还有A.class 和 B.class , 其中B类上标注了@Component注解,A上仅仅一个普通的Java类

package com.artisan.test;
import org.springframework.stereotype.Component;
@Component
public class B { 
}
package com.artisan.test;
public class A {
}

我们启动下Spring容器,然后尝试去重bean容器中获取A和B的单例对象,看看会发生什么?

package com.artisan.test;
import com.artisan.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BeanLoadTest {
  public static void main(String[] args) {
    // spring容器
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    System.out.println(ac.getBean(B.class));
    System.out.println(ac.getBean(A.class));
  }
}


结果显而易见, 被标注了@Component注解的B类,成功的从bean容器中获取到了,而A类是无法从bean容器中获取到的 ( No qualifying bean of type ‘com.artisan.test.A’ available)。

com.artisan.test.B@28864e92
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.artisan.test.A' available
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
  at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1177)
  at com.artisan.test.BeanLoadTest.main(BeanLoadTest.java:12)


这是为什么呢?Spring的源码是如何实现的呢? 接下来的文章,我们逐层揭开Sping Bean的神秘面纱 …


Bean实例化的原理


我们知道普通的Java类的实例化的过程,被JVM编译成字节码文件以后,通过new 关键字实例化。


Spring bean的实例化区别于普通Java类的实例化过程,是一个相对复杂的过程。


原理如下


1. 扫描到可以受到Spring管理的Bean,将其转化成BeanDefinition


2. BeanDefinition是个接口,其中有很多属性可以设置,比如 scope 、lazyInit、dependson 、autoType 、关联的是哪个类setBeanClass 等等


3. 将BeanDefinition放入到一个Map中


4. 遍历Map ,取出BeanDefinition,根据你上一步设置的各种属性,去做不同的操作,比如autoType 、是否懒加载等等等等,实例化Bean


5. 实例化完成以后,将实例化好的Bean放到map中 (就是spring容器),即Spring的单例池 singletonObjectsMap。


这里只会创建单例模式的Bean,prototype等类型的bean不会添加到单例池中,因为prototype每次都会new一个,没有必要去缓存。


当然了,Spring的实现是很复杂的,我们这里先对其大致的过程和原理有个初步的了解,方便后续源码的展开


20200911092320666.png

singleton vs prototype


spring容器在启动的时候就已经将singleton的bean 缓存到 单例池中,而 prototype类型的bean ,在spring容器启动的时候并不会被实例化,仅在调用的时候生成,且每次都一个新的对象 。

看个演示20200911095006795.png


加个断点,

可以发现 还没执行到ac.getBean(B.class),仅在容器启动阶段就已经实例化完成了singleton作用域的bean。

20200911095209116.png


接下来我们看下prototype类型的bean


20200911095236463.png


可以看到 在spring容器启动的时候,并没有实例化prototype类型的bean 。


2020091109540837.png

20200911095530349.png

Singleton VS Prototype 小结


我们看到了 Singleton VS Prototype的区别

  1. 创建时机不同: singleton的bean是在容器初始化的时候创建的,而原型bean是在调用的时候创建的
  1. 作用域不同: 单例singleton的bean 在容器中仅会创建一次,并且只有一个,而原型Prototype类型的bean每次调用都会初始化一个新的对象。


下文


下文我们探讨对象和bean的关系

相关文章
|
7天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
7天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
10 1
|
8天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
15 1
|
1月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
2月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
164 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
2月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
160 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
23天前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
|
23天前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
4天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
10 0
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
117 9