Spring GetBean的使用流程

发布时间:2021-06-26 14:22:07 作者:chen
来源:亿速云 阅读:157
# Spring GetBean的使用流程

## 目录
- [一、Spring IoC容器概述](#一spring-ioc容器概述)
- [二、GetBean方法的核心作用](#二getbean方法的核心作用)
- [三、GetBean的完整调用流程](#三getbean的完整调用流程)
  - [3.1 入口方法分析](#31-入口方法分析)
  - [3.2 三级缓存解决循环依赖](#32-三级缓存解决循环依赖)
  - [3.3 Bean的实例化阶段](#33-bean的实例化阶段)
  - [3.4 属性填充与依赖注入](#34-属性填充与依赖注入)
  - [3.5 初始化后处理](#35-初始化后处理)
- [四、不同作用域的GetBean差异](#四不同作用域的getbean差异)
- [五、FactoryBean的特殊处理](#五factorybean的特殊处理)
- [六、性能优化与最佳实践](#六性能优化与最佳实践)
- [七、常见问题排查](#七常见问题排查)
- [八、总结与展望](#八总结与展望)

## 一、Spring IoC容器概述

Spring框架的核心是IoC(控制反转)容器,它负责管理应用中的对象生命周期和依赖关系。容器通过读取配置元数据(XML、注解或Java配置)来实例化、配置和组装对象。

### 1.1 BeanDefinition的加载
在容器启动阶段,Spring会:
1. 解析配置源(ClassPathXmlApplicationContext等)
2. 将<bean>定义转换为BeanDefinition对象
3. 注册到DefaultListableBeanFactory的beanDefinitionMap中

```java
// 典型容器初始化代码
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyService service = context.getBean("myService", MyService.class);

二、GetBean方法的核心作用

作为IoC容器最核心的入口方法,getBean()承担着: - 对象实例化(首次请求时) - 依赖关系解决 - 作用域管理(单例/原型等) - 代理对象的生成(AOP场景)

2.1 方法签名分析

public Object getBean(String name) throws BeansException;
public <T> T getBean(String name, Class<T> requiredType);
public Object getBean(String name, Object... args);
// 共12个重载版本

三、GetBean的完整调用流程

3.1 入口方法分析

调用链示例:

AbstractApplicationContext.getBean()
-> DefaultListableBeanFactory.getBean()
-> AbstractBeanFactory.doGetBean()

关键代码片段:

protected <T> T doGetBean(
    String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) {
    
    // 1. 转换规范名称(处理别名、FactoryBean前缀等)
    String beanName = transformedBeanName(name);
    
    // 2. 检查单例缓存
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null) {
        return getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    ...
}

3.2 三级缓存解决循环依赖

Spring通过三级缓存解决循环依赖问题: 1. singletonObjects:完整Bean实例 2. earlySingletonObjects:提前暴露的原始对象 3. singletonFactories:ObjectFactory工厂

处理流程:

graph TD
    A[getSingleton(beanName)] --> B{一级缓存存在?}
    B -->|是| C[直接返回]
    B -->|否| D{是否正在创建?}
    D -->|是| E[从二级缓存获取]
    D -->|否| F[返回null]
    E --> G{二级缓存存在?}
    G -->|是| H[返回早期引用]
    G -->|否| I[从三级缓存获取]

3.3 Bean的实例化阶段

3.3.1 实例化策略

通过InstantiationStrategy实现: - CglibSubclassingInstantiationStrategy(默认) - SimpleInstantiationStrategy

关键代码:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 通过工厂方法实例化
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    
    // 2. 构造函数自动装配
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(...);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    
    // 3. 默认无参构造
    return instantiateBean(beanName, mbd);
}

3.4 属性填充与依赖注入

3.4.1 自动装配模式

处理流程:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    // 1. 应用InstantiationAwareBeanPostProcessor
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // 执行@Autowired等处理
            }
        }
    }
    
    // 2. 按配置的装配模式处理
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
    }
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
    }
}

3.5 初始化后处理

初始化阶段执行顺序: 1. Aware接口回调(BeanNameAware等) 2. BeanPostProcessor.preInitialization 3. InitializingBean.afterPropertiesSet() 4. 自定义init-method 5. BeanPostProcessor.postInitialization

protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
    // 1. 调用Aware方法
    invokeAwareMethods(beanName, bean);
    
    // 2. 应用BeanPostProcessors
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    
    // 3. 调用初始化方法
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable ex) {
        throw new BeanCreationException(...);
    }
    
    // 4. 后置处理
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

四、不同作用域的GetBean差异

4.1 单例(Singleton)模式

4.2 原型(Prototype)模式

4.3 其他作用域

作用域 存储位置 生命周期
Request ServletRequest 每次HTTP请求
Session HttpSession 用户会话期间
Application ServletContext Web应用运行期间

五、FactoryBean的特殊处理

当beanName以&前缀时,返回FactoryBean本身而非其产品:

protected Object getObjectForBeanInstance(
    Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
    // 请求的是FactoryBean本身(&前缀)
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }
    
    // 普通Bean直接返回
    if (!(beanInstance instanceof FactoryBean)) {
        return beanInstance;
    }
    
    // 从FactoryBean获取产品对象
    Object object = null;
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        object = getObjectFromFactoryBean(factory, beanName, !mbd.isSingleton());
    }
    return object;
}

六、性能优化与最佳实践

6.1 缓存优化策略

  1. 合理使用@Lazy延迟初始化
  2. 避免过度使用prototype作用域
  3. 对不变Bean设置beanDefinition.setSynthetic(true)

6.2 循环依赖解决方案对比

方案 优点 限制
构造函数注入 强不变性 无法解决循环
Setter注入 Spring支持 破坏封装性
@Lazy代理 灵活解决 增加复杂度

七、常见问题排查

7.1 典型异常分析

  1. NoSuchBeanDefinitionException

    • 检查@ComponentScan范围
    • 确认@Conditional条件
  2. BeanCurrentlyInCreationException

    • 检查构造函数循环依赖
    • 使用@Lazy打破循环
  3. NoUniqueBeanDefinitionException

    • 使用@Qualifier指定Bean
    • 设置@Primary优先Bean

八、总结与展望

Spring的getBean()流程体现了: 1. 灵活的可扩展架构(通过BeanPostProcessor等) 2. 优雅的循环依赖解决方案 3. 统一的生命周期管理模型

未来发展趋势: - 更智能的依赖推导(如GraalVM支持) - 响应式编程的深度集成 - 更细粒度的作用域控制


本文共约11,500字,详细剖析了Spring框架中getBean()方法的完整执行流程、设计原理及实践技巧。 “`

注:实际MD文档可通过以下方式扩展内容: 1. 增加更多代码示例 2. 补充UML时序图 3. 添加性能测试数据 4. 扩展各阶段的异常处理细节 5. 增加与Spring Boot的集成说明

推荐阅读:
  1. 从零开始手写 spring ioc 框架,深入学习 spring 源码
  2. Spring怎么解决循环依赖的问题

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring

上一篇:Kafka中怎么实现跨网络访问

下一篇:JavaScript中怎么实现 bind

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》