Spring IOC依赖注入:从原理到实践的深度解析

文章目录

  • 引言
  • 一、什么是IOC(控制反转)
    • [1.1 IOC的核心概念](#1.1 IOC的核心概念)
    • [1.2 IOC与DI的关系](#1.2 IOC与DI的关系)
    • [1.3 IOC带来的好处](#1.3 IOC带来的好处)
  • 二、Bean的声明方式详解
    • [2.1 XML配置文件方式(经典方式)](#2.1 XML配置文件方式(经典方式))
    • [2.2 注解方式(现代主流)](#2.2 注解方式(现代主流))
    • [2.3 Java配置类方式(类型安全)](#2.3 Java配置类方式(类型安全))
    • [2.4 混合使用策略](#2.4 混合使用策略)
  • 三、IOC容器的工作流程深度解析
    • [3.1 第一阶段:IOC容器初始化](#3.1 第一阶段:IOC容器初始化)
      • [3.1.1 流程图解](#3.1.1 流程图解)
      • [3.1.2 详细过程分析](#3.1.2 详细过程分析)
      • [3.1.3 BeanDefinition的创建过程示例](#3.1.3 BeanDefinition的创建过程示例)
    • [3.2 第二阶段:Bean初始化及依赖注入](#3.2 第二阶段:Bean初始化及依赖注入)
      • [3.2.1 流程图解](#3.2.1 流程图解)
      • [3.2.2 Bean的完整生命周期](#3.2.2 Bean的完整生命周期)
      • [3.2.3 依赖注入的三种方式](#3.2.3 依赖注入的三种方式)
      • [3.2.4 BeanPostProcessor的强大扩展能力](#3.2.4 BeanPostProcessor的强大扩展能力)
    • [3.3 第三阶段:Bean的使用与管理](#3.3 第三阶段:Bean的使用与管理)
      • [3.3.1 Bean的获取方式](#3.3.1 Bean的获取方式)
      • [3.3.2 Bean作用域详解](#3.3.2 Bean作用域详解)
      • [3.3.3 条件化Bean配置](#3.3.3 条件化Bean配置)
  • 四、高级特性与最佳实践
    • [4.1 循环依赖的解决](#4.1 循环依赖的解决)
    • [4.2 延迟初始化策略](#4.2 延迟初始化策略)
    • [4.3 工厂Bean的使用](#4.3 工厂Bean的使用)
    • [4.4 Bean的生命周期回调](#4.4 Bean的生命周期回调)
  • 五、性能优化与常见问题
    • [5.1 性能优化建议](#5.1 性能优化建议)
    • [5.2 常见问题与解决方案](#5.2 常见问题与解决方案)
  • 六、实战案例:电商系统IOC设计
  • 总结

引言

在当今的企业级Java应用开发中,Spring框架无疑是最受欢迎的框架之一。而Spring框架的核心------IOC(控制反转)容器,更是理解Spring精髓的关键所在。本文将深入剖析Spring IOC容器的依赖注入全过程,带你领略这一革命性设计思想的魅力所在。

一、什么是IOC(控制反转)

1.1 IOC的核心概念

控制反转(Inversion of Control) 是一种颠覆传统编程模式的设计思想。在传统的程序设计中,对象的创建和依赖关系的管理由应用程序代码主动控制;而在IOC模式下,这种控制权被反转给了容器。

举个生活中的例子:传统方式就像你自己去市场买菜、洗菜、切菜、炒菜(全程自己控制);而IOC模式更像是去餐厅点菜,你只需要告诉服务员想吃什么(声明需求),餐厅后厨(容器)会帮你准备好一切。

1.2 IOC与DI的关系

很多初学者容易混淆IOC和DI(依赖注入)的概念,这里做一个清晰的区分:

  • IOC:是一种更宏观的设计思想,强调控制权的反转
  • DI:是IOC思想的一种具体实现方式,通过容器注入依赖

可以说,DI是实现IOC的主要手段,但并非唯一方式。在Spring框架中,我们主要使用依赖注入来实现控制反转。

1.3 IOC带来的好处

java 复制代码
// 传统方式:紧耦合
public class UserService {
    private UserDao userDao = new UserDaoImpl();  // 直接new,高度耦合
    
    public void addUser(User user) {
        userDao.save(user);
    }
}

// IOC方式:松耦合
public class UserService {
    @Autowired
    private UserDao userDao;  // 依赖由容器注入
    
    public void addUser(User user) {
        userDao.save(user);
    }
}

核心优势

  1. 降低耦合度:组件间依赖关系由容器管理
  2. 提高可测试性:便于进行单元测试和模拟
  3. 增强可维护性:配置集中管理,易于修改
  4. 提升复用性:组件可被多个应用共享使用

二、Bean的声明方式详解

Spring提供了多种灵活的方式来声明和配置Bean,满足不同场景的需求。

2.1 XML配置文件方式(经典方式)

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 基本Bean定义 -->
    <bean id="userDao" class="com.example.dao.UserDaoImpl"/>
    
    <!-- 带属性的Bean -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
    <!-- 构造器注入 -->
    <bean id="userService" class="com.example.service.UserServiceImpl">
        <constructor-arg ref="userDao"/>
        <constructor-arg value="default"/>
    </bean>
    
    <!-- Setter注入 -->
    <bean id="orderService" class="com.example.service.OrderServiceImpl">
        <property name="userService" ref="userService"/>
        <property name="timeout" value="5000"/>
    </bean>
</beans>

XML配置的特点

  • 集中管理:所有配置在一个或几个文件中
  • 与代码解耦:修改配置无需重新编译
  • 可读性强:结构清晰,适合复杂配置
  • 支持热更新:部分场景下可动态刷新

2.2 注解方式(现代主流)

java 复制代码
// 1. 组件扫描配置
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}

// 2. Service层
@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    @Autowired  // 自动注入
    private UserDao userDao;
    
    @Value("${app.default.name}")  // 注入配置值
    private String defaultName;
    
    @PostConstruct
    public void init() {
        System.out.println("UserService初始化完成");
    }
    
    @PreDestroy
    public void destroy() {
        System.out.println("UserService准备销毁");
    }
}

// 3. Dao层
@Repository
public class UserDaoImpl implements UserDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public User findById(Long id) {
        return jdbcTemplate.queryForObject(
            "SELECT * FROM users WHERE id = ?",
            new UserRowMapper(),
            id
        );
    }
}

// 4. 控制器层
@Controller
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    @ResponseBody
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
}

常用注解分类

注解 作用 说明
@Component 通用组件 最基础的组件注解
@Service 服务层组件 业务逻辑层
@Repository 数据访问层 数据访问层,自动异常转换
@Controller 控制层 MVC控制器
@RestController REST控制器 包含@Controller@ResponseBody
@Configuration 配置类 定义配置信息
@Autowired 自动注入 按类型自动注入
@Qualifier 指定Bean名 @Autowired配合使用
@Resource 资源注入 JDK注解,可按名称注入
@Value 值注入 注入简单值或表达式

2.3 Java配置类方式(类型安全)

java 复制代码
@Configuration
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
public class AppConfig {
    
    @Bean
    public DataSource dataSource(
            @Value("${db.url}") String url,
            @Value("${db.username}") String username,
            @Value("${db.password}") String password) {
        
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaximumPoolSize(20);
        return dataSource;
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean
    @Scope("prototype")  // 原型模式
    @Lazy  // 懒加载
    public UserService userService(UserDao userDao) {
        return new UserServiceImpl(userDao);
    }
    
    @Bean
    public UserDao userDao(JdbcTemplate jdbcTemplate) {
        UserDaoImpl userDao = new UserDaoImpl();
        userDao.setJdbcTemplate(jdbcTemplate);
        return userDao;
    }
}

Java配置的优势

  • 类型安全:编译时检查,避免配置错误
  • IDE友好:自动补全和重构支持
  • 便于调试:可直接在代码中打断点
  • 条件化配置 :结合@Conditional实现灵活配置

2.4 混合使用策略

在实际项目中,推荐混合使用各种配置方式:

java 复制代码
@Configuration
@Import({DataSourceConfig.class, CacheConfig.class})  // 导入其他配置类
@ImportResource("classpath:legacy-beans.xml")  // 导入XML配置
@ComponentScan(basePackages = "com.example.service")
public class MainConfig {
    
    // 新功能使用Java配置
    @Bean
    public NewFeatureService newFeatureService() {
        return new NewFeatureServiceImpl();
    }
}

三、IOC容器的工作流程深度解析

Spring IOC容器的工作流程可以分为三个核心阶段,每个阶段都有其独特的职责和实现机制。

3.1 第一阶段:IOC容器初始化

这个阶段是容器启动的核心,主要完成Bean定义的加载和注册。

3.1.1 流程图解

复制代码
启动ApplicationContext
    ↓
加载配置资源
    ↓
创建BeanDefinitionReader
    ↓
读取并解析配置
    ↓
生成BeanDefinition对象
    ↓
注册到BeanDefinitionRegistry
    ↓
初始化完成,进入下一阶段

3.1.2 详细过程分析

1. 资源定位与加载

java 复制代码
// Spring容器的启动入口
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 或者使用注解方式
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

2. BeanDefinition的创建

Spring将每个Bean的配置信息解析为BeanDefinition对象,这是一个重要的数据结构:

java 复制代码
// BeanDefinition接口的主要方法
public interface BeanDefinition {
    // Bean的类名
    void setBeanClassName(String beanClassName);
    String getBeanClassName();
    
    // 作用域
    void setScope(String scope);
    String getScope();
    
    // 是否懒加载
    void setLazyInit(boolean lazyInit);
    boolean isLazyInit();
    
    // 依赖的Bean名称
    void setDependsOn(String... dependsOn);
    String[] getDependsOn();
    
    // 是否单例
    boolean isSingleton();
    
    // 是否原型
    boolean isPrototype();
    
    // 工厂方法
    void setFactoryMethodName(String factoryMethodName);
    String getFactoryMethodName();
    
    // 初始化方法
    void setInitMethodName(String initMethodName);
    String getInitMethodName();
    
    // 销毁方法
    void setDestroyMethodName(String destroyMethodName);
    String getDestroyMethodName();
    
    // 属性值
    MutablePropertyValues getPropertyValues();
}

3. 注册到容器

Spring使用BeanDefinitionRegistry来管理所有的BeanDefinition:

java 复制代码
// 核心注册表接口
public interface BeanDefinitionRegistry {
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
    void removeBeanDefinition(String beanName);
    BeanDefinition getBeanDefinition(String beanName);
    boolean containsBeanDefinition(String beanName);
    String[] getBeanDefinitionNames();
    int getBeanDefinitionCount();
}

// 实际实现:DefaultListableBeanFactory
public class DefaultListableBeanFactory implements BeanDefinitionRegistry {
    // 使用ConcurrentHashMap存储BeanDefinition
    private final Map<String, BeanDefinition> beanDefinitionMap = 
        new ConcurrentHashMap<>(256);
    
    // 按类型存储Bean名称
    private final Map<Class<?>, String[]> allBeanNamesByType = 
        new ConcurrentHashMap<>(64);
}

3.1.3 BeanDefinition的创建过程示例

以XML配置为例:

xml 复制代码
<!-- XML配置 -->
<bean id="userService" class="com.example.UserServiceImpl" 
      scope="singleton" lazy-init="false">
    <property name="userDao" ref="userDao"/>
    <property name="defaultName" value="admin"/>
</bean>

被解析为:

java 复制代码
// 创建RootBeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.example.UserServiceImpl");
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
beanDefinition.setLazyInit(false);

// 设置属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("userDao", new RuntimeBeanReference("userDao"));
propertyValues.addPropertyValue("defaultName", "admin");
beanDefinition.setPropertyValues(propertyValues);

// 注册到容器
registry.registerBeanDefinition("userService", beanDefinition);

3.2 第二阶段:Bean初始化及依赖注入

这个阶段是IOC容器的核心执行阶段,完成Bean的实例化、依赖注入和初始化。

3.2.1 流程图解

复制代码
获取BeanDefinition
    ↓
实例化Bean(createBeanInstance)
    ↓
处理BeanPostProcessor(实例化前)
    ↓
属性注入(populateBean)
    ↓
处理Aware接口
    ↓
BeanPostProcessor前置处理
    ↓
执行初始化方法
    ↓
BeanPostProcessor后置处理
    ↓
Bean准备就绪

3.2.2 Bean的完整生命周期

java 复制代码
// Bean的完整生命周期(简化版)
public class BeanLifecycleDemo implements 
        BeanNameAware, BeanFactoryAware, ApplicationContextAware,
        InitializingBean, DisposableBean {
    
    private String name;
    
    // 1. 实例化(构造函数)
    public BeanLifecycleDemo() {
        System.out.println("1. 构造函数执行 - 实例化Bean");
    }
    
    // 2. 属性设置(Setter方法)
    public void setName(String name) {
        System.out.println("2. 属性设置 - name: " + name);
        this.name = name;
    }
    
    // 3. BeanNameAware接口
    @Override
    public void setBeanName(String name) {
        System.out.println("3. BeanNameAware - beanName: " + name);
    }
    
    // 4. BeanFactoryAware接口
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("4. BeanFactoryAware - 设置BeanFactory");
    }
    
    // 5. ApplicationContextAware接口
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        System.out.println("5. ApplicationContextAware - 设置ApplicationContext");
    }
    
    // 6. BeanPostProcessor.postProcessBeforeInitialization
    // 7. @PostConstruct注解方法
    @PostConstruct
    public void postConstruct() {
        System.out.println("7. @PostConstruct - 注解初始化方法");
    }
    
    // 8. InitializingBean.afterPropertiesSet
    @Override
    public void afterPropertiesSet() {
        System.out.println("8. InitializingBean - afterPropertiesSet");
    }
    
    // 9. init-method配置的方法
    public void customInit() {
        System.out.println("9. init-method - 自定义初始化方法");
    }
    
    // 10. BeanPostProcessor.postProcessAfterInitialization
    // 11. Bean准备就绪,可使用
    public void doSomething() {
        System.out.println("11. Bean业务方法执行");
    }
    
    // 12. @PreDestroy注解方法
    @PreDestroy
    public void preDestroy() {
        System.out.println("12. @PreDestroy - 注解销毁方法");
    }
    
    // 13. DisposableBean.destroy
    @Override
    public void destroy() {
        System.out.println("13. DisposableBean - destroy方法");
    }
    
    // 14. destroy-method配置的方法
    public void customDestroy() {
        System.out.println("14. destroy-method - 自定义销毁方法");
    }
}

3.2.3 依赖注入的三种方式

1. 构造器注入(推荐)

java 复制代码
@Component
public class OrderService {
    private final UserService userService;
    private final ProductService productService;
    
    // 构造器注入
    @Autowired
    public OrderService(UserService userService, ProductService productService) {
        this.userService = userService;
        this.productService = productService;
    }
}

优点

  • 保证依赖不可变(final字段)
  • 保证依赖不为null
  • 保证完全初始化的状态
  • 避免循环依赖问题
  • 易于测试

2. Setter注入

java 复制代码
@Component
public class OrderService {
    private UserService userService;
    private ProductService productService;
    
    // Setter注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    @Autowired
    public void setProductService(ProductService productService) {
        this.productService = productService;
    }
}

适用场景

  • 可选依赖
  • 需要重新配置的依赖
  • 有默认实现的依赖

3. 字段注入

java 复制代码
@Component
public class OrderService {
    @Autowired
    private UserService userService;
    
    @Autowired
    private ProductService productService;
}

注意:虽然字段注入写法简洁,但存在以下问题:

  • 不能声明为final
  • 隐藏依赖关系
  • 不利于测试
  • Spring团队不推荐使用

3.2.4 BeanPostProcessor的强大扩展能力

BeanPostProcessor是Spring提供的重要扩展点,可以在Bean初始化前后进行自定义处理:

java 复制代码
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor, Ordered {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("Before初始化: " + beanName + " - " + bean.getClass().getName());
        
        // 示例:为特定类型的Bean添加代理
        if (bean instanceof UserService) {
            System.out.println("为UserService创建代理");
            return Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("调用方法: " + method.getName());
                    return method.invoke(bean, args);
                }
            );
        }
        
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("After初始化: " + beanName + " - " + bean.getClass().getName());
        
        // 示例:检查Bean的属性
        if (bean instanceof Validatable) {
            ((Validatable) bean).validate();
        }
        
        return bean;
    }
    
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;  // 执行顺序
    }
}

3.3 第三阶段:Bean的使用与管理

3.3.1 Bean的获取方式

1. 依赖注入(推荐)

java 复制代码
@Component
public class OrderController {
    
    // 按类型注入
    @Autowired
    private OrderService orderService;
    
    // 按名称注入
    @Autowired
    @Qualifier("specialOrderService")
    private OrderService specialService;
    
    // 构造器注入(Spring 4.3+可以省略@Autowired)
    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }
    
    // 集合注入
    @Autowired
    private List<Validator> validators;
    
    // Map注入(key为bean名称)
    @Autowired
    private Map<String, Processor> processors;
}

2. 编程式获取

java 复制代码
// 通过ApplicationContext获取
@Component
public class BeanLocator {
    
    @Autowired
    private ApplicationContext context;
    
    public Object getBeanByName(String name) {
        return context.getBean(name);
    }
    
    public <T> T getBeanByType(Class<T> type) {
        return context.getBean(type);
    }
    
    public <T> Map<String, T> getBeansOfType(Class<T> type) {
        return context.getBeansOfType(type);
    }
    
    // 获取所有Bean名称
    public String[] getAllBeanNames() {
        return context.getBeanDefinitionNames();
    }
}

3. 延迟查找

java 复制代码
@Component
public class LazyBeanLookup {
    
    // 延迟注入(当使用时才获取)
    @Autowired
    private ObjectProvider<ExpensiveService> expensiveServiceProvider;
    
    public void doWork() {
        // 按需获取
        ExpensiveService service = expensiveServiceProvider.getIfAvailable();
        if (service != null) {
            service.process();
        }
    }
}

3.3.2 Bean作用域详解

Spring支持多种Bean作用域:

java 复制代码
@Configuration
public class ScopeConfig {
    
    // 单例(默认) - 整个容器只有一个实例
    @Bean
    @Scope("singleton")  // 或 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public SingletonBean singletonBean() {
        return new SingletonBean();
    }
    
    // 原型 - 每次获取都创建新实例
    @Bean
    @Scope("prototype")  // 或 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }
    
    // Request作用域(Web环境)
    @Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public RequestScopedBean requestScopedBean() {
        return new RequestScopedBean();
    }
    
    // Session作用域(Web环境)
    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public SessionScopedBean sessionScopedBean() {
        return new SessionScopedBean();
    }
    
    // 自定义作用域
    @Bean
    public CustomScope customScope() {
        return new CustomScope();
    }
    
    @Bean
    public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
        return beanFactory -> {
            beanFactory.registerScope("custom", customScope());
        };
    }
    
    @Bean
    @Scope("custom")
    public CustomScopedBean customScopedBean() {
        return new CustomScopedBean();
    }
}

3.3.3 条件化Bean配置

Spring提供了强大的条件化配置机制:

java 复制代码
@Configuration
public class ConditionalConfig {
    
    // 根据条件创建Bean
    @Bean
    @ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
    @ConditionalOnClass(name = "redis.clients.jedis.Jedis")
    public CacheService redisCacheService() {
        return new RedisCacheService();
    }
    
    @Bean
    @ConditionalOnMissingBean(CacheService.class)
    public CacheService localCacheService() {
        return new LocalCacheService();
    }
    
    // 自定义条件
    @Bean
    @Conditional(ProductionCondition.class)
    public DataSource productionDataSource() {
        return createProductionDataSource();
    }
    
    @Bean
    @Conditional(DevelopmentCondition.class)
    public DataSource developmentDataSource() {
        return createDevelopmentDataSource();
    }
    
    // 配置类条件
    @Configuration
    @ConditionalOnWebApplication
    @ConditionalOnProperty(prefix = "security", name = "enabled", matchIfMissing = true)
    @EnableWebSecurity
    public static class SecurityConfig extends WebSecurityConfigurerAdapter {
        // 安全配置
    }
}

// 自定义条件类
public class ProductionCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        return "production".equals(env.getProperty("app.env"));
    }
}

四、高级特性与最佳实践

4.1 循环依赖的解决

Spring通过三级缓存巧妙解决了单例Bean的构造器循环依赖问题:

java 复制代码
// 循环依赖示例
@Component
public class ServiceA {
    private final ServiceB serviceB;
    
    @Autowired
    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

@Component
public class ServiceB {
    private final ServiceA serviceA;
    
    @Autowired
    public ServiceB(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

// Spring的三级缓存解决方案
public class DefaultSingletonBeanRegistry {
    // 一级缓存:存放完全初始化好的Bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    // 二级缓存:存放早期暴露的Bean(未完成属性注入)
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    
    // 三级缓存:存放Bean工厂,用于创建早期引用
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
    // 正在创建中的Bean
    private final Set<String> singletonsCurrentlyInCreation = 
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}

解决流程

  1. 创建ServiceA,放入三级缓存
  2. ServiceA需要ServiceB,开始创建ServiceB
  3. ServiceB需要ServiceA,从三级缓存获取ServiceA的早期引用
  4. ServiceB创建完成,注入到ServiceA
  5. ServiceA完成创建

4.2 延迟初始化策略

java 复制代码
@Configuration
public class LazyConfig {
    
    // 懒加载Bean
    @Bean
    @Lazy
    public ExpensiveBean expensiveBean() {
        System.out.println("创建ExpensiveBean...");
        return new ExpensiveBean();
    }
    
    // 配置类懒加载
    @Configuration
    @Lazy
    public static class LazySubConfig {
        @Bean
        public AnotherBean anotherBean() {
            return new AnotherBean();  // 只有被请求时才创建
        }
    }
    
    // 条件化懒加载
    @Bean
    @Lazy
    @ConditionalOnMissingBean
    public DefaultService defaultService() {
        return new DefaultService();
    }
}

4.3 工厂Bean的使用

FactoryBean用于创建复杂的对象:

java 复制代码
@Component
public class ConnectionFactoryBean implements FactoryBean<Connection> {
    
    @Value("${db.url}")
    private String url;
    
    @Value("${db.username}")
    private String username;
    
    @Value("${db.password}")
    private String password;
    
    @Override
    public Connection getObject() throws Exception {
        // 创建复杂的连接对象
        return DriverManager.getConnection(url, username, password);
    }
    
    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }
    
    @Override
    public boolean isSingleton() {
        return false;  // 每次获取新连接
    }
}

// 使用FactoryBean
@Component
public class DataAccessService {
    
    @Autowired
    private Connection connection;  // 实际获取的是FactoryBean.getObject()
    
    // 如果需要获取FactoryBean本身
    @Autowired
    private ConnectionFactoryBean connectionFactoryBean;
    
    // 或者通过名称获取
    @Autowired
    @Qualifier("&connectionFactoryBean")  // &前缀表示获取FactoryBean本身
    private FactoryBean<Connection> factoryBean;
}

4.4 Bean的生命周期回调

java 复制代码
@Component
public class LifecycleBean implements 
        SmartLifecycle, 
        ApplicationListener<ContextRefreshedEvent> {
    
    private volatile boolean running = false;
    
    // 1. 容器刷新完成事件
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("容器刷新完成,开始初始化业务...");
        initBusiness();
    }
    
    // 2. SmartLifecycle - 启动
    @Override
    public void start() {
        if (!running) {
            System.out.println("LifecycleBean开始启动...");
            running = true;
            // 启动后台线程等
        }
    }
    
    // 3. SmartLifecycle - 停止
    @Override
    public void stop() {
        if (running) {
            System.out.println("LifecycleBean正在停止...");
            running = false;
            // 清理资源
        }
    }
    
    @Override
    public boolean isRunning() {
        return running;
    }
    
    @Override
    public int getPhase() {
        return 0;  // 执行阶段
    }
    
    @Override
    public boolean isAutoStartup() {
        return true;  // 自动启动
    }
    
    private void initBusiness() {
        // 业务初始化逻辑
    }
}

五、性能优化与常见问题

5.1 性能优化建议

  1. 合理使用作用域

    • 无状态Bean使用单例
    • 有状态Bean考虑原型
    • Web相关Bean使用request/session作用域
  2. 懒加载策略

    java 复制代码
    @Configuration
    @Lazy  // 整个配置类懒加载
    public class LazyConfig {
        
        @Bean
        @Lazy(false)  // 这个Bean不懒加载
        public EssentialBean essentialBean() {
            return new EssentialBean();
        }
    }
  3. 避免过度使用AOP

    java 复制代码
    // 精确指定切点,避免匹配过多方法
    @Pointcut("execution(public * com.example.service.*.*(..))")
    public void serviceLayer() {}
  4. 合理使用缓存

    java 复制代码
    @Component
    @CacheConfig(cacheNames = "users")
    public class UserService {
        
        @Cacheable(key = "#id")
        public User getUser(Long id) {
            // 数据库查询
        }
        
        @CachePut(key = "#user.id")
        public User updateUser(User user) {
            // 更新数据库
        }
        
        @CacheEvict(key = "#id")
        public void deleteUser(Long id) {
            // 删除数据库记录
        }
    }

5.2 常见问题与解决方案

问题1:Bean创建失败

java 复制代码
// 原因:循环依赖(构造器注入)
@Component
public class A {
    private final B b;
    public A(B b) { this.b = b; }  // 错误:循环依赖
}

@Component
public class B {
    private final A a;
    public B(A a) { this.a = a; }  // 错误:循环依赖
}

// 解决方案1:使用Setter注入
@Component
public class A {
    private B b;
    @Autowired
    public void setB(B b) { this.b = b; }
}

// 解决方案2:使用@Lazy
@Component
public class A {
    private final B b;
    public A(@Lazy B b) { this.b = b; }  // 延迟注入
}

问题2:多个同类型Bean

java 复制代码
// 多个同类型Bean
@Bean
public DataSource primaryDataSource() { ... }

@Bean
public DataSource secondaryDataSource() { ... }

// 解决方案1:使用@Primary
@Bean
@Primary
public DataSource primaryDataSource() { ... }

// 解决方案2:使用@Qualifier
@Autowired
@Qualifier("secondaryDataSource")
private DataSource dataSource;

// 解决方案3:使用@Resource(按名称)
@Resource(name = "secondaryDataSource")
private DataSource dataSource;

问题3:Bean覆盖问题

java 复制代码
// 在application.properties中控制
spring.main.allow-bean-definition-overriding=true

// 或者明确指定Bean名称
@Bean("myDataSource")
public DataSource dataSource() { ... }

六、实战案例:电商系统IOC设计

java 复制代码
// 领域模型
@Entity
@Data
public class Product {
    private Long id;
    private String name;
    private BigDecimal price;
    private Integer stock;
}

// 仓储层
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findByPriceLessThan(BigDecimal price);
}

// 服务层
@Service
@Transactional
public class ProductService {
    
    @Autowired
    private ProductRepository productRepository;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private PriceCalculator priceCalculator;
    
    @Autowired
    private List<Validator> validators;  // 策略模式
    
    public Product createProduct(Product product) {
        // 验证
        validators.forEach(v -> v.validate(product));
        
        // 计算价格
        BigDecimal finalPrice = priceCalculator.calculate(product);
        product.setPrice(finalPrice);
        
        // 保存
        return productRepository.save(product);
    }
    
    @Async  // 异步处理
    @EventListener
    public void handleOrderEvent(OrderCreatedEvent event) {
        updateInventory(event.getProductId(), event.getQuantity());
    }
}

// 配置类
@Configuration
@EnableAsync
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
@EnableCaching
public class AppConfig {
    
    @Bean
    public PriceCalculator priceCalculator(
            @Value("${tax.rate}") BigDecimal taxRate,
            @Value("${discount.enabled}") boolean discountEnabled) {
        
        return new PriceCalculator(taxRate, discountEnabled);
    }
    
    @Bean
    @Order(1)
    public Validator stockValidator() {
        return product -> {
            if (product.getStock() < 0) {
                throw new ValidationException("库存不能为负");
            }
        };
    }
    
    @Bean
    @Order(2)
    public Validator priceValidator() {
        return product -> {
            if (product.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
                throw new ValidationException("价格必须大于0");
            }
        };
    }
    
    // 条件化配置:开发环境
    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        return DataSourceBuilder.create()
            .url("jdbc:h2:mem:testdb")
            .username("sa")
            .password("")
            .build();
    }
    
    // 条件化配置:生产环境
    @Bean
    @Profile("prod")
    public DataSource prodDataSource(
            @Value("${db.url}") String url,
            @Value("${db.username}") String username,
            @Value("${db.password}") String password) {
        
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaximumPoolSize(50);
        return dataSource;
    }
}

总结

Spring IOC容器通过其精妙的设计和实现,为我们提供了一套完整的依赖管理解决方案。从Bean的声明、注册、初始化到使用,每一个环节都体现了Spring框架的设计哲学:约定优于配置面向接口编程关注点分离

关键要点回顾:

  1. IOC是思想,DI是实现:理解控制反转和依赖注入的关系
  2. 多种配置方式:XML、注解、Java配置各有适用场景
  3. 完整的生命周期:从BeanDefinition到销毁,每个阶段都可定制
  4. 强大的扩展点:BeanPostProcessor、FactoryBean等提供无限可能
  5. 灵活的作用域:适应不同应用场景的需求
  6. 优雅的循环依赖解决:三级缓存机制的精妙设计

掌握Spring IOC容器的原理和实践,不仅能帮助我们更好地使用Spring框架,更能提升我们的系统设计能力和架构思维。在实际项目中,应根据具体需求选择合适的配置方式和设计模式,充分发挥IOC容器的优势。


如需获取更多关于Spring IoC容器深度解析、Bean生命周期管理、循环依赖解决方案、条件化配置等内容,请持续关注本专栏《Spring核心技术深度剖析》系列文章。

相关推荐
To Be Clean Coder3 小时前
【Spring源码】从源码倒看Spring用法(二)
java·后端·spring
To Be Clean Coder6 小时前
【Spring源码】getBean源码实战(二)
java·后端·spring
0和1的舞者8 小时前
SpringAOP详解(二)
学习·spring·切面·代理·知识·springaop
廋到被风吹走8 小时前
【Spring】Spring Cache 深度解析
java·后端·spring
七夜zippoe9 小时前
响应式编程基石 Project Reactor源码解读
java·spring·flux·响应式编程·mono·订阅机制
IT 行者9 小时前
Spring Framework 6.x 异常国际化完全指南:让错误信息“说“多国语言
java·后端·spring·异常处理·problemdetail·国际化i18n
鱼跃鹰飞10 小时前
面试题:Spring事务失效的八大场景
数据库·mysql·spring
wa的一声哭了10 小时前
内积空间 内积空间二
java·开发语言·python·spring·java-ee·django·maven
cike_y10 小时前
Spring使用注解开发
java·后端·spring·jdk1.8