聚焦IOC容器刷新环节postProcessBeanFactory(BeanFactory后置处理)专项 📅 发布时间:2026/9/7 14:04:36 👁 浏览次数: 目录一、IOC容器的刷新环节快速回顾二、postProcessBeanFactory源码展示分析一模版方法postProcessBeanFactory二AnnotationConfigServletWebServerApplicationContext调用父类的 postProcessBeanFactory包扫描注解类注册三postProcessBeanFactory 主要功能三、调用父类方法以继承基础设置和逻辑一重要任务回顾二注册 WebApplicationContextServletContextAwareProcessor三忽略 ServletContextAware 接口的依赖四注册 Web 应用程序范围ExistingWebApplicationScopes 的角色注册 Web 应用程序作用域四、执行包扫描五、注解类注册一扫描和注册注解类的过程步骤扫描注解类创建 BeanDefinition注册 BeanDefinition二对注解类注册的理解新思路新的思路六、总结干货分享感谢您的阅读在很早之前我们单独写过一篇文章《分析SpringBoot启动配置原理》具体可见分析SpringBoot启动配置原理_spring启动加载顺序及原理-CSDN博客文章浏览阅读1.6w次点赞15次收藏43次。分析SpringBoot启动配置原理给出整体初步分析和对应流程图并从三方面进行展开分析SpringApplication构造过程分析SpringApplication启动过程分析SpringBoot自动配置分析_spring启动加载顺序及原理https://blog.csdn.net/xiaofeng10330111/article/details/130903779?ops_request_misc%257B%2522request%255Fid%2522%253A%2522171829487016800213028572%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257Drequest_id171829487016800213028572biz_id0utm_mediumdistribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-130903779-null-null.nonecaseutm_term%E5%88%86%E6%9E%90SpringBoot%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86spm1018.2226.3001.4450其中IOC容器的刷新环节可当重点分析值得在读源码时进行深入分析我们会从多个方向上再次进行分析回顾和学习。历史其他专项展示具体内容具体链接探究Spring BeanFactory重看Spring聚焦BeanFactory分析_java beanfactory 实现类-CSDN博客探究Spring ApplicationContext重看Spring聚焦ApplicationContext分析_applicationcontext消息资源处理-CSDN博客ApplicationContext vs BeanFactory解锁ApplicationContext vs BeanFactory: 谁更具选择性-CSDN博客探究Spring Environment重看Spring聚焦Environment分析-CSDN博客探究Spring BeanDefintion重看Spring聚焦BeanDefinition分析和构造-CSDN博客对焦后置处理器聚焦Spring后置处理器分析对比_spring的后置处理器分析-CSDN博客BeanFactory - obtainFreshBeanFactory专项聚焦IOC容器刷新环节obtainFreshBeanFactory初始化BeanFactory专项_refreshbeanfactory-CSDN博客prepareBeanFactory专项聚焦IOC容器刷新环节prepareBeanFactory专项-CSDN博客一、IOC容器的刷新环节快速回顾我们将AbstractApplicationContext的refresh方法源码提取并进行重点代码标注说明如下public abstract class AbstractApplicationContext implements ApplicationContext { Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备上下文环境包括初始化工厂、后置处理器等 prepareRefresh(); // 创建并初始化 BeanFactory ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory(); // 设置 BeanFactory 的类加载器、资源加载器等 prepareBeanFactory(beanFactory); try { // 允许子类对 BeanFactory 进行进一步的自定义处理 postProcessBeanFactory(beanFactory); // 调用 BeanFactoryPostProcessors 进行后置处理 invokeBeanFactoryPostProcessors(beanFactory); // 注册 BeanPostProcessors用于对 Bean 实例进行后置处理 registerBeanPostProcessors(beanFactory); // 初始化消息源 initMessageSource(); // 初始化事件广播器 initApplicationEventMulticaster(); // 初始化其他特殊 Bean onRefresh(); // 注册关闭钩子 registerListeners(); // 初始化所有剩余的单例 Bean finishBeanFactoryInitialization(beanFactory); // 完成上下文刷新 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn(Exception encountered during context initialization - cancelling refresh attempt: ex); } // 销毁已创建的 Bean关闭容器 destroyBeans(); // 重置容器刷新标志允许再次刷新 cancelRefresh(ex); // 把异常重新抛出允许调用者处理 throw ex; } finally { // 重置已注册的 JVM 关闭钩子 resetCommonCaches(); } } } }以上内容请多次翻看并理解如果忘记了最好在次读一下之前的原文博客进行基本的回顾我们本次讲聚焦其中的postProcessBeanFactory专项展开分析。二、postProcessBeanFactory源码展示分析postProcessBeanFactory是一个允许子类在BeanFactory完成初始化之后但在Bean实例化之前对其进行进一步自定义的钩子方法。虽然在AbstractApplicationContext中该方法是一个空实现该方法就是一个模版方法但子类可以覆盖此方法以添加特定的逻辑。一模版方法postProcessBeanFactory在AbstractApplicationContext类中postProcessBeanFactory方法定义如下protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 默认实现为空子类可以覆盖此方法进行自定义处理 }直观的看下有哪些子类进行了具体的实现以上是几个常见子类对postProcessBeanFactory方法的具体实现我们一般探究其中一个即可理解体会其他可当作扩展去学习。二AnnotationConfigServletWebServerApplicationContext我们以AnnotationConfigServletWebServerApplicationContext为基本去体会一下Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); if (this.basePackages ! null this.basePackages.length 0) { this.scanner.scan(this.basePackages); } if (!this.annotatedClasses.isEmpty()) { this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); } }调用父类的postProcessBeanFactorysuper.postProcessBeanFactory(beanFactory);确保父类postProcessBeanFactory方法中的所有逻辑都会被执行。通过调用父类的方法继承了父类的初始化和处理逻辑常包括一些基本的设置和注册操作为后续的自定义逻辑打下基础。包扫描if (this.basePackages ! null this.basePackages.length 0) { this.scanner.scan(this.basePackages); }this.scanner是一个ClassPathBeanDefinitionScanner实例它负责扫描指定的包路径 (basePackages)从而找到并注册符合条件的Bean它会扫描指定的包路径寻找符合条件的组件类如带有Component、Service、Repository、Controller注解的类并将它们注册为Bean定义。注解类注册if (!this.annotatedClasses.isEmpty()) { this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); }this.reader是一个AnnotatedBeanDefinitionReader实例它负责将指定的注解类 (annotatedClasses如带有Configuration、Component注解的类) 注册到BeanFactory中从而使这些类能够参与到 Spring 的依赖注入和生命周期管理中。ClassUtils.toClassArray将一个SetClass?转换为一个Class?[]数组这个转换在将注解类注册到AnnotatedBeanDefinitionReader中时非常有用。三postProcessBeanFactory主要功能从上述分析可以看出在 Spring IOC 容器中postProcessBeanFactory方法的主要功能可归纳为调用父类方法以继承基础设置和逻辑: 确保基本的设置和注册操作在子类中得到执行。进行包扫描: 扫描指定的包路径自动发现并注册符合条件的组件类可以通过注解配置的方式管理Bean减少手动注册的工作量。注册注解类: 将特定的注解类注册到BeanFactory中使其参与到 Spring 的依赖注入和生命周期管理中。三、调用父类方法以继承基础设置和逻辑protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ServletContextAware.class); this.registerWebApplicationScopes(); }一重要任务回顾postProcessBeanFactory方法主要完成了以下几个重要任务注册WebApplicationContextServletContextAwareProcessor: 添加一个BeanPostProcessor处理实现了ServletContextAware接口的 bean注入ServletContext对象。忽略ServletContextAware接口的依赖: 告诉BeanFactory忽略对ServletContextAware接口的自动依赖注入。注册 Web 应用程序范围: 注册与 Web 应用程序相关的作用域使得 bean 可以在request、session和application范围内被管理。这些步骤使得 Spring 容器能够更好地支持 Web 应用程序的特定需求为处理 HTTP 请求、会话管理和应用程序范围内的 bean 提供了必要的基础设施。二注册WebApplicationContextServletContextAwareProcessorWebApplicationContextServletContextAwareProcessor类实现了BeanPostProcessor接口用于在 bean 初始化之前和之后进行自定义的处理。public class WebApplicationContextServletContextAwareProcessor implements BeanPostProcessor { private final WebApplicationContext webApplicationContext; public WebApplicationContextServletContextAwareProcessor(WebApplicationContext webApplicationContext) { this.webApplicationContext webApplicationContext; } Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof ServletContextAware) { ((ServletContextAware) bean).setServletContext(this.webApplicationContext.getServletContext()); } return bean; } Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }这个类主要的作用是处理实现了ServletContextAware接口的 bean并将ServletContext注入到这些 bean 中。三忽略ServletContextAware接口的依赖ignoreDependencyInterface方法的作用是告诉BeanFactory在处理自动装配时忽略特定接口的依赖注入。也就是说当BeanFactory遇到实现了该接口的 bean 时不会自动尝试注入该接口的依赖。public interface ServletContextAware { void setServletContext(ServletContext servletContext); }ServletContextAware是一个标记接口用于获取ServletContext对象。实现了该接口的 bean 需要ServletContext这在 Web 应用程序中非常常见。如果不忽略ServletContextAware接口的依赖Spring 容器在创建 bean 时会尝试自动注入ServletContext对象。然而在 Spring 的设计中ServletContext的注入通常是通过BeanPostProcessor来处理的而不是通过自动装配。因此需要忽略该接口的自动依赖注入防止 Spring 容器在自动装配时出错。四注册 Web 应用程序范围private void registerWebApplicationScopes() { ExistingWebApplicationScopes existingScopes new ExistingWebApplicationScopes(this.getBeanFactory()); WebApplicationContextUtils.registerWebApplicationScopes(this.getBeanFactory()); existingScopes.restore(); }Spring 提供了几种标准的 Web 应用程序作用域Request Scope请求作用域每个 HTTP 请求都会创建一个新的 bean 实例该 bean 在请求结束时被销毁。适合存储与单个请求相关的数据如表单数据或请求参数处理器。Session Scope会话作用域每个 HTTP 会话期间创建一个 bean 实例该 bean 在会话结束时被销毁。适合存储需要在用户会话期间保持状态的数据如用户登录信息或购物车内容。Application Scope应用程序作用域整个 Web 应用程序中仅创建一个 bean 实例该 bean 与ServletContext绑定。适合存储全局配置信息或共享的资源如全局缓存或系统配置。ExistingWebApplicationScopes的角色public static class ExistingWebApplicationScopes { private static final SetString SCOPES; private final ConfigurableListableBeanFactory beanFactory; private final MapString, Scope scopes new HashMap(); public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) { this.beanFactory beanFactory; Iterator var2 SCOPES.iterator(); while(var2.hasNext()) { String scopeName (String)var2.next(); Scope scope beanFactory.getRegisteredScope(scopeName); if (scope ! null) { this.scopes.put(scopeName, scope); } } } public void restore() { this.scopes.forEach((key, value) - { if (ServletWebServerApplicationContext.logger.isInfoEnabled()) { ServletWebServerApplicationContext.logger.info(Restoring user defined scope key); } this.beanFactory.registerScope(key, value); }); } static { SetString scopes new LinkedHashSet(); scopes.add(request); scopes.add(session); SCOPES Collections.unmodifiableSet(scopes); } }ExistingWebApplicationScopes类的主要作用在于管理和保护已有的自定义作用域配置。它通过以下方式实现保存当前状态: 在初始化时ExistingWebApplicationScopes会获取当前注册的作用域信息并保存到内部的scopes映射中。这包括了所有已定义的作用域如request和session。恢复状态: 在需要时比如在注册标准 Web 应用程序作用域之后ExistingWebApplicationScopes可以恢复之前保存的作用域配置。这样可以确保注册标准作用域不会覆盖或修改已有的自定义作用域定义。在技术实现上ExistingWebApplicationScopes利用 Spring 框架提供的ConfigurableListableBeanFactory接口来管理作用域信息。它通过迭代已定义的标准作用域集合如request和session并与实际注册的作用域进行匹配来确保作用域配置的一致性和正确性。注册 Web 应用程序作用域WebApplicationContextUtils.registerWebApplicationScopes()方法在 Spring 框架中用于注册与 Web 应用程序相关的标准作用域如request、session和application。public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) { registerWebApplicationScopes(beanFactory, (ServletContext)null); } public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, Nullable ServletContext sc) { beanFactory.registerScope(request, new RequestScope()); beanFactory.registerScope(session, new SessionScope()); if (sc ! null) { ServletContextScope appScope new ServletContextScope(sc); beanFactory.registerScope(application, appScope); sc.setAttribute(ServletContextScope.class.getName(), appScope); } beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory()); beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory()); if (jsfPresent) { WebApplicationContextUtils.FacesDependencyRegistrar.registerFacesDependencies(beanFactory); } }registerWebApplicationScopes()方法的主要任务是确保BeanFactory支持这些标准的 Web 应用程序作用域注册作用域实例: 方法会向BeanFactory中注册相应的作用域实例如RequestScope、SessionScope和ServletContextScope。配置作用域支持: 如果BeanFactory尚未配置支持这些作用域方法可能会进行配置以确保它们能够正确地管理和维护这些作用域。确保作用域生命周期管理: 对于每种作用域Spring 确保在适当的时机创建、销毁和管理 bean 实例。例如在请求结束后销毁请求作用域的 bean 实例以避免内存泄漏和资源浪费。registerWebApplicationScopes()方法的实现会调整BeanFactory以便能够正确地管理和控制这些作用域确保了在多用户、多请求的环境中每个 bean 实例都能按预期的方式进行创建和销毁从而保证了应用程序的稳定性和性能。四、执行包扫描// 执行包扫描自动注册符合条件的组件类 if (this.basePackages ! null this.basePackages.length 0) { this.scanner.scan(this.basePackages); }通过包扫描Spring 可以自动发现项目中符合特定条件的类这些类通常被标注了诸如Component、Service、Controller等注解或者是配置类其避免了手动在配置文件中一一列出每个需要注册的 Bean减少了配置的工作量。根据配置的条件如this.basePackages扫描器可以只扫描特定的包路径而非整个类路径从而精确地控制哪些类需要被注册为 Bean。scanner是一个专门用于扫描指定包路径下类的工具或组件。它能够递归地搜索指定包及其子包中的类文件。一旦扫描器发现符合条件的类Spring 将调用相应的注册方法将这些类注册为 Bean。对于每个扫描到的类Spring 将创建一个对应的 BeanDefinition用于后续的 Bean 实例化和依赖注入。应用场景和实际意义模块化开发通过自动注册不同模块的组件可以自动装配降低了模块间耦合度。动态可扩展性允许开发者通过简单地添加新的组件类如新的Component类来扩展应用的功能而不需要修改现有的配置文件。执行包扫描并自动注册符合条件的组件类是 Spring 框架中支持依赖注入和面向组件的核心功能之一通过简化配置提高开发效率。五、注解类注册// 注册额外的注解配置类 if (!this.annotatedClasses.isEmpty()) { this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); }注册注解类的主要目的是让 Spring 容器能够识别和管理这些类将其纳入到整个应用程序的 Bean 管理体系中。通过这种方式注解类可以享受 Spring 提供的各种功能如依赖注入DI、面向方面编程AOP、生命周期回调等。一扫描和注册注解类的过程步骤在postProcessBeanFactory方法中通过扫描和注册注解类的过程可以分为以下几个步骤扫描注解类首先Spring 会扫描指定包路径下的类找到所有带有特定注解的类。Spring 中的扫描器通常是ClassPathBeanDefinitionScanner它能够递归地扫描指定包路径下的类文件并根据配置的过滤条件如注解决定是否将其注册为 Bean。ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(beanFactory); scanner.scan(basePackages);常见的注解包括ComponentServiceRepositoryController其他自定义注解这些注解用于标识该类是一个 Spring 管理的组件。这部分其实是上一节中讲解的。创建 BeanDefinition对于每一个扫描到的注解类Spring 会创建一个BeanDefinition对象。BeanDefinition描述了 Bean 的各种属性和元数据如 Bean 的类名、作用域、初始化和销毁方法等。扫描器在找到符合条件的类后会调用AnnotatedBeanDefinitionReader或类似的类来创建BeanDefinitionAnnotatedBeanDefinitionReader reader new AnnotatedBeanDefinitionReader(beanFactory); reader.register(annotatedClasses.toArray(new Class[0]));注册 BeanDefinition创建好BeanDefinition之后Spring 会将其注册到BeanFactory中。这一步骤通常由BeanDefinitionRegistry接口的registerBeanDefinition方法来完成。BeanDefinitionRegistry接口提供了registerBeanDefinition方法用于将创建好的BeanDefinition注册到BeanFactory中beanFactory.registerBeanDefinition(beanName, beanDefinition);postProcessBeanFactory方法通过注册注解类使这些类能够参与到 Spring 的依赖注入和生命周期管理中。这一过程包括扫描指定包路径、创建并注册BeanDefinition等步骤通过自动化的组件发现和注册机制Spring 极大地简化了应用程序的配置和管理工作。二对注解类注册的理解新思路注解类的注册不仅仅是简单的扫描和注册其实可以通过扩展和优化比如可以在这里增加protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); // 执行包扫描自动注册符合条件的组件类 if (this.basePackages ! null this.basePackages.length 0) { this.scanner.scan(this.basePackages); } // 动态注册额外的注解配置类 if (!this.annotatedClasses.isEmpty()) { for (Class? annotatedClass : this.annotatedClasses) { if (shouldRegister(annotatedClass)) { this.reader.register(annotatedClass); } } } } // 判断是否注册某个注解类的逻辑 private boolean shouldRegister(Class? annotatedClass) { // 根据某些条件决定是否注册 // 例如检查注解类上是否有特定注解或者根据配置文件中的设置 return true; }新的思路支持更多注解类型除了常见的 Spring 注解还可以支持更多的自定义注解或第三方注解。这可以通过扩展AnnotatedBeanDefinitionReader来实现增加对其他注解类型的解析和处理。动态注解类注册在应用运行过程中根据某些条件动态决定是否注册某些注解类。比如可以通过配置文件或者数据库表来决定需要注册哪些类从而实现更加灵活的 Bean 管理。注解类的优先级管理对于不同的注解类可以设置不同的优先级。在注册时根据优先级决定注册顺序从而控制 Bean 的初始化顺序。这在一些复杂应用中非常有用可以避免由于 Bean 初始化顺序引起的问题。条件性注解注册可以根据当前的环境或者配置条件决定是否注册某些注解类。例如只有在特定的 Profile如开发环境或生产环境下才注册某些类从而实现环境隔离和配置灵活性。六、总结在 Spring IOC 容器中postProcessBeanFactory方法作为一个关键的扩展点允许子类在 BeanFactory 初始化后、Bean 实例化前进行进一步自定义处理。通过对AnnotationConfigServletWebServerApplicationContext类的分析我们理解了该方法的主要功能和实现包括调用父类方法以继承基础设置和逻辑、执行包扫描、自动注册符合条件的组件类以及注解类注册等关键步骤。包扫描和注解类注册是postProcessBeanFactory的核心功能能够自动发现并注册带有特定注解的类这不仅简化了配置还增强了应用的模块化和动态可扩展性。通过扩展和优化如支持更多注解类型、动态注解类注册、注解类优先级管理和条件性注解注册可以进一步提升 Spring 框架的灵活性和功能性适应复杂应用的需求。这些机制确保了 Spring 容器能够更好地支持 Web 应用程序的特定需求提供必要的基础设施从而保证了应用程序的稳定性和性能。在实际开发中通过合理运用这些功能可以大大简化配置、提高开发效率并增强应用的可维护性和扩展性。