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核心技术深度剖析》系列文章。

相关推荐
努力也学不会java7 小时前
【Spring Cloud】 服务注册/服务发现
人工智能·后端·算法·spring·spring cloud·容器·服务发现
Hello.Reader8 小时前
Spring 新声明式 HTTP 客户端:HTTP Interface + RestClient,把“调用外部 API”写成接口
java·spring·http
若鱼19199 小时前
SpringBoot4.0新特性-声明式HTTP远程调用客户端进阶篇
java·spring
夜勤月9 小时前
拒绝线程死锁与调度延迟:深度实战 C++ 内存模型与无锁队列,构建高并发系统级中枢
java·c++·spring
a程序小傲9 小时前
SpringBoot 秒实现在线 Word 编辑、协同、转化等功能
java·开发语言·spring boot·后端·spring·word·深度优先
BlockChain8889 小时前
Spring Cloud实战:电商微服务系统从0到1(25000字终极实战指南)
spring·spring cloud·微服务
手握风云-9 小时前
JavaEE 进阶第十一期:Spring MVC - Web开发的“交通枢纽”(五)
前端·spring·java-ee
a努力。9 小时前
得物Java面试被问:Kafka的零拷贝技术和PageCache优化
java·开发语言·spring·面试·职场和发展·架构·kafka
若离学姐9 小时前
Spring Cloud 零基础教程:Eureka 实战
spring·spring cloud·eureka