【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(一)(下)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(一)(下)

refresh() 第四步:postProcessBeanFactory(beanFactory)


模版方法。因为beanFactory都准备好了,子类可以自己去实现自己的逻辑。

比如一些web的ApplicationContext,就实现了自己的逻辑,做一些自己的web相关的事情。此处我们就是web环境下,因此会进来AbstractRefreshableWebApplicationContext#postProcessBeanFactory方法:


  @Override
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //注册ServletContextAwareProcessor 这样任意Bean都可以很方便的获取到ServletContext了  同时忽略另外两个,因为ServletContextAwareProcessor 都把事情都做了
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
    //注册web环境,包括request、session、golableSession、application
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    //注册servletContext、contextParamters、contextAttributes  、servletConfig单例bean
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
  }


这里面两个工具方法,具体做了什么,请参考:

【小家Spring】spring-web包里的一些好用的工具介绍,WebUtils,RequestContextUtils,WebApplicationContextUtils等

refresh() 第五步:invokeBeanFactoryPostProcessors(beanFactory)


invokeBeanFactoryPostProcessors执行BeanFactory后置处理器,当然前提是你已经在容器中注册过此处理器了。


  protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    // 这里就是定制:如果loadTimeWeaver这个Bean存在,那么就会配置上运行时织入的处理器LoadTimeWeaverAwareProcessor
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
  }


这里面我们必须先看看getBeanFactoryPostProcessors()这个方法:

  public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
    return this.beanFactoryPostProcessors;
  }



这里非常有意思。方法非常简单,但有意思在于:它不是返回Spring容器里面的Processors,而是你自己的注册的(你自己手动set的),也就是说我们自己手动调用set方法添加进去,就能够执行。并不需要自己配置@Bean或者在xml里配置


那么重点就在于PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,它的代码可谓非常非常多:

  public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    // 这个doc说明很清楚:不管怎么样,先执行BeanDefinitionRegistryPostProcessors 
    // 需要注意的是BeanDefinitionRegistryPostProcessors 为 BeanFactoryPostProcessor 的子接口 它新增了方法:void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
    // BeanFactoryPostProcessor 的方法为;void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    // 所以BeanDefinitionRegistryPostProcessors,它可以我们介入,改变Bean的一些定义信息
    Set<String> processedBeans = new HashSet<>();
    // 只有此beanFactory 是BeanDefinitionRegistry  才能执行BeanDefinitionRegistryPostProcessor,才能修改Bean的定义嘛~
    if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      // 此处安放了两个容器,一个装载普通的BeanFactoryPostProcessor
      // 另外一个装载和Bean定义有关的 BeanDefinitionRegistryPostProcessor
      // 另外都是LinkedList,所以执行顺序和set进去的顺序是保持一样的
      List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
      // 这里是我们自己的set进去的,若没set,这里就是空(若是Sprng容器里的,下面会处理,见下面)
      // 从此处可以看出,我们手动set进去的,最最最最有限执行的
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
        if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
          BeanDefinitionRegistryPostProcessor registryProcessor =
              (BeanDefinitionRegistryPostProcessor) postProcessor;
          // 这里执行post方法,然后然后吧它缓冲起来了,放在了registryProcessors里
          registryProcessor.postProcessBeanDefinitionRegistry(registry);
          registryProcessors.add(registryProcessor);
        }
        else {
          // 缓冲起来常规的处理器
          regularPostProcessors.add(postProcessor);
        }
      }
      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let the bean factory post-processors apply to them!
      // Separate between BeanDefinitionRegistryPostProcessors that implement
      // PriorityOrdered, Ordered, and the rest.
      // 接下来,就是去执行Spring容器里面的一些PostProcessor了。他们顺序doc里也写得很清楚:
      // 先执行实现了PriorityOrdered接口的,然后是Ordered接口的,最后执行剩下的
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
      // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
      // 先从容器中拿出来所有的BeanDefinitionRegistryPostProcessor 然后先执行PriorityOrdered
      // 本例中有一个这个类型的处理器:ConfigurationClassPostProcessor(显然是处理@Configuration这种Bean的)
      // 至于这个Bean是什么时候注册进去的,前面有。在loadBeanDefinitions()初始化AnnotatedBeanDefinitionReader的时候调用的AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)方法的时候,注册了6个Bean
      String[] postProcessorNames =
          beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
          // processedBeans也顺带保存了一份,保存的是bean的Name哦~
          currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
          processedBeans.add(ppName);
        }
      }
      // 排序
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      // 此处缓冲起来(需要注意的是,是排序后,再放进去的 这样是最好的)
      registryProcessors.addAll(currentRegistryProcessors);
      // 这个方法很简单,就是吧currentRegistryProcessors里面所有的处理器for循环一个个的执行掉(本处只有ConfigurationClassPostProcessor,详见我的另一篇专门博文讲解)
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      // 此处把当前持有的执行对象给清空了,需要注意。以方便装载后续执行的处理器们
      currentRegistryProcessors.clear();
      // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
      // 此处逻辑完全同上  处理实现Order接口的RegistryProcessors
      postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
        if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
          currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
          processedBeans.add(ppName);
        }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
      // 最后执行,两个排序接口都没有实现的BeanDefinitionRegistryPostProcessor们,并且也缓存起来
      boolean reiterate = true;
      while (reiterate) {
        reiterate = false;
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
          if (!processedBeans.contains(ppName)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
            reiterate = true;
          }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();
      }
      // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
      // 现在,这里很明显:去执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
      // 以及 顶层接口BeanFactoryPostProcessor的postProcessBeanFactory方法
      // 我们当前环境regularPostProcessors长度为0.registryProcessors有一个解析@Configuration的处理器
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    } else {
      // Invoke factory processors registered with the context instance.
      // 若是普通的Bean工厂,就直接执行set进来的后置处理器即可(因为容器里就没有其它Bean定义了)
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!
    // 下面就是开始执行BeanFactoryPostProcessor 基本也是按照上面的顺序来执行的
    // 上面9个Bean,我们知道 也就ConfigurationClassPostProcessor是实现了此接口的。因此本环境下,只有它了,并且它在上面还已经执行了
    String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
      // 这里面注意,已经执行过的后置处理器,就不要再执行了
      if (processedBeans.contains(ppName)) {
        // skip - already processed in first phase above
      }
      else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
        orderedPostProcessorNames.add(ppName);
      }
      else {
        nonOrderedPostProcessorNames.add(ppName);
      }
    }
    // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    // Finally, invoke all other BeanFactoryPostProcessors.
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
    beanFactory.clearMetadataCache();
  }


ConfigurationClassPostProcessor处理器解析: 【小家Spring】Spring解析@Configuration注解的处理器:ConfigurationClassPostProcessor(ConfigurationClassParser)


postProcessBeanDefinitionRegistry和postProcessBeanFactory方法:

两者都存在于BeanDefinitionRegistryPostProcessor接口中,表明其既可以自定义BeanDefinition并注册进容器中也可以对beanFactory的修改


那为什么逻辑要先执行postProcessBeanDefinitionRegistry然后在执行postProcessBeanFactory呢?


因为postProcessBeanDefinitionRegistry是用来创建bean定义的,而postProcessBeanFactory是修改BeanFactory,当然postProcessBeanFactory也可以修改bean定义的。为了保证在修改之前所有的bean定义的都存在,所以优先执行postProcessBeanDefinitionRegistry。如不是以上顺序,会出先再修改某个bean定义的报错,因为此bean定义的还没有被创建。


至此,invokeBeanFactoryPostProcessors(beanFactory)这一步就完成了。这一步主要做了:


1.执行了BeanDefinitionRegistryPostProcessor(此处只有ConfigurationClassPostProcessor)


2.执行了BeanFactoryPostProcessor


3.完成了@Configuration配置文件的解析,并且把扫描到的、配置的Bean定义信息都加载进容器里


4.Full模式下,完成了对@Configuration配置文件的加强,使得管理Bean依赖关系更加的方便了


这里注册Bean定义的时候有个小细节:我们都知道Spring支持到了FactoryBean的模式,所以这里如果发现注册的Bean为FactoryBean类型的话,会把自己以及getObject()出来的对象的Bean定义都注册上去。并且FactoryBean的名称为:beanName = FACTORY_BEAN_PREFIX + beanName; 这一点需要注意

总结


上面5个步骤,已经Bean工厂完全准备好了,并且也注册好了所有的Bean的定义信息(此时Bean还并没有创建)。也完成了对配置文件的解析,可以说Spring IOC容器的大的准备工作已经完成了,在接下来的一篇博文里,会详细讲述到对Bean的一些初始化、以及操作~

相关文章
|
4天前
|
XML Java 数据格式
Spring容器的本质
本文主要讨论Spring容器最核心的机制,用最少的代码讲清楚Spring容器的本质。
|
8天前
|
IDE Java 应用服务中间件
spring boot 启动流程
Spring Boot 启动流程简介: 在使用 Spring Boot 之前,启动 Java Web 应用需要配置 Web 容器(如 Tomcat),并将应用打包放入容器目录。而使用 Spring Boot,只需运行 main() 方法即可启动 Web 应用。Spring Boot 的核心启动方法是 SpringApplication.run(),它负责初始化和启动应用上下文。 主要步骤包括: 1. **应用启动计时**:使用 StopWatch 记录启动时间。 2. **打印 Banner**:显示 Spring Boot 的 LOGO。 3. **创建上下文实例**:通过反射创建
|
2月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
74 6
|
2月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
50 1
|
3月前
|
前端开发 Java Docker
使用Docker容器化部署Spring Boot应用程序
使用Docker容器化部署Spring Boot应用程序
|
3月前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
72 0
|
29天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
233 17
Spring Boot 两种部署到服务器的方式
|
29天前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
61 17
springboot自动配置原理
|
1月前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
87 11
|
1月前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
366 12

热门文章

最新文章