Cynicism Cynicism
首页
  • 前端学习笔记

    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript
    • JS设计模式总结
    • 小程序笔记
  • 后端学习笔记

    • 《JavaWeb》
    • 《SSM》
    • 《瑞吉外卖》
    • 《Git》
    • 《SpringCloud》
    • 《黑马点评》
    • 《Spring原理》
    • 《JVM》
    • 《Java并发编程》
    • 《学成在线》
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试
  • 常见问题
  • 实用技巧
  • 友情链接
实习
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Cynicism

Java后端学习中的IKUN
首页
  • 前端学习笔记

    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript
    • JS设计模式总结
    • 小程序笔记
  • 后端学习笔记

    • 《JavaWeb》
    • 《SSM》
    • 《瑞吉外卖》
    • 《Git》
    • 《SpringCloud》
    • 《黑马点评》
    • 《Spring原理》
    • 《JVM》
    • 《Java并发编程》
    • 《学成在线》
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试
  • 常见问题
  • 实用技巧
  • 友情链接
实习
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Bean生命周期
  • AOP
  • WEB
  • SpringBoot
  • 策略模式
  • 初始化IOC容器
    • 1. prepareRefresh()
    • 2. obtainFreshBeanFactory()
    • 3. prepareBeanFactory(beanFactory)
    • 4. postProcessBeanFactory(beanFactory)
    • 5. invokeBeanFactoryPostProcessors(beanFactory)
    • 6. registerBeanPostProcessors(beanFactory)
    • 7. initMessageSource()
    • 8. initApplicationEventMulticaster()
    • 9. onRefresh()
    • 10. registerListeners()
    • 11. finishBeanFactoryInitialization(beanFactory)
    • 12. finishRefresh()
    • 13. 总结
  • 《Spring原理》
cynicism
2024-01-08
目录

初始化IOC容器

提示

本文主要对启动容器过程中最核心的refresh()函数进行解析

# 1. prepareRefresh()

刷新前的预处理

  1. this.closed.set(false),this.active.set(true) 设置一些标记位
  2. initPropertySources()初始化一些属性设置;(交由子类去实现,比如web容器中的 AbstractRefreshableWebApplicationContext 就去初始化了servlet的一些init参数等等)
  3. getEnvironment().validateRequiredProperties();检验属性的合法等
  4. earlyApplicationEvents= new LinkedHashSet();初始化容器,保存一些早期的事件;

# 2. obtainFreshBeanFactory()

获取BeanFactory,注册配置文件中的Bean定义

  1. refreshBeanFactory(): 抽象方法,子类【AbstractRefreshableApplicationContext】唯一实现的:
    ① 若已经存在beanFactory了,那就做一些清理工作(销毁单例Bean、关闭工厂)
    ② 创建了一个this.beanFactory = new DefaultListableBeanFactory();并且设置id
    ③ 把旧的工厂的属性赋值给新创建的工厂:customizeBeanFactory(beanFactory)
    ④ loadBeanDefinitions(beanFactory):加载Bean定义。抽象方法,由子类去决定从哪儿去把Bean定义加载进来,实现有比如:
    • XmlWebApplicationContext:专为web设计的从xml文件里加载Bean定义(借助XmlBeanDefinitionReader)
    • ClassPathXmlApplicationContext/FileSystemXmlApplicationContext:均由父类 AbstractXmlApplicationContext去实现这个方法的,也是借助XmlBeanDefinitionReader
    • AnnotationConfigWebApplicationContext:基于注解驱动的容器。(也是当下最流行、最重要的一个实现,前面一篇博文对此有重点分析),借助了AnnotatedBeanDefinitionReader.register()方法加载Bean定义

(这里面需要注意的是:.register()只是把当前这一个Class对象registry.registerBeanDefinition()了,至于内部的@Bean、@ComponentScan扫描到的,都不是在此处注册的

有必要说一句:AnnotationConfigApplicationContext是在非web环境下的容器。它虽然没有实现实现loadBeanDefinitions()抽象方法,是因为它在new对象的时候,已经调用了.register()完成配置Bean定义信息的注册了

  1. getBeanFactory(): 返回刚才GenericApplicationContext创建的BeanFactory对象;
  2. 将创建的BeanFactory【DefaultListableBeanFactory】返回;

到这一步截止,BeanFactory已经创建好了(只不过都还是默认配置而已),配置Bean的定义信息也注册好了

# 3. prepareBeanFactory(beanFactory)

BeanFactory的预准备工作(对BeanFactory进行一些设置)

  1. 设置BeanFactory的类加载器、StandardBeanExpressionResolver、ResourceEditorRegistrar
  2. 添加感知后置处理器BeanPostProcessor【ApplicationContextAwareProcessor】,并设置一些忽略EnvironmentAware、EmbeddedValueResolverAware、xxxxx(因为这个处理器都一把抓了)
  3. 注册【可以解析的(表示虽然不在容器里,但还是可以直接 @Auwowired)】自动装配;我们能直接在任何组件中自动注入(@Autowired):BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
  4. 添加BeanPostProcessor【ApplicationListenerDetector】 检测注入进来的Bean是否是监听器
  5. Detect a LoadTimeWeaver and prepare for weaving, if found.添加编译时的AspectJ支持:LoadTimeWeaverAwareProcessor (添加的支持的条件是:beanFactory.containsBean("loadTimeWeaver"))
  6. 给BeanFactory中注册一些能用的组件;
    • environment-->【ConfigurableEnvironment】、
    • systemProperties-->【Map<String, Object>】、
    • systemEnvironment-->【Map<String, Object>】

# 4. postProcessBeanFactory(beanFactory)

BeanFactory准备工作完成后进行的后置处理工作(由子类完成)

一般web容器都会对应的实现此方法,比如 AbstractRefreshableWebApplicationContext:

  1. 添加感知BeanPostProcessor【ServletContextAwareProcessor】,支持到了ServletContextAware、ServletConfigAware
  2. 注册scopse:beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());当然还有SCOPE_SESSION、SCOPE_APPLICATION
  3. 向上线一样,注册【可以解析的】自动注入依赖:ServletRequest/ServletResponse/HttpSession/WebRequest (备注:此处放进容器的都是xxxObjectFactory类型,所以这是为何@Autowired没有线程安全问题的重要一步)
  4. registerEnvironmentBeans:注册环境相关的Bean(使用的registerSingleton,是直接以单例Bean放到容器里面了)
    • servletContext-->【ServletContext】
    • servletConfig-->【ServletConfig】
    • contextParameters-->【Map<String, String>】 保存有所有的init初始化参数(getInitParameter)
    • contextAttributes-->【Map<String, Object>】 servletContext的所有属性(ServletContext#getAttribute(String))

以上是BeanFactory的创建及预准备工作,至此准备工作完成了,那么接下来就得利用工厂干点正事了

# 5. invokeBeanFactoryPostProcessors(beanFactory)

执行BeanFactoryPostProcessor的方法(第四步中已经注册了此处理器)

BeanFactoryPostProcessor:BeanFactory的后置处理器。此处调用,现在就表示在BeanFactory标准初始化之后执行的;

两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor(子接口)

  1. 执行BeanFactoryPostProcessor们的方法;
    先执行BeanDefinitionRegistryPostProcessor
    • 获取所有的BeanDefinitionRegistryPostProcessor;(当然会最先执行我们手动set进去的Processor,但是这个一般都不会有)
    • 先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、postProcessor.postProcessBeanDefinitionRegistry(registry)
    • 在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor
    • 最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors

都会调用getBean(“name”,BeanDefinitionRegistryPostProcessor.class)方法,所以都会先实例化后处理器,再执行

笔记

这里面需要特别的介绍一个处理器:ConfigurationClassPostProcessor,它是一个BeanDefinitionRegistryPostProcessor它会解析完成所有的@Configuration配置类,然后所有@Bean、@ComponentScan等等Bean定义都会搜集进来了,所以这一步是非常的重要的。需要注意的是这个时候注册进来的bean还没有实例化。

再执行BeanFactoryPostProcessor的方法(顺序逻辑同上,略)

  1. 再次检测一次添加对AspectJ的支持。为何还要检测呢?through an @Bean method registered by ConfigurationClassPostProcessor,这样我们注入了一个切面Bean,就符合条件了嘛

上面5个步骤,已经Bean工厂完全准备好了,并且也注册好了所有的Bean的定义信息(此时Bean还并没有创建)

# 6. registerBeanPostProcessors(beanFactory)

注册BeanPostProcessor(Bean的后置处理器),实现在bean的初始化前后进行一些操作

不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的

  • BeanPostProcessor:BeanPostProcessor是一个工厂钩子,允许Spring框架在新创建Bean实例时对其进行定制化修改,比如填充Bean、创建代理、解析Bean内部的注解等等
  • DestructionAwareBeanPostProcessor:Bean销毁时候
  • InstantiationAwareBeanPostProcessor:Bean初始化的时候
  • SmartInstantiationAwareBeanPostProcessor:初始化增强版本:增加了一个对Bean类型预测的回调(一般是Spring内部使用,调用者还是使用InstantiationAwareBeanPostProcessor就好)
  • MergedBeanDefinitionPostProcessor:合并处理Bean定义的时候的回调【该类型的处理器保存在名为internalPostProcessors的List中】
  1. 获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
  2. 先注册PriorityOrdered优先级接口的BeanPostProcessor: 把每一个BeanPostProcessor添加到BeanFactory中
  3. 再注册Ordered接口的、最后注册没有实现任何优先级接口的、最终注册MergedBeanDefinitionPostProcessor

🔎此处细节:BeanPostProcessor本身也是一个Bean,其注册之前一定先实例化,而且是分批实例化和注册

# 7. initMessageSource()

初始化MessageSource组件(做国际化功能;消息绑定,消息解析)

  1. 看容器中是否有id为messageSource的,类型是MessageSource的组件,如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
  2. 把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource

# 8. initApplicationEventMulticaster()

初始化事件派发器

  1. 从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
  2. 如果上一步没有配置;创建一个SimpleApplicationEventMulticaster,将创建的ApplicationEventMulticaster添加到BeanFactory中

# 9. onRefresh()

留给子容器(子类) 容器刷新的时候做些事

# 10. registerListeners()

把容器中将所有项目里面的ApplicationListener注册进来

  1. 拿到容器里所有的Bean定义的名字,类型为ApplicationListener,然后添加进来:getApplicationEventMulticaster().addApplicationListener(listener);
  2. 派发之前步骤产生的事件(早期事件)

🔎细节:此处只是把Bean的名字放进去,Bean还没有实例化哦

# 11. finishBeanFactoryInitialization(beanFactory)

初始化所有剩下的单实例bean(主要是自定义的一些Bean);这应该是最核心的一步了

  1. 为容器初始化ConversionService(容器若没有就不用初始化了,依然采用getBean()初始化的) 提供转换服务
  2. 若没有设置值解析器,那就注册一个默认的值解析器(lambda表示的匿名处理)
  3. 实例化LoadTimeWeaverAware(若存在)
  4. 清空临时类加载器:beanFactory.setTempClassLoader(null)
  5. 缓存(快照)下当前所有的Bean定义信息 beanFactory.freezeConfiguration();
  6. beanFactory.preInstantiateSingletons(): 实例化后剩下的单实例bean

更精确的是说是根据Bean的定义信息:beanDefinitionNames来实例化、初始化剩余的Bean

# 12. finishRefresh()

完成BeanFactory的初始化创建工作;IOC容器就创建完成

  1. clearResourceCaches(); (Spring5.0才有)
  2. initLifecycleProcessor();初始化和生命周期有关的后置处理器;从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
  3. getLifecycleProcessor().onRefresh(); 相当于上面刚注册,下面就调用了
  4. publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
  5. liveBeansView.registerApplicationContext(this); 和MBean相关,略

# 13. 总结

  1. Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息(可以有N种方式);
    • xml注册bean;
    • 注解注册Bean;@Service、@Component、@Bean、xxx
  2. Spring容器会合适的时机创建这些Bean
    • 用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
    • 统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
  3. 后置处理器;BeanPostProcessor
    • 每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
    • AutowiredAnnotationBeanPostProcessor:处理自动注入
    • AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
    • ...
  4. 事件驱动模型
    • ApplicationListener;事件监听;
    • ApplicationEventMulticaster;事件派发:
编辑 (opens new window)
#spring
上次更新: 2025/05/12, 04:51:03
策略模式

← 策略模式

最近更新
01
JVM调优
06-03
02
Linux篇
03-30
03
Kafka篇
03-30
更多文章>
Theme by Vdoing | Copyright © 2023-2025 Cynicism | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式