zoukankan      html  css  js  c++  java
  • Spring IOC 初始化刷新流程

    Spring Web 环境下(存在父子容器),注解驱动容器实例为:AnnotationConfigWebApplicationContext,XML 配置驱动容器实例为:XmlWebApplicationContext

    SpringBoot Web 环境下容器实例为(单一容器):AnnotationConfigServletWebServerApplicationContext

    一、调试环境

    只是研究 IOC 启动刷新流程,其实不管什么方式启动 IOC,都是用的一样的代码(一个父类,主要启动流程在这个父类里)

    非 Web 环境:https://gitee.com/jhxxb/MySpringBoot/tree/master/spring-base/Spring-IOC/src/main/java/s_001_Bean_Registered

    Web 环境:https://gitee.com/jhxxb/MySpringBoot/tree/master/web-base/spring-mvc

    图中这两个类,是非 web 环境下注解驱动启动和 xml 配置启动的实例类,可以看到它们有共同的父类 AbstractApplicationContext

    其中 StaticApplicationContext 一般用于测试,几乎不使用

    再看 AbstractApplicationContext 的接口

    refresh() 方法所有的 ApplicationContext 子类都没重写,只有 AbstractApplicationContext 里有实现过(接口定义在 ConfigurableApplicationContext)

    二、开始源码

    public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
        public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
            this();
            register(componentClasses); // 把配置类(们)注册进来
            refresh(); // 容器启动核心方法
        }
    
        public AnnotationConfigApplicationContext() {
            // AnnotatedBeanDefinitionReader 是一个读取注解的 Bean 读取器,这里将 this 传了进去。
            this.reader = new AnnotatedBeanDefinitionReader(this);
            this.scanner = new ClassPathBeanDefinitionScanner(this);
    
            // 从上面这个构造函数可以顺便提一句:如果你仅仅是这样 ApplicationContext applicationContext = new AnnotationConfigApplicationContext()
            // 容器是不会启动的(也就是不会执行refresh()的),这时候需要自己之后再手动启动容器
        }
    
        @Override
        public void register(Class<?>... componentClasses) {
            Assert.notEmpty(componentClasses, "At least one component class must be specified");
            this.reader.register(componentClasses);
        }

    refresh()

    public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
        @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.
                // 获取新的 beanFactory,销毁原有 beanFactory、为每个 bean 生成 BeanDefinition 等。注意,此处是获取新的,销毁旧的,这就是刷新的意义
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                // 配置标准的 beanFactory,设置 ClassLoader,设置 SpEL 表达式解析器等
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    // 模板方法,允许在子类中对 beanFactory 进行后置处理。
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    // 实例化并调用所有注册的 beanFactory 后置处理器(实现接口 BeanFactoryPostProcessor 的 bean)。
                    // 在 beanFactory 标准初始化之后执行  例如:PropertyPlaceholderConfigurer(处理占位符)
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    // 实例化和注册 beanFactory 中扩展了 BeanPostProcessor 的 bean。
                    // 例如:
                    // AutowiredAnnotationBeanPostProcessor(处理被 @Autowired 注解修饰的 bean 并注入)
                    // RequiredAnnotationBeanPostProcessor(处理被 @Required 注解修饰的方法)
                    // CommonAnnotationBeanPostProcessor(处理 @PreDestroy、@PostConstruct、@Resource 等多个注解的作用)等。
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    // 初始化国际化工具类 MessageSource
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    // 初始化事件广播器
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    // 模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的 Spring 容器做不同的事情
                    onRefresh();
    
                    // Check for listener beans and register them.
                    // 注册监听器,并且广播 early application events,也就是早期的事件
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    // 非常重要。。。实例化所有剩余的(非懒加载)单例 Bean。(也就是我们自己定义的那些 Bean 们)
                    // 比如 invokeBeanFactoryPostProcessors 方法中根据各种注解解析出来的类,在这个时候都会被初始化  扫描的 @Bean 之类的
                    // 实例化的过程各种 BeanPostProcessor 开始起作用~~~~~~~~~~~~~~
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    // refresh 做完之后需要做的其他事情
                    // 清除上下文资源缓存(如扫描中的 ASM 元数据)
                    // 初始化上下文的生命周期处理器,并刷新(找出 Spring 容器中实现了 Lifecycle 接口的 bean 并执行 start() 方法)。
                    // 发布 ContextRefreshedEvent 事件告知对应的 ApplicationListener 进行响应的操作
                    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.
                    // 如果刷新失败那么就会将已经创建好的单例 Bean 销毁掉
                    destroyBeans();
    
                    // Reset 'active' flag.
                    // 重置 context 的活动状态 告知是失败的
                    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...
                    // 失败与否,都会重置 Spring 内核的缓存。因为可能不再需要 metadata 给单例 Bean 了
                    resetCommonCaches();
                }
            }
        }

    三、具体步骤

    一、prepareRefresh()

    https://www.cnblogs.com/jhxxb/p/13650829.html

    二、obtainFreshBeanFactory()

    https://www.cnblogs.com/jhxxb/p/13950058.html

    三、prepareBeanFactory(beanFactory)

    https://www.cnblogs.com/jhxxb/p/13953664.html

    四、postProcessBeanFactory(beanFactory)

    https://www.cnblogs.com/jhxxb/p/13953816.html

    五、invokeBeanFactoryPostProcessors(beanFactory)

    https://www.cnblogs.com/jhxxb/p/13955154.html

    六、registerBeanPostProcessors(beanFactory)

    https://www.cnblogs.com/jhxxb/p/13957928.html

    七八九十、initMessageSource()、initApplicationEventMulticaster()、onRefresh()、registerListeners()

    https://www.cnblogs.com/jhxxb/p/13960012.html

    十一、finishBeanFactoryInitialization(beanFactory)

    https://www.cnblogs.com/jhxxb/p/13960276.html

    十二、finishRefresh()

    https://www.cnblogs.com/jhxxb/p/13985589.html


    https://blog.csdn.net/f641385712/article/details/88041409

    https://blog.csdn.net/f641385712/article/details/88118288

    https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core

    https://blog.csdn.net/heroqiang/article/details/81110238

    https://javadoop.com/post/spring-ioc

  • 相关阅读:
    寒假学习10
    寒假学习9
    寒假学习8
    寒假学期7
    寒假学习6
    寒假学习5
    寒假学习4
    Notification通知栏的使用
    Service的使用
    BroadcastReceive的使用
  • 原文地址:https://www.cnblogs.com/jhxxb/p/13609289.html
Copyright © 2011-2022 走看看