Marvel-Site Marvel-Site
首页
  • Java

    • Java基础
    • Java进阶
    • Java容器
    • Java并发编程
    • Java虚拟机
  • 计算机基础

    • 数据结构与算法
    • 计算机网络
    • 操作系统
    • Linux
  • 框架|中间件

    • Spring
    • MySQL
    • Redis
    • MQ
    • Zookeeper
    • Git
  • 架构

    • 分布式
    • 高并发
    • 高可用
    • 架构
  • 框架

    • React
    • 其他
  • 实用工具
  • 安装配置

    • Linux
    • Windows
    • Mac
  • 开发工具

    • IDEA
    • VsCode
  • 关于
  • 收藏
  • 草稿
  • 索引

    • 分类
    • 标签
    • 归档
GitHub (opens new window)

Marvel

吾必当乘此羽葆盖车
首页
  • Java

    • Java基础
    • Java进阶
    • Java容器
    • Java并发编程
    • Java虚拟机
  • 计算机基础

    • 数据结构与算法
    • 计算机网络
    • 操作系统
    • Linux
  • 框架|中间件

    • Spring
    • MySQL
    • Redis
    • MQ
    • Zookeeper
    • Git
  • 架构

    • 分布式
    • 高并发
    • 高可用
    • 架构
  • 框架

    • React
    • 其他
  • 实用工具
  • 安装配置

    • Linux
    • Windows
    • Mac
  • 开发工具

    • IDEA
    • VsCode
  • 关于
  • 收藏
  • 草稿
  • 索引

    • 分类
    • 标签
    • 归档
GitHub (opens new window)
  • 关于

  • 收藏

  • 草稿

    • 控制反转与依赖注入
    • Spring创建Bean的过程
      • 环境搭建
      • refresh() 说明
        • AnnotationConfigApplicationContext
        • ClassPathXmlApplicationContext
      • refresh() 核心方法
        • 1. prepareRefresh()
        • 2. obtainFreshBeanFactory()
        • refreshBeanFactory()
        • getId()
        • setSerializationId()
        • getBeanFactory()
        • 3. prepareBeanFactory()
  • 更多
  • 草稿
Marvel
1999-04-07
目录

Spring创建Bean的过程

# 环境搭建

# refresh() 说明

Spring IoC 容器对 Bean 定义资源的载入是从 refresh() 函数开始的,refresh() 是一个模板方法,refresh() 方法的作用是在创建 IoC 容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在 refresh() 之后使用的是新建立起来的 IoC 容器。

refresh() 是 AbstractApplicationContext 内的模板方法,可以被子类重写。

refresh() 包含 12 关键方法:

  • prepareRefresh()
  • obtainFreshBeanFactory()
  • prepareBeanFactory()
  • postProcessBeanFactory()
  • invokeBeanFactoryPostProcessors()
  • registerBeanPostProcessors()
  • initMessageSource()
  • initApplicationEventMulticaster()
  • onRefresh()
  • registerListeners()
  • finishBeanFactoryInitialization(beanFactory)
  • finishRefresh()

启动 Spring 容器经常采用两种方案:

  1. AnnotationConfigApplicationContext 直接读取配置类加载 Bean
  2. ClasspathXmlApplicationContext 通过配置文件加载 Bean

# AnnotationConfigApplicationContext

如果通过配置类启动容器,可以使用 AnnotationConfigApplicationContext 进行创建。

image-20240423204707712

没有重写 refresh() 内的12个方法。

# ClassPathXmlApplicationContext

如果通过注解文件启动容器,可以使用 ClassPathXmlApplicationContext 进行创建。

image-20240423212538932

# refresh() 核心方法

# 1. prepareRefresh()

为 applicationContext 容器做准备,设置其启动日期和活动标志,以及执行任何属性源的初始化。

# 2. obtainFreshBeanFactory()

该方法主要是获取到应用上下文维护的 beanFactory,默认是 DefaultListableBeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}
1
2
3
4

# refreshBeanFactory()

调用 GenericApplicationContext 的 refreshBeanFactory() 方法。其首先应用 CAS 思想设置刷新标志,然后为 beanFactory 设置序列化ID,默认是application。

@Override
protected final void refreshBeanFactory() throws IllegalStateException {

    // 通过CAS设置当前为正在refresh
    if (!this.refreshed.compareAndSet(false, true)) {
        throw new IllegalStateException(
                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }
    // 设置序列化ID
    this.beanFactory.setSerializationId(getId());
}
1
2
3
4
5
6
7
8
9
10
11

当前对象 this 指的是 AnnotationConfigServletWebServerApplicationContext,而 refreshBeanFactory 调用是其祖父类 GenericApplicationContext 。

# getId()

AbstractApplicationContext 的 getId() 方法。

private String id = ObjectUtils.identityToString(this);
	
public String getId() {
    return this.id;
}
1
2
3
4
5

返回结为:org.springframework.context.annotation.AnnotationConfigApplicationContext@2dda6444,就是 Main 函数中创建的 Spring 容器。

# setSerializationId()
public void setSerializationId(@Nullable String serializationId) {
    if (serializationId != null) { // 成立
        // serializableFactories 是类变量
        // 将<序列化ID,容器>放到map中,可以根据ID找到容器
        serializableFactories.put(serializationId, new WeakReference<>(this));
    }
    else if (this.serializationId != null) {
        serializableFactories.remove(this.serializationId);
    }
    this.serializationId = serializationId;
}
1
2
3
4
5
6
7
8
9
10
11

image-20240423193956350

# getBeanFactory()

调用 GenericApplicationContext 的 getBeanFactory() 方法,返回当前 beanFactory 对象,默认是 DefaultListableBeanFactory 类型。

@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
	return this.beanFactory;
}
1
2
3
4

# 3. prepareBeanFactory()

该方法主要是对 beanFactory 做了一些基础设置的配置,比如 BeanClassLoader、BeanExpressionResolver、ApplicationContextAwareProcessor、ApplicationListenerDetector 监听器检测器以及默认的环境信息 bean。并设置了哪些不需要自动注入以及哪些已经解析过可以直接使用。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 设置类加载器,默认是RestartClassLoader
	beanFactory.setBeanClassLoader(getClassLoader());

	// 设置表达式解析器,比如SPEL语法就是该解析器内维护的SpelExpressionParser进行处理的
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	
	// 注册一个属性编辑器注册器,用于将字符串值转换为特定类型的对象的组件
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// 为beanFactory配置一些回调,这些在bean实例化过程中会被触发
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

	// 告诉BeanFactory在进行依赖注入时忽略指定的接口,在进行依赖注入时,BeanFactory将不会自动注入实现了这些接口的bean
  // 我们可以通过其他方式手动处理这些依赖关系,例如通过自定义的注入逻辑或者使用特定的注解。
  // 当我们希望在某些接口上使用特定的注解来进行依赖注入时,可以将这些接口添加到ignoreDependencyInterface列表中,以避免自动注入的冲突。
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// 向BeanFactory注册可解析的依赖项,当遇到这个特定的依赖项时,不需要进行自动解析,而是使用我们提供的值或对象
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// 添加ApplicationListenerDetector后置处理器
  // 可以在Bean的初始化过程中检测并处理实现了ApplicationListener接口的Bean,将其注册为应用程序上下文的事件监听器
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// 如果不包含,则注册
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// 注册三个环境相关的Bean对象
  // 环境对象
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
  // 系统属性Map:java.runtime.version、user.name等等
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
  // 系统环境Map:比如当前PATH、USER、HOME等等
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
  
  // 注册完成后,singletonObjects单例池中多了三个Bean对象
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
编辑 (opens new window)
上次更新: 2024/05/10, 19:32:46
控制反转与依赖注入

← 控制反转与依赖注入

最近更新
01
位运算
05-21
02
二叉树
05-12
03
Spring三级缓存解决循环依赖
03-25
更多文章>
Theme by Vdoing | Copyright © 2022-2024 Marvel
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式