Spring IOC核心原理详解与运用实战教程

2025-11-26 19:50

本文主要是介绍Spring IOC核心原理详解与运用实战教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《SpringIOC核心原理详解与运用实战教程》本文详细解析了SpringIOC容器的核心原理,包括BeanFactory体系、依赖注入机制、循环依赖解决和三级缓存机制,同时,介绍了SpringBo...

1. Spring IOC核心原理深度解析

1.1 BeanFactory体系与内部结构

Spring IOC容器的根基是BeanFactory接口,它定义了容器的基本行为规范,是所有Spring容器实现的最小化契约。作为Spring框架的基础设施,BeanFactory不仅负责Bean的创建与管理,还提供了类型判断、依赖注入等核心功能。与通常理解不同,BeanFactory本身并不直接涉及Bean的加载方式,而是聚焦于定义IOC容器的基本行为模式。

1.1.1 核心接口层级体系

BeanFactory的设计体现了接口隔离原则(ISP),通过分层接口逐步扩展功能:

  • BeanFactory :最基础接口,提供getBean()、containsBean()等核心方法
  • HierarchicalBeanFactory :支持父子容器分层结构,实现Bean的层级查找
  • ListableBeanFactory :支持枚举所有Bean实例,提供类型扫描能力
  • AutowireCapableBeanFactory :扩展自动装配能力,支持resolveDependency等依赖解析方法
  • ConfigurableBeanFactory :提供配置能力,允许注册作用域、类型转换器等
  • ConfigurableListableBeanFactory :集合所有可配置与可枚举特性,是完整的容器契约

1.1.2 关键实现类分析

DefaultListableBeanFactory是Spring注册及加载Bean的核心实现类,整合了所有接口功能。其内部维护多个关键数据结构:

// 核心数据结构示意
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory 
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
    // Bean定义注册表:存储所有BeanDefinition
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 单例Bean缓存:一级缓存singletonObjects
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    // 三级缓存结构(解决循环依赖)
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
    private final Map<String, Object> earlySingletonObjects = new HashMap<>();
}

AbstractAutowireCapableBeanFactory作为创建、自动装配、初始化和销毁Bean的核心抽象类,提供了完整的Bean生命周期模板方法。其createBean方法是整个Bean创建流程的入口:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 解析Bean类型
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    // 2. 准备方法覆盖(处理@Lookup等)
    mbd.prepareMethodOverrides();
    // 3. 实例化前的BeanPostProcessor处理
    Object bean = resolveBeforeInstantiation(beanName, mbd);
    if (bean != null) return bean;
    // 4. 执行实际创建
    Object beanInstance = doCreateBean(beanName, mbd, args);
    return beanInstance;
}

DefaultSingletonBeanRegistry负责单例Bean的注册与管理,维护三级缓存机制。其getSingleton方法是解决循环依赖的关键:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    // 一级缓存查询
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null) {
        // 二级缓存查询
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null) {
            // 三级缓存获取工厂并创建
            ObjectFactory<?> factory = this.singletonFactories.get(beanName);
            if (factory != null) {
                singletonObject = factory.getObject();
                this.earlySingletonObjects.put(beanName, singletonObject);
                this.singletonFactories.remove(beanName);
            }
        }
    }
    return singletonObject;
}

1.2 依赖注入机制详解

依赖注入(DI)是IOC的具体实现,Spring通过反射机制将对象的创建和依赖管理交给容器完成。现代Spring应用主要采用注解驱动注入,其核心处理器是AutowiredAnnotationBeanPostProcessor。

1.2.1 注入方式演进

  • 构造器注入:Spring官方推荐方式,强制依赖完整性,支持不可变对象
  • Setter注入:传统方式,提供灵活性但破坏封装性
  • 字段注入:使用@Autowired直接标注字段,简洁但难以测试

1.2.2 @Autowired处理核心流程

AutowiredAnnotationBeanPostProcessor(简称AOP)实现了BeanPostProcessor和MergedBeanDefinitionPostProcessor接口,其处理流程分为三个阶段:

阶段一:元数据提取与缓存
在Bean定义合并阶段,postProcessMergedBeanDefinition方法扫描类中的@Autowired、@Value、@Inject注解,构建InjectionMetadata对象。为提高性能,Spring使用injectionMetadataCache缓存已解析的元数据,避免重复反射扫描。

private final Map<Class<?>, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>();
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
    // 从缓存获取
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    // 检查是否需要刷新
    if (InjectionMetadata.needsRefresh(metadjavascriptata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            metadata = buildAutowiringMetadata(clazz); // 反射解析
            this.injectionMetadataCache.put(cacheKey, metadata);
        }
    }
    return metadata;
}

阶段二:依赖解析
在属性填充阶段,resolveDependency方法通过DefaultListableBeanFactory的依赖解析器定位目标Bean。解析策略包括:

  • 按类型匹配:首选策略,利用ResolvableType进行泛型精确匹配
  • 按名称匹配:当存在多个同类型Bean时,结合@Qualifier注解
  • @Value解析:通过EmbeddedValueResolver处理SpEL表达式和占位符

阶段三:实际注入
postProcessProperties方法调用InjectionMetadata.inject()完成最终注入。对于字段注入,使用反射的Field.set()方法;对于方法注入,使用Method.invoke()。

1.3 循环依赖与三级缓存机制

Spring通过三级缓存机制解决单例Bean的循环依赖问题。

1.3.1 三级缓存结构

// DefaultSingletonBeanRegistry中的三级缓存
public class DefaultSingletonBeanRegistry {
    // 一级缓存:完全初始化完成的单例Bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // 二级缓存:早期曝光的单例Bean(已实例化但尚未初始化)
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    // 三级缓存:单例Bean工厂,用于生成早期Bean引用
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}

1.3.2 循环依赖解决流程

假设场景:A依赖B,B依赖A

  1. 创建A实例:doCreateBean调用createBeanInstance实例化A,此时A未填充属性
  2. 暴露早期引用:将A的ObjectFactory放入三级缓存`singletonFactories
  3. 填充A的属性:populateBean发现需要B,触发getBean(B)
  4. 创建B实例:同样流程实例化B,并将其工厂放入三级缓存
  5. 填充B的属性:B需要A,调用getBean(A)
  6. 从缓存获取A:此时A不在一级缓存,但三级缓存存在其工厂,调用getObject()返回A的早期引用(未完全初始化),并将A移至二级缓存
  7. 完成B初始化:B获得A的早期引用后完成属性填充和初始化,将B放入一级缓存
  8. 完成A初始化:B创建完成后,A继续填充属性,最终完成初始化并放入一级缓存

重要限制:此机制仅支持单例Bean的属性注入循环依赖,构造器注入的循环依赖无法解决,因为实例化阶段就需要依赖对象,无法提前暴露工厂。

2. Spring Boot中的IOC实践与应用

2.1 Spring Boot自动配置与IOC的协同

Spring Boot的自动配置机制是其核心特性,建立在Spring IOC容器之上,通过条件注解实现智能装配。

2.1.1 @Conditional体系与条件评估

@Conditional是Spring 4.0引入的基础设施,通过Condition接口实现条件化装配。Spring Boot扩展了多个派生注解:

@ConditionalOnClass      // 类路径存在指定类
@ConditionalOnMissingBean // 容器中不存在指定Bean
@ConditionalOnProperty   // 配置属性满足条件
@ConditionalOnWebApplication // 当前是Web应用

内部工作原理:
AutoConfigurationImportSelector负责加载META-INF/spring.factories中定义的自动配置类。在filter方法中,调用ConditionEvaLuator对每个配置类上的条件注解进行评估:

// AutoConfigurationImportSelector核心逻辑
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    return configurations;
}
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
    // 遍历每个配置类
    for (String configuration : configurations) {
        // 获取其上的@Conditional注解
        // 调用ConditionEvaluator评估
        if (conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
            continue; // 不满足条件则跳过
        }
        result.add(configuration);
    }
    return result;
}

ConditionEvaluator通过ConditionContext获取容器上下文、环境变量、类加载器等信息,调用Condition.matches()方法进行最终决策。

2.1.2 @ConditionalOnMissingBean实践示例

在Starter开发中,@ConditionalOnMissingBean允许用户轻松覆盖默认配置:

@Configuration
public class MyAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(MyService.class)
    public MyService defaultMyService() {
        return new DefaultMyServiceImpl();
    }
}
// 用户自定义Bean将覆盖默认实现
@Component
public class CustomMyService implements MyService {
    // 自定义实现
}

2.2 Bean作用域与生命周期管理

Spring Boot简化了作用域配置,通过@Scope注解灵活控制Bean生命周期。

2.2.1 内置作用域详解

  • singleton :默认作用域,IOC容器中仅一个实例
  • prototype :每次请求创建新实例,适合有状态Bean
  • request :HTTP请求级别,Web应用中每个请求一个实例
  • session :HTTP会话级别,每个用户会话一个实例
  • application :ServletContext级别,整个应用共享
  • websocket :WebSocket会话级别

2.2.2 自定义作用域实现步骤

实现线程局部作用域的完整示例:

实现Scope接口:

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class ThreadLocalScope implements Scope {
    private final ThreadLocal<Map<String, Object>> threadLocal = 
        ThreadLocal.withInitial(HashMap::new);
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = threadLocal.get();
        return scope.computeIfAbsent(name, k -> objectFactory.getObject());
    }
    @Override
    public Object remove(String name) {
        return threadLocal.get().remove(name);
    }
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // 线程销毁时清理
    }
    @Override
    public String getConversationId() {
        return Tphphread.currentThread().getName();
    }
}

注册作用域:

@Configuration
public class ScopeConfig {
    @Bean
    public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
        return beanFactory -> beanFactory.registerScope("threadLocal", new ThreadLocalScope());
    }
}

使用自定义作用域:

@Component
@Scope("threadLocal")
public class RequestContext {
    private String traceId;
    // getter/setter
}
// 或通过@Scope的proxyMode创建代理
@Component
@Scope(value = "threadLocal", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TenantDataSource {
    // 多租户数据源实现
}

2.3 配置方式演进与最佳实践

2.3.1 @ConfigurationProperties构造函数绑定(Spring Boot 2.2+)

构造函数绑定实现不可变配置类,提升线程安全性:

@ConfigurationProperties(prefix = "app.datasource")
@ConstructorBinding // Spring Boot 2.2+支持
public class DataSourceProperties {
    private final String url;
    private final String username;
    private final int poolSize;
    // 单构造器可省略@ConstructorBinding
    public DataSourceProperties(String url, String username, int poolSize) {
        this.url = url;
        this.username = username;
        this.poolSize = poolSize;
    }
    // 仅提供getter,无setter实现不可变
    public String getUrl() { return url; }
}
// 启用配置类
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class AppConfig {
}

配置步骤:

  1. 添加@ConfigurationProperties和@ConstructorBinding注解
  2. 定义final字段和参数化构造函数
  3. 使用@EnableConfigurationProperties或@ConfigurationPropertiesScan启用扫描
  4. 在application.yml中提供配置值

注意事项:@ConstructorBinding不能与@Component、@Bean或@Import一起使用。

3. Bean创建过程的完整剖析

3.1 BeanDefinition的解析与合并

3.1.1 BeanDefinition继承机制

Spring支持通过parent属性实现Bean定义的继承,类似于面向对象中的类继承。子定义可以覆盖父定义的属性,也可以新增特有配置:

<bean id="abstractDataSource" abstract="true" 
      class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test"/>
</bean>
<bean id="masterDataSource" parent="abstractDataSource">
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

合并算法:AbstractBeanFactory.getMergedBeanDefinition()方法递归合并父定义,最终生成RootBeanDefinition。合并过程确保父定义的通用配置被子定义继承,同时子定义可以覆盖特定属性。

3.1.2 ClassPathBeanDefinitionScanner扫描机制

ClassPathBeanDefinitionScanner是注解驱动开发的核心,负责扫描类路径并解析@Component及其派生注解:

// 扫描入口
public int scan(String... basePackages) {
    int beanCount = 0;
    for (String basePackage : basePackages) {
        // 查找候选组件
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            // 解析作用域、代理模式等
            ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 生成Bean名称
          js  String beanName = beanNameGenerator.generateBeanName(candidate, registry);
            // 注册到容器
            registry.registerBeanDefinition(beanName, candidate);
            beanCount++;
        }
    }
    return beanCount;
}

扫描过程通过ASM字节码操作直接读取Class文件的元数据,无需类加载,提升性能。

3.1.3 BeanDefinitionReader的多源配置处理

BeanDefinitionReader是配置解析的统一入口,支持XML、Properties、注解等多种配置源:

  • XmlBeanDefinitionReader :解析XML配置,通过BeanDefinitionParserDelegate处理< bean>、< import>、< alias>等标签
  • AnnotatedBeanDefinitionReader :处理@Configuration、@Component等注解,直接注册BeanDefinition
  • PropertiesBeanDefinitionReader :兼容旧版Properties格式配置

3.2 实例化、属性注入与初www.chinasem.cn始化

3.2.1 实例化策略

Spring通过InstantiationStrategy接口抽象实例化过程,支持两种实现:

  1. SimpleInstantiationStrategy :通过反射调用构造器
  2. CglibSubclassingInstantiationStrategy :当存在方法注入时,生成CGLIB子类
// AbstractAutowireCapableBeanFactory中的实例化
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 使用工厂方法实例化
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // 2. 构造器自动装配
    Constructor<?>[] constructors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (constructors != null) {
        return autowireConstructor(beanName, mbd, constructors, args);
    }
    // 3. 默认无参构造器
    return instantiateBean(beanName, mbd);
}

3.2.2 属性注入与Aware接口

populateBean方法负责属性填充,支持byName、byType、constructor等多种注入模式。在注入前,Spring会回调各类Aware接口:

private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(this);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }
}

3.3 BeanPostProcessor的执行机制

BeanPostProcessor是Spring扩展机制的核心,允许在Bean生命周期的关键节点进行拦截:

// 初始化前回调
Object postProcessBeforeInitialization(Object bean, String beanName)
// 初始化后回调
Object postProcessAfterInitialization(Object bean, String beanName)

执行顺序:BeanPostProcessor的调用遵循明确的顺序,通过Ordered接口或@Order注解控制优先级。典型应用场景包括:

  • @Autowired处理 :AutowiredAnnotationBeanPostProcessor
  • AOP代理创建:AnnotationAwareASPectJAutoProxyCreator
  • 初始化验证:CommonAnnotationBeanPostProcessor处理@PostConstruct

到此这篇关于Spring IOC核心原理详解与运用实战教程的文章就介绍到这了,更多相关Spring IOC原理内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Spring IOC核心原理详解与运用实战教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156281

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

MySQL快速复制一张表的四种核心方法(包括表结构和数据)

《MySQL快速复制一张表的四种核心方法(包括表结构和数据)》本文详细介绍了四种复制MySQL表(结构+数据)的方法,并对每种方法进行了对比分析,适用于不同场景和数据量的复制需求,特别是针对超大表(1... 目录一、mysql 复制表(结构+数据)的 4 种核心方法(面试结构化回答)方法 1:CREATE