为了演示Spring中对象是如何创建并放到spring容器中,这里新建一个maven项目:

其中pom.xm文件中只引入了一个依赖:

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.9.RELEASE</version>
</dependency>
</dependencies>

其实我们只需要这一个,不过spring还是会自动导入他别的依赖,例如spring core,spring aop:

需要说明的是我这里并没有建spring boot项目,只是引入一个spring context依赖的maven项目。

新建一个config配置类,并没有@Configuration注解:

@ComponentScan("component")
public class MyConfig {
}

只有一个@ComponentScan注解,去扫描指定包。

新建一个类(bean),只有@Component注解:

@Component
public class People {
}

新建Test类,此类去创建spring context(spring上下文,或者说是spring容器):

import config.MyConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Test {
public static void main(String[] args) {
//通过注解配置类初始化 spring上下文
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
//还有一种通过xml来初始化 spring上下文,这里就不介绍了。
//ClassPathXmlApplicationContext
System.out.println(annotationConfigApplicationContext.getBean("people"));
}
}

项目结构如图:

我们只关注bean的创建,所以在 new AnnotationConfigApplicationContext(MyConfig.class) 时会去扫描类,然后实例化。

this()调用此类的构造器:

这个reader和scanner和这里bean实例化没有关系,是一些扩展。我们关注他的父类构造器:

可见this()方法就是建立一个beanFactory工厂,至于细节暂时不去深入。

register()方法作用是新建一个BeanDefinition。

BeanDefinition顾名思义就是spring定义的一个描述bean的类,这个是接口,其描述类的属性由其子类扩展,比如class,lazy(懒加载)等等:

上面时AbstarctBeanDefinition类下的属性。spring根据我们的类(不管是@Service,@Controller,或者是通过@Bean方式),生成对应的BeanDefinition对象。

再把它放到一个Map中:

registerBeanDefinition有三个实现方法,不管哪个都有下面这一句:

即把各个BeanDefinition对象放入beanDefinitionMap中去,而这些map的集合就是spring 的容器。

所以register()做了两件事:

1:生成对应BeanDefinition对象;

2:放入beanDefinitionMap中。

最后再来看refresh()方法:

这个方法是spring中最复杂也是最重要的方法:

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

其中invokeBeanFactoryPostProcessors()方法需要讲一讲,详见下一篇。

Spring Boot源码(五):BeanFactoryPostProcessor和BeanPostProcessor

Spring Boot源码(四):Bean装配的更多相关文章

  1. 曹工说Spring Boot源码(6)-- Spring怎么从xml文件里解析bean的

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  2. 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享

    写在前面的话&&About me 网上写spring的文章多如牛毛,为什么还要写呢,因为,很简单,那是人家写的:网上都鼓励你不要造轮子,为什么你还要造呢,因为,那不是你造的. 我不是要 ...

  3. 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...

  4. 曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 大 ...

  5. 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean definition的?

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 大 ...

  6. 曹工说Spring Boot源码(5)-- 怎么从properties文件读取bean

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  7. Spring Boot源码(六):Bean的创建详解

    继续之前的项目: People加上无参构造方法: @Component public class People { // private User user; public People(){ Sys ...

  8. 曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(context命名空间上)

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  9. # 曹工说Spring Boot源码(10)-- Spring解析xml文件,到底从中得到了什么(context:annotation-config 解析)

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

随机推荐

  1. iNeuOS工业互联平台,iNeuKernel(物联网核心组件)远程控制标准化设计与实现。发布v2.3版本。

    目       录 1.      概述... 2 2.      平台演示... 2 3.      控制端与iNeuKernel的交互协议... 3 4.      设备驱动实现控制业务... 4 ...

  2. this和static

    [this] 指的是明确的标记本类的结构 当前正在调用类中方法的对象,不是一个固定的 java中以“{}”为界限.如果现在属性名称和参数名称重名,那么默认情况下,如果没有加任何的限制,指的是最近的“{ ...

  3. Node.js实战--资源压缩与zlib模块

    Blog:<NodeJS模块研究 - zlib> Github:https://github.com/dongyuanxin/blog nodejs 的 zlib 模块提供了资源压缩功能. ...

  4. SendInput模拟键盘操作

    #include <windows.h> int main() { HWND parentHwnd, childHwnd; INPUT input[4]; parentHwnd = Fin ...

  5. vscode下搭建vue.js开发环境(基于最新的@Vue/cli 4.2.2)

    2020-02-13. 网上的那些怎么安装vue环境的2.x就不要再看了,都过时了,现在去官网下载,按照他们的设置各种问题.接下来看下最新的安装方法. 前四步是一样的: 1.下载并安装vscode 2 ...

  6. C语言关于getchar()的小笔记

    #include <windows.h> #include <mmsystem.h> #include <string.h> void main() { int a ...

  7. Sophus库CMakeLists.txt内容详解笔记

    CMakeLists.txt: SET(PROJECT_NAME Sophus) PROJECT(${PROJECT_NAME}) CMAKE_MINIMUM_REQUIRED(VERSION 2.6 ...

  8. 部署 harbor 私有仓库

    安装下载依赖包 安装docker-compose 从 docker compose 发布页面下载最新的 docker-compose 二进制文件,本文以1.25.4为例 cd /opt/k8s/wor ...

  9. python 函数3(模块)

    1.将函数存储在模块中 1.1.导入整个模块 要将函数导入,得先创建模块,模块 是扩展名为.py的文件,包含要导入到程序中的代码. 首先定义编写一个.py的文件,命名为pizza.py,代码如下: d ...

  10. c++ 中变量成员的初始化时机

    代码如下: 注意一下我打断点的位置. 最后的结果: 在程序进入MyTest()的函数体之前,控制台就打印出来了I have been constructed. 即:在进入构造函数的函数体之前,类中的成 ...