常见问题 网站建设,app软件怎么开发,台州seo公司,做编辑器的网站在 Java 技术栈的面试中#xff0c;Spring 几乎是必问的模块#xff0c;而 Bean 的加载过程 更是 Spring IoC 容器最核心、最复杂的环节。很多开发者能背出 BeanFactoryPostProcessor、BeanPostProcessor 等接口#xff0c;却难以将其串联成一个完整的流程。本文将彻底剖析这…在 Java 技术栈的面试中Spring 几乎是必问的模块而Bean 的加载过程更是 Spring IoC 容器最核心、最复杂的环节。很多开发者能背出BeanFactoryPostProcessor、BeanPostProcessor等接口却难以将其串联成一个完整的流程。本文将彻底剖析这一过程从AbstractApplicationContext#refresh()入口开始深入源码梳理出 Bean 加载的十二个关键阶段并附带清晰的代码示例和设计思想解读。1. 引言IoC 容器与 BeanSpring IoC 容器如ApplicationContext负责管理应用中对象的生命周期这些被管理的对象称为Bean。容器启动后需要完成以下核心任务加载读取配置元数据XML、注解、Java Config。解析将配置信息转换为BeanDefinition对象。注册将BeanDefinition存入容器缓存。实例化 初始化按需或立即创建 Bean 实例并完成依赖注入、初始化回调。就绪将完整 Bean 放入容器供其他组件使用。本文将围绕AnnotationConfigApplicationContext基于注解的容器的启动流程逐层剥开 Bean 加载的全貌。2. 宏观流程从refresh()开始所有 Spring 容器的启动逻辑都汇聚于AbstractApplicationContext.refresh()方法。该方法定义了 IoC 容器初始化的模板javaOverride public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. 准备工作记录容器状态、验证必要属性等 prepareRefresh(); // 2. 获取 BeanFactory通常为 DefaultListableBeanFactory ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory(); // 3. 准备 BeanFactory配置类加载器、注册默认环境 Bean、后置处理器等 prepareBeanFactory(beanFactory); try { // 4. 允许子类对 BeanFactory 进行后置处理如 Servlet 相关特性 postProcessBeanFactory(beanFactory); // 5. 调用 BeanFactoryPostProcessor包括 BeanDefinitionRegistryPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // 6. 注册 BeanPostProcessor拦截 Bean 的实例化/初始化 registerBeanPostProcessors(beanFactory); // 7. 初始化国际化资源MessageSource initMessageSource(); // 8. 初始化事件广播器ApplicationEventMulticaster initApplicationEventMulticaster(); // 9. 留给子类初始化其他特殊 Bean如 SpringBoot 的嵌入式容器 onRefresh(); // 10. 注册事件监听器 registerListeners(); // 11. 实例化所有非懒加载的单例 Bean finishBeanFactoryInitialization(beanFactory); // 12. 完成刷新发布相应的事件 finishRefresh(); } catch (BeansException ex) { // 异常处理销毁已创建的 Bean destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }其中步骤 2~6 主要涉及 BeanDefinition 的加载与后处理而步骤 11 是真正创建 Bean 实例的关键环节。我们按逻辑将其拆解为两大阶段Bean 定义的加载与注册对应步骤 2,5Bean 的实例化与初始化对应步骤 113. Bean 定义的加载与注册3.1obtainFreshBeanFactory()获取/创建 BeanFactory该方法会调用子类的refreshBeanFactory()来创建或刷新底层的BeanFactory。对于AnnotationConfigApplicationContext其内部持有一个DefaultListableBeanFactory并调用loadBeanDefinitions加载配置。关键点DefaultListableBeanFactory是 Spring 最强大的 BeanFactory 实现它维护了beanDefinitionMapConcurrentHashMap和beanDefinitionNamesList等核心数据结构。loadBeanDefinitions通过BeanDefinitionReader读取配置如AnnotatedBeanDefinitionReader处理带注解的类ClassPathBeanDefinitionScanner扫描指定包。3.2BeanDefinition的解析与注册以注解方式为例注册一个配置类如Configuration标注的类时AnnotatedBeanDefinitionReader会做两件事为配置类本身生成ScannedGenericBeanDefinition。注册内部 Bean 后置处理器如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等。扫描指定包时ClassPathBeanDefinitionScanner会遍历类文件筛选出带有Component、Service等注解的类生成BeanDefinition并注册。注册的本质将BeanDefinition放入DefaultListableBeanFactory#beanDefinitionMap同时将 beanName 存入beanDefinitionNames。3.3BeanFactoryPostProcessor的执行步骤 5invokeBeanFactoryPostProcessors(beanFactory)是 Bean 定义加载后最重要的扩展点。它负责调用所有已注册的BeanFactoryPostProcessor允许开发者修改尚未实例化的 Bean 定义。其中BeanDefinitionRegistryPostProcessor是其子接口允许在常规后处理器之前对注册表进行操作。典型的实现有ConfigurationClassPostProcessor处理Configuration类解析其中的Bean方法、ComponentScan、Import等生成更多的BeanDefinition。PropertySourcesPlaceholderConfigurer解析Value中的${...}占位符替换为配置文件中的值。这一阶段完成后所有的 BeanDefinition 都已准备就绪但 Bean 实例尚未创建。4. Bean 的实例化与初始化finishBeanFactoryInitialization步骤 11finishBeanFactoryInitialization(beanFactory)是 Bean 创建的真正入口。它实例化所有非懒加载的单例 Bean除容器内部 Bean 外。方法内部主要调用了DefaultListableBeanFactory#preInstantiateSingletonsjavaOverride public void preInstantiateSingletons() throws BeansException { // 获取所有 beanName 的副本防止并发修改 ListString beanNames new ArrayList(this.beanDefinitionNames); // 依次实例化所有非懒加载单例 Bean for (String beanName : beanNames) { RootBeanDefinition bd getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() bd.isSingleton() !bd.isLazyInit()) { // 处理 FactoryBean 的特殊逻辑以 开头 if (isFactoryBean(beanName)) { Object bean getBean(FACTORY_BEAN_PREFIX beanName); FactoryBean? factory (FactoryBean?) bean; // 如果 FactoryBean 也想被立即初始化非懒加载单例 if (factory.isEagerInit()) { getBean(beanName); } } else { getBean(beanName); } } } // 对所有已创建的单例 Bean 触发 SmartInitializingSingleton#afterSingletonsInstantiated for (String beanName : beanNames) { Object singletonInstance getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { ((SmartInitializingSingleton) singletonInstance).afterSingletonsInstantiated(); } } }核心是getBean(String name)它最终会调用doGetBean该方法内部包含创建 Bean 的完整流程。下面我们详细拆解doGetBean中创建单例 Bean 的逻辑以createBean为核心。5. 深入doGetBeanBean 创建的完整生命周期doGetBean的代码很长我们只聚焦于创建新实例的分支java// 从缓存中获取单例解决循环依赖的关键 Object sharedInstance getSingleton(beanName); if (sharedInstance ! null args null) { // 返回实例如果是 FactoryBean 则返回其产品 bean getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 标记当前 Bean 正在创建用于检测循环依赖 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 获取父 BeanFactory 处理略 // 将当前 Bean 标记为正在创建 beforeSingletonCreation(beanName); try { // 实际创建单例 singletonObject singletonFactory.getObject(); } finally { afterSingletonCreation(beanName); } // 将创建好的单例加入缓存 addSingleton(beanName, singletonObject); }真正的创建逻辑在singletonFactory.getObject()中它由createBean方法提供javaOverride protected Object createBean(String beanName, RootBeanDefinition mbd, Nullable Object[] args) { // 解析 Bean 的 Class 对象 Class? resolvedClass resolveBeanClass(mbd, beanName); // 处理 lookup-method 和 replace-method 等覆盖MethodOverrides mbd.prepareMethodOverrides(); // 让 BeanPostProcessor 有机会返回代理对象如 AOP Object bean resolveBeforeInstantiation(beanName, mbd); if (bean ! null) { return bean; // 若前置处理器返回了代理则跳过后续实例化 } // 实际创建 Bean 实例 Object beanInstance doCreateBean(beanName, mbd, args); return beanInstance; }这里出现了第一个关键拦截点resolveBeforeInstantiation对应InstantiationAwareBeanPostProcessor的前置方法。我们将其融入下面的阶段详解。6. 十二个关键阶段详解为了便于记忆我们将 Bean 加载过程归纳为十二个阶段并分别说明每个阶段的触发时机、涉及的关键接口/方法以及典型应用场景。阶段 1Bean 定义的解析与注册触发点refresh()→obtainFreshBeanFactory()→loadBeanDefinitions操作将配置元数据转化为BeanDefinition并注册到容器。参与接口BeanDefinitionReader、ClassPathBeanDefinitionScanner、BeanDefinitionRegistryPostProcessor后处理定义。扩展应用自定义标签/注解解析、动态注册 Bean。阶段 2实例化前置处理触发点createBean→resolveBeforeInstantiation操作调用所有InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法若返回非空对象则直接作为 Bean 实例跳过后续实例化步骤。典型应用AOP 生成代理对象AbstractAutoProxyCreator在此处返回代理。注意此处返回的 Bean 仍会经过后续的BeanPostProcessor处理初始化前后。阶段 3实例化 Bean触发点doCreateBean→createBeanInstance操作通过反射或工厂方法创建 Bean 实例。流程包括推断构造方法优先使用Autowired标注的构造器。若配置了Supplier则调用get()获得实例。否则使用合适的构造器反射实例化。涉及对象SmartInstantiationAwareBeanPostProcessor用于推断构造器。典型问题多构造器时如何选择Spring 会按优先级Autowired构造器 参数最多的构造器 默认无参构造器。阶段 4实例化后置处理触发点doCreateBean→populateBean之前 →InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation操作如果该方法返回false则跳过后续的属性填充populateBean。通常很少使用用于完全自定义属性注入。典型应用当 Bean 需要自己管理属性注入时可通过此方法拦截。阶段 5属性填充前的后置处理处理自动注入模型触发点populateBean内部遍历InstantiationAwareBeanPostProcessor的postProcessProperties或已废弃的postProcessPropertyValues。操作处理Autowired、Resource、Value等注解解析依赖并注入。核心实现AutowiredAnnotationBeanPostProcessor扫描字段/方法上的注解通过DefaultListableBeanFactory#resolveDependency解析依赖按类型、名称等。循环依赖处理此处若发现尚未创建的依赖会触发依赖 Bean 的创建通过getBean从而可能引发循环依赖问题。Spring 通过三级缓存解决。阶段 6属性填充依赖注入操作将解析好的属性值设置到 Bean 实例中反射调用 setter 或直接字段赋值。这一步由 BeanWrapper 完成。阶段 7Aware 接口回调触发点initializeBean→invokeAwareMethods操作若 Bean 实现了特定的 Aware 接口则调用相应方法BeanNameAware传入 beanNameBeanClassLoaderAware传入 ClassLoaderBeanFactoryAware传入 BeanFactory注意此时 Bean 还未完全初始化可能造成提前使用风险注意ApplicationContextAware等由ApplicationContextAwareProcessor处理属于BeanPostProcessor在下一阶段执行。阶段 8初始化前置处理触发点initializeBean→applyBeanPostProcessorsBeforeInitialization操作依次调用所有BeanPostProcessor的postProcessBeforeInitialization方法。典型应用ApplicationContextAwareProcessor注入ApplicationContext。InitDestroyAnnotationBeanPostProcessor执行PostConstruct标记的方法实际上PostConstruct在postProcessBeforeInitialization中被调用不对稍后解释。实际上PostConstruct是通过CommonAnnotationBeanPostProcessor在postProcessBeforeInitialization中调用的因为PostConstruct是 JSR-250 规范由该后置处理器处理。注意部分资料将PostConstruct归为初始化阶段但源码中它在postProcessBeforeInitialization执行早于InitializingBean。阶段 9初始化 Bean触发点invokeInitMethods操作如果 Bean 实现了InitializingBean调用afterPropertiesSet()。如果配置了自定义的init-method或Bean(initMethod ...)通过反射调用。典型用途执行自定义初始化逻辑如资源打开、连接建立等。阶段 10初始化后置处理触发点applyBeanPostProcessorsAfterInitialization操作调用所有BeanPostProcessor的postProcessAfterInitialization方法。此时 Bean 已经完成初始化即将返回给容器。典型应用AOP 在此处生成代理AbstractAutoProxyCreator的postProcessAfterInitialization创建代理。注意与阶段 2 区分阶段 2 是在实例化前返回代理而阶段 10 是在正常初始化后包装代理。前者用于提前代理如Configuration类后者用于常规 Bean 的 AOP。事件发布、监控等。阶段 11注册销毁回调触发点registerDisposableBeanIfNecessary操作如果 Bean 需要销毁如实现了DisposableBean、有PreDestroy方法、指定了destroy-method将其包装为DisposableBeanAdapter并注册到disposableBeans集合中等待容器关闭时回调。阶段 12完成并放入单例缓存操作将创建好的单例 Bean 放入DefaultSingletonBeanRegistry的一级缓存singletonObjects中并从二级/三级缓存中移除。至此Bean 完全就绪可供应用使用。7. 循环依赖与三级缓存上述阶段中属性填充阶段 6涉及依赖注入可能触发其他 Bean 的创建从而产生循环依赖。Spring 通过三级缓存解决大部分单例 setter 注入的循环依赖一级缓存singletonObjects完全初始化好的单例 Bean。二级缓存earlySingletonObjects提前曝光的单例 Bean实例化但未完成初始化即半成品。三级缓存singletonFactories存放ObjectFactory用于生成提前曝光的 Bean通常是getEarlyBeanReference用于处理 AOP 代理。工作流程以 A 依赖 BB 依赖 A 为例A 开始创建实例化 A阶段 3此时 A 为原始对象。将 A 的ObjectFactory放入三级缓存。填充 A 时发现依赖 B于是去创建 B。B 实例化后填充 B 时发现依赖 A此时从三级缓存拿到 A 的ObjectFactory调用getObject()获得 A 的早期引用可能是代理放入二级缓存并删除三级缓存。B 注入 A 的早期引用完成初始化放入一级缓存。回到 A注入已经完成初始化的 B完成 A 的初始化放入一级缓存。注意构造器注入无法解决循环依赖因为构造器在实例化阶段阶段 3就需要依赖此时还未放入三级缓存所以会报错。8. 扩展点总结与对比为了便于面试回答我们整理出两大扩展点家族8.1BeanFactoryPostProcessor系列作用于 BeanDefinition 阶段BeanDefinitionRegistryPostProcessor在常规BeanFactoryPostProcessor之前执行可动态注册新的 BeanDefinition。BeanFactoryPostProcessor处理 BeanDefinition 的属性如占位符替换PropertySourcesPlaceholderConfigurer。8.2BeanPostProcessor系列作用于 Bean 实例化/初始化阶段InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation实例化前阶段 2postProcessAfterInstantiation实例化后阶段 4postProcessProperties属性注入前阶段 5BeanPostProcessorpostProcessBeforeInitialization初始化前阶段 8postProcessAfterInitialization初始化后阶段 10DestructionAwareBeanPostProcessor销毁前回调。8.3 Aware 接口感知容器对象按调用顺序BeanNameAware、BeanClassLoaderAware、BeanFactoryAware阶段 7ApplicationContextAware、ResourceLoaderAware、EnvironmentAware等由ApplicationContextAwareProcessor在阶段 8 中调用8.4 初始化/销毁接口初始化PostConstruct→InitializingBean#afterPropertiesSet→init-method销毁PreDestroy→DisposableBean#destroy→destroy-method9. 源码追踪实战一个简单 Bean 的加载足迹假设我们有以下配置类javaConfiguration ComponentScan(com.example) public class AppConfig { }以及一个普通 ServicejavaService public class UserService { Autowired private OrderService orderService; PostConstruct public void init() { System.out.println(init...); } }启动容器new AnnotationConfigApplicationContext(AppConfig.class);足迹追踪refresh()→obtainFreshBeanFactory()→ 创建DefaultListableBeanFactory。invokeBeanFactoryPostProcessors→ConfigurationClassPostProcessor处理AppConfig扫描com.example生成UserService的ScannedGenericBeanDefinition。registerBeanPostProcessors→ 注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等。finishBeanFactoryInitialization→ 遍历 beanNames开始创建userService。getBean(userService)→doGetBean→createBean。resolveBeforeInstantiation遍历InstantiationAwareBeanPostProcessor此处无特殊代理返回 null。doCreateBeancreateBeanInstance通过无参构造器反射创建UserService实例。将UserService原始对象的ObjectFactory放入三级缓存。populateBean调用AutowiredAnnotationBeanPostProcessor#postProcessProperties解析orderService字段触发getBean(orderService)创建OrderService省略过程。解析到依赖后通过反射将orderService注入。initializeBeaninvokeAwareMethods无对应 Aware 接口。applyBeanPostProcessorsBeforeInitializationCommonAnnotationBeanPostProcessor调用PostConstruct方法init()。invokeInitMethods无InitializingBean和无自定义 init-method。applyBeanPostProcessorsAfterInitialization无特殊后置处理。registerDisposableBeanIfNecessary若需销毁则注册。将userService加入一级缓存singletonObjects。所有单例创建完成后触发SmartInitializingSingleton#afterSingletonsInstantiated如有。至此UserService加载完成。10. 常见面试题精选10.1 Spring 如何解决循环依赖答通过三级缓存。第一级存放完整 Bean第二级存放早期暴露的 Bean半成品第三级存放ObjectFactory用于生成早期 Bean 的代理。仅支持单例、非构造器注入的循环依赖。10.2Autowired与Resource的区别答Autowired是 Spring 注解默认按类型装配可通过Qualifier指定名称Resource是 JSR-250 注解默认按名称装配名称可通过name属性指定找不到再按类型。10.3BeanPostProcessor与BeanFactoryPostProcessor的区别答前者作用于 Bean 实例化阶段可对 Bean 实例进行加工后者作用于 Bean 定义阶段可修改 Bean 定义元数据。10.4PostConstruct在哪个阶段执行答在BeanPostProcessor#postProcessBeforeInitialization阶段执行早于InitializingBean#afterPropertiesSet。10.5 FactoryBean 与 BeanFactory 的区别答BeanFactory是容器负责创建和管理 BeanFactoryBean是一个特殊的 Bean用于生产其他 Bean 实例如SqlSessionFactoryBean。从容器中获取时加前缀返回FactoryBean本身不加则返回其产品。11. 总结本文从refresh()方法出发详细剖析了 Bean 加载的完整流程涵盖了定义注册、实例化、属性填充、初始化、销毁注册等十二个阶段并深入讲解了循环依赖的解决机制及核心扩展点。希望通过这篇文章读者能建立起对 Spring IoC 容器的整体认知能够从容应对面试中的 Bean 加载相关问题。