Spring IOC详解

29 阅读12分钟

Spring IOC详解:从原理到实战

前言

Spring框架的核心是IoC(Inversion of Control,控制反转)容器,它是Spring框架的基石。理解IoC容器的工作原理和使用方式,对于深入掌握Spring框架至关重要。本文将从IoC的基本概念出发,结合源码分析和实战案例,全面解析Spring IoC容器的核心知识点。

一、什么是IoC

1.1 控制反转的概念

IoC(Inversion of Control)控制反转,是一种设计思想。传统的程序设计中,对象的创建和依赖关系的管理都是由程序代码直接控制的。而在IoC中,这些控制权被"反转"给了容器。

传统方式 vs IoC方式
┌─────────────────────────────────────────────┐
│  传统方式:                                  │
│  ┌──────────┐     new      ┌──────────┐    │
│  │ UserService│ ─────────> │  UserDao │    │
│  └──────────┘              └──────────┘    │
│  对象主动创建依赖                            │
├─────────────────────────────────────────────┤
│  IoC方式:                                  │
│  ┌──────────┐            ┌──────────┐      │
│  │UserService│            │  UserDao │      │
│  └─────┬────┘            └─────┬────┘      │
│        │                       │            │
│        └───────┐       ┌───────┘            │
│                ▼       ▼                    │
│           ┌─────────────┐                   │
│           │  IoC Container│                  │
│           └─────────────┘                   │
│  容器负责创建对象和注入依赖                  │
└─────────────────────────────────────────────┘

1.2 为什么需要IoC

/**
 * 传统方式的问题
 */
public class UserServiceOld {
    // 紧耦合:直接依赖具体实现
    private UserDao userDao = new UserDaoImpl();

    public User findUser(Long id) {
        return userDao.findById(id);
    }
}

// 问题:
// 1. 紧耦合:UserService直接依赖UserDaoImpl
// 2. 难以测试:无法mock UserDao
// 3. 难以扩展:要换实现必须修改代码
/**
 * IoC方式的优势
 */
public class UserService {
    // 依赖抽象,由外部注入
    private UserDao userDao;

    // 构造器注入
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User findUser(Long id) {
        return userDao.findById(id);
    }
}

// 优势:
// 1. 松耦合:依赖抽象而非具体实现
// 2. 易于测试:可以注入Mock对象
// 3. 易于扩展:更换实现无需修改代码

1.3 DI(依赖注入)

DI(Dependency Injection)依赖注入,是IoC的一种实现方式。它通过外部注入依赖对象,而不是在对象内部创建。

IoC和DI的关系
┌─────────────────────────────────┐
│  IoC (控制反转)                  │
│  - 设计思想/原则                 │
│  - 将控制权交给容器              │
│                                  │
│  ┌─────────────────────────┐   │
│  │ DI (依赖注入)            │   │
│  │ - IoC的具体实现方式      │   │
│  │ - 构造器注入             │   │
│  │ - Setter注入             │   │
│  │ - 字段注入               │   │
│  └─────────────────────────┘   │
└─────────────────────────────────┘

二、Spring IoC容器

2.1 BeanFactory与ApplicationContext

Spring提供了两种IoC容器:BeanFactory和ApplicationContext。

IoC容器层次结构
                BeanFactory
                    ↑
                    │
           ApplicationContext
                    ↑
       ┌────────────┼────────────┐
       │            │            │
ClassPathXml  FileSystemXml  AnnotationConfig
ApplicationContext ApplicationContext ApplicationContext
/**
 * BeanFactory - 基础容器
 */
public class BeanFactoryDemo {
    public static void main(String[] args) {
        // 创建资源对象
        Resource resource = new ClassPathResource("beans.xml");

        // 创建BeanFactory
        BeanFactory factory = new XmlBeanFactory(resource);

        // 获取Bean(延迟加载)
        UserService userService = (UserService) factory.getBean("userService");
    }
}

/**
 * ApplicationContext - 高级容器
 */
public class ApplicationContextDemo {
    public static void main(String[] args) {
        // 创建ApplicationContext
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        // 获取Bean(预加载)
        UserService userService = context.getBean("userService", UserService.class);

        // ApplicationContext提供更多功能
        String[] beanNames = context.getBeanDefinitionNames();
        for (String name : beanNames) {
            System.out.println(name);
        }
    }
}

BeanFactory vs ApplicationContext:

┌───────────────────┬─────────────────┬────────────────────┐
│      特性          │   BeanFactory   │ ApplicationContext │
├───────────────────┼─────────────────┼────────────────────┤
│  Bean加载          │   延迟加载       │    立即加载         │
│  国际化支持        │   不支持         │    支持             │
│  事件发布          │   不支持         │    支持             │
│  AOP支持           │   需手动配置     │    自动支持         │
│  资源访问          │   较弱           │    强大             │
│  使用场景          │   资源受限环境   │    企业级应用       │
└───────────────────┴─────────────────┴────────────────────┘

2.2 Bean的配置方式

2.2.1 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.impl.UserDaoImpl"/>

    <!-- 构造器注入 -->
    <bean id="userService" class="com.example.service.UserService">
        <constructor-arg ref="userDao"/>
    </bean>

    <!-- Setter注入 -->
    <bean id="orderService" class="com.example.service.OrderService">
        <property name="orderDao" ref="orderDao"/>
        <property name="timeout" value="30"/>
    </bean>

    <!-- 集合注入 -->
    <bean id="emailService" class="com.example.service.EmailService">
        <property name="receivers">
            <list>
                <value>admin@example.com</value>
                <value>support@example.com</value>
            </list>
        </property>
    </bean>
</beans>
2.2.2 注解配置
/**
 * 配置类
 */
@Configuration
public class AppConfig {

    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }

    @Bean
    public UserService userService() {
        return new UserService(userDao());
    }

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }
}

/**
 * 使用配置类
 */
public class AnnotationConfigDemo {
    public static void main(String[] args) {
        ApplicationContext context =
            new AnnotationConfigApplicationContext(AppConfig.class);

        UserService userService = context.getBean(UserService.class);
    }
}
2.2.3 组件扫描
/**
 * 启用组件扫描
 */
@Configuration
@ComponentScan(basePackages = "com.example")
public class ScanConfig {
}

/**
 * DAO层
 */
@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public User findById(Long id) {
        System.out.println("查询用户: " + id);
        return new User(id, "User" + id);
    }
}

/**
 * Service层
 */
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public User getUser(Long id) {
        return userDao.findById(id);
    }
}

/**
 * Controller层
 */
@Controller
public class UserController {

    @Autowired
    private UserService userService;

    public void handleRequest(Long userId) {
        User user = userService.getUser(userId);
        System.out.println("处理用户请求: " + user);
    }
}

三、依赖注入方式

3.1 构造器注入

/**
 * 构造器注入(推荐方式)
 */
@Service
public class OrderService {

    private final OrderDao orderDao;
    private final PaymentService paymentService;

    // Spring 4.3+,单个构造器可以省略@Autowired
    @Autowired
    public OrderService(OrderDao orderDao, PaymentService paymentService) {
        this.orderDao = orderDao;
        this.paymentService = paymentService;
    }

    public void createOrder(Order order) {
        orderDao.save(order);
        paymentService.processPayment(order.getId());
    }
}

// 优点:
// 1. 保证依赖不可变(final)
// 2. 依赖明确,易于测试
// 3. 防止空指针异常
// 4. 支持循环依赖检测

3.2 Setter注入

/**
 * Setter注入
 */
@Service
public class EmailService {

    private TemplateEngine templateEngine;
    private MailSender mailSender;

    @Autowired
    public void setTemplateEngine(TemplateEngine templateEngine) {
        this.templateEngine = templateEngine;
    }

    @Autowired
    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void sendEmail(String to, String subject, String content) {
        String body = templateEngine.process(content);
        mailSender.send(to, subject, body);
    }
}

// 优点:
// 1. 可选依赖
// 2. 可以在对象创建后修改依赖
// 缺点:
// 1. 依赖可变
// 2. 可能出现空指针

3.3 字段注入

/**
 * 字段注入(不推荐,但最常用)
 */
@Service
public class ProductService {

    @Autowired
    private ProductDao productDao;

    @Autowired
    private InventoryService inventoryService;

    public Product getProduct(Long id) {
        Product product = productDao.findById(id);
        product.setStock(inventoryService.getStock(id));
        return product;
    }
}

// 优点:
// 1. 代码简洁
// 缺点:
// 1. 不能用于final字段
// 2. 难以进行单元测试
// 3. 隐藏了依赖关系
// 4. 违反了依赖注入原则

3.4 方法注入

/**
 * 方法注入 - 处理作用域问题
 */
@Component
@Scope("singleton")
public abstract class CommandManager {

    public void process() {
        // 每次都获取新的Command实例
        Command command = createCommand();
        command.execute();
    }

    // 查找方法注入
    @Lookup
    protected abstract Command createCommand();
}

@Component
@Scope("prototype")
public class Command {
    public void execute() {
        System.out.println("执行命令");
    }
}

四、Bean的生命周期

4.1 生命周期流程

Bean生命周期流程图
┌─────────────────────────────────────────┐
│  1. 实例化Bean                           │
│     new XXX()                            │
├─────────────────────────────────────────┤
│  2. 设置属性                             │
│     populateBean()                       │
├─────────────────────────────────────────┤
│  3. 调用BeanNameAware.setBeanName()     │
├─────────────────────────────────────────┤
│  4. 调用BeanFactoryAware.setBeanFactory│
├─────────────────────────────────────────┤
│  5. 调用ApplicationContextAware        │
├─────────────────────────────────────────┤
│  6. 前置处理                             │
│     BeanPostProcessor.postProcessBefore │
├─────────────────────────────────────────┤
│  7. 调用InitializingBean.afterProperties│
├─────────────────────────────────────────┤
│  8. 调用自定义init-method               │
├─────────────────────────────────────────┤
│  9. 后置处理                             │
│     BeanPostProcessor.postProcessAfter  │
├─────────────────────────────────────────┤
│  10. Bean可以使用了                      │
├─────────────────────────────────────────┤
│  11. 容器关闭                            │
├─────────────────────────────────────────┤
│  12. 调用DisposableBean.destroy()       │
├─────────────────────────────────────────┤
│  13. 调用自定义destroy-method            │
└─────────────────────────────────────────┘

4.2 生命周期回调

/**
 * 完整的Bean生命周期示例
 */
@Component
public class LifecycleBean implements
        BeanNameAware,
        BeanFactoryAware,
        ApplicationContextAware,
        InitializingBean,
        DisposableBean {

    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    public LifecycleBean() {
        System.out.println("1. 构造器执行");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("2. BeanNameAware.setBeanName(): " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        System.out.println("3. BeanFactoryAware.setBeanFactory()");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        System.out.println("4. ApplicationContextAware.setApplicationContext()");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("5. @PostConstruct注解的方法执行");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("6. InitializingBean.afterPropertiesSet()");
    }

    public void customInit() {
        System.out.println("7. 自定义init-method执行");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("8. @PreDestroy注解的方法执行");
    }

    @Override
    public void destroy() {
        System.out.println("9. DisposableBean.destroy()");
    }

    public void customDestroy() {
        System.out.println("10. 自定义destroy-method执行");
    }
}

/**
 * 配置Bean
 */
@Configuration
public class LifecycleConfig {

    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    public LifecycleBean lifecycleBean() {
        return new LifecycleBean();
    }
}

4.3 BeanPostProcessor

/**
 * 自定义BeanPostProcessor
 * 类似于Spring AOP的实现原理
 */
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("前置处理: " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("后置处理: " + beanName);

        // 可以返回代理对象
        if (bean instanceof UserService) {
            return createProxy(bean);
        }
        return bean;
    }

    private Object createProxy(Object target) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                System.out.println("代理方法调用: " + method.getName());
                return method.invoke(target, args);
            }
        );
    }
}

五、Bean的作用域

5.1 常见作用域

/**
 * 单例作用域(默认)
 */
@Service
@Scope("singleton")  // 可以省略
public class SingletonService {
    // 整个容器只有一个实例
}

/**
 * 原型作用域
 */
@Service
@Scope("prototype")
public class PrototypeService {
    // 每次获取都创建新实例
}

/**
 * Web环境作用域
 */
@Controller
@Scope("request")
public class RequestController {
    // 每个HTTP请求创建一个实例
}

@Controller
@Scope("session")
public class SessionController {
    // 每个HTTP会话创建一个实例
}

@Controller
@Scope("application")
public class ApplicationController {
    // 整个ServletContext一个实例
}

5.2 作用域对比

┌─────────────┬────────────────┬────────────────────┐
│  作用域      │  创建时机       │  使用场景           │
├─────────────┼────────────────┼────────────────────┤
│  singleton  │  容器启动时     │  无状态Bean         │
│  prototype  │  每次getBean   │  有状态Bean         │
│  request    │  每次HTTP请求  │  Web请求数据        │
│  session    │  每次会话       │  用户会话数据       │
│  application│  ServletContext│  应用全局数据       │
└─────────────┴────────────────┴────────────────────┘

5.3 作用域依赖问题

/**
 * 单例Bean依赖原型Bean的问题
 */
@Service
@Scope("singleton")
public class SingletonBean {

    // 问题:prototypeBean只会注入一次
    @Autowired
    private PrototypeBean prototypeBean;

    public void doSomething() {
        prototypeBean.execute();
    }
}

/**
 * 解决方案1:方法注入
 */
@Service
@Scope("singleton")
public abstract class SingletonBeanWithLookup {

    public void doSomething() {
        PrototypeBean bean = getPrototypeBean();
        bean.execute();
    }

    @Lookup
    protected abstract PrototypeBean getPrototypeBean();
}

/**
 * 解决方案2:使用Provider
 */
@Service
@Scope("singleton")
public class SingletonBeanWithProvider {

    @Autowired
    private Provider<PrototypeBean> prototypeBeanProvider;

    public void doSomething() {
        PrototypeBean bean = prototypeBeanProvider.get();
        bean.execute();
    }
}

/**
 * 解决方案3:ApplicationContext
 */
@Service
@Scope("singleton")
public class SingletonBeanWithContext {

    @Autowired
    private ApplicationContext context;

    public void doSomething() {
        PrototypeBean bean = context.getBean(PrototypeBean.class);
        bean.execute();
    }
}

六、自动装配

6.1 @Autowired注解

/**
 * @Autowired的使用
 */
@Service
public class AutowiredDemo {

    // 字段注入
    @Autowired
    private UserDao userDao;

    // 构造器注入
    private OrderDao orderDao;

    @Autowired
    public AutowiredDemo(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    // Setter注入
    private ProductDao productDao;

    @Autowired
    public void setProductDao(ProductDao productDao) {
        this.productDao = productDao;
    }

    // 可选依赖
    @Autowired(required = false)
    private OptionalService optionalService;

    // 集合注入
    @Autowired
    private List<MessageSender> senders;

    @Autowired
    private Map<String, PaymentStrategy> paymentStrategies;
}

6.2 @Qualifier注解

/**
 * 使用@Qualifier指定具体的Bean
 */
public interface MessageSender {
    void send(String message);
}

@Component("emailSender")
public class EmailSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("发送邮件: " + message);
    }
}

@Component("smsSender")
public class SmsSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("发送短信: " + message);
    }
}

@Service
public class NotificationService {

    // 使用@Qualifier指定具体的实现
    @Autowired
    @Qualifier("emailSender")
    private MessageSender emailSender;

    @Autowired
    @Qualifier("smsSender")
    private MessageSender smsSender;

    public void notify(String message, String channel) {
        if ("email".equals(channel)) {
            emailSender.send(message);
        } else if ("sms".equals(channel)) {
            smsSender.send(message);
        }
    }
}

6.3 @Primary注解

/**
 * 使用@Primary设置首选Bean
 */
@Component
@Primary  // 默认注入这个实现
public class PrimaryEmailSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("主要邮件发送器: " + message);
    }
}

@Component
public class BackupEmailSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("备用邮件发送器: " + message);
    }
}

@Service
public class EmailService {

    // 自动注入@Primary标记的Bean
    @Autowired
    private MessageSender sender;  // 注入PrimaryEmailSender
}

6.4 @Resource vs @Autowired

/**
 * @Resource@Autowired的区别
 */
@Service
public class ResourceDemo {

    // @Autowired: 按类型装配(Spring注解)
    @Autowired
    private UserDao userDao;

    // @Resource: 按名称装配(JSR-250标准)
    @Resource(name = "userDaoImpl")
    private UserDao userDaoByName;

    // @Inject: 按类型装配(JSR-330标准)
    @Inject
    private OrderDao orderDao;
}
┌──────────────┬─────────────┬──────────────┬────────────┐
  注解           来源          装配方式       required  
├──────────────┼─────────────┼──────────────┼────────────┤
  @Autowired    Spring       类型优先       支持       
  @Resource     JSR-250      名称优先       不支持     
  @Inject       JSR-330      类型优先       不支持     
└──────────────┴─────────────┴──────────────┴────────────┘

七、实战案例

7.1 案例1:多数据源配置

/**
 * 主数据源配置
 */
@Configuration
public class DataSourceConfig {

    @Bean(name = "primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "primaryJdbcTemplate")
    public JdbcTemplate primaryJdbcTemplate(
            @Qualifier("primaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "secondaryJdbcTemplate")
    public JdbcTemplate secondaryJdbcTemplate(
            @Qualifier("secondaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

/**
 * 使用多数据源
 */
@Repository
public class MultiDataSourceDao {

    @Autowired
    @Qualifier("primaryJdbcTemplate")
    private JdbcTemplate primaryJdbcTemplate;

    @Autowired
    @Qualifier("secondaryJdbcTemplate")
    private JdbcTemplate secondaryJdbcTemplate;

    public User findUserFromPrimary(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        return primaryJdbcTemplate.queryForObject(sql,
            new BeanPropertyRowMapper<>(User.class), id);
    }

    public Order findOrderFromSecondary(Long id) {
        String sql = "SELECT * FROM orders WHERE id = ?";
        return secondaryJdbcTemplate.queryForObject(sql,
            new BeanPropertyRowMapper<>(Order.class), id);
    }
}

7.2 案例2:策略模式与IoC

/**
 * 策略接口
 */
public interface PaymentStrategy {
    boolean support(String paymentType);
    void pay(Order order);
}

/**
 * 支付宝策略
 */
@Component
public class AlipayStrategy implements PaymentStrategy {

    @Override
    public boolean support(String paymentType) {
        return "ALIPAY".equals(paymentType);
    }

    @Override
    public void pay(Order order) {
        System.out.println("使用支付宝支付订单: " + order.getId());
    }
}

/**
 * 微信策略
 */
@Component
public class WechatStrategy implements PaymentStrategy {

    @Override
    public boolean support(String paymentType) {
        return "WECHAT".equals(paymentType);
    }

    @Override
    public void pay(Order order) {
        System.out.println("使用微信支付订单: " + order.getId());
    }
}

/**
 * 策略管理器
 */
@Service
public class PaymentStrategyManager {

    // Spring自动注入所有PaymentStrategy实现
    @Autowired
    private List<PaymentStrategy> strategies;

    public void pay(Order order, String paymentType) {
        PaymentStrategy strategy = strategies.stream()
            .filter(s -> s.support(paymentType))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("不支持的支付方式"));

        strategy.pay(order);
    }
}

/**
 * 使用示例
 */
@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private PaymentStrategyManager paymentManager;

    @PostMapping("/{id}/pay")
    public void payOrder(@PathVariable Long id, @RequestParam String paymentType) {
        Order order = new Order(id);
        paymentManager.pay(order, paymentType);
    }
}

7.3 案例3:条件化配置

/**
 * 自定义条件注解
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
    String name();
    String havingValue() default "";
}

/**
 * 条件判断类
 */
public class OnPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> attributes =
            metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName());

        String propertyName = (String) attributes.get("name");
        String expectedValue = (String) attributes.get("havingValue");

        Environment env = context.getEnvironment();
        String actualValue = env.getProperty(propertyName);

        return expectedValue.equals(actualValue);
    }
}

/**
 * 使用条件化配置
 */
@Configuration
public class CacheConfig {

    @Bean
    @ConditionalOnProperty(name = "cache.type", havingValue = "redis")
    public CacheService redisCacheService() {
        return new RedisCacheService();
    }

    @Bean
    @ConditionalOnProperty(name = "cache.type", havingValue = "memory")
    public CacheService memoryCacheService() {
        return new MemoryCacheService();
    }

    @Bean
    @ConditionalOnMissingBean(CacheService.class)
    public CacheService defaultCacheService() {
        return new MemoryCacheService();
    }
}

7.4 案例4:事件驱动

/**
 * 自定义事件
 */
public class UserRegisteredEvent extends ApplicationEvent {
    private User user;

    public UserRegisteredEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

/**
 * 事件监听器1:发送欢迎邮件
 */
@Component
public class WelcomeEmailListener {

    @EventListener
    public void handleUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("发送欢迎邮件给: " + user.getEmail());
    }
}

/**
 * 事件监听器2:赠送优惠券
 */
@Component
public class CouponListener {

    @EventListener
    @Async  // 异步处理
    public void handleUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("为新用户赠送优惠券: " + user.getId());
    }
}

/**
 * 事件发布者
 */
@Service
public class UserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void register(User user) {
        // 保存用户
        saveUser(user);

        // 发布事件
        UserRegisteredEvent event = new UserRegisteredEvent(this, user);
        eventPublisher.publishEvent(event);
    }

    private void saveUser(User user) {
        System.out.println("保存用户: " + user.getUsername());
    }
}

八、源码分析

8.1 容器启动流程

/**
 * ApplicationContext启动流程简化版
 */
public class SimpleApplicationContext {

    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    public void refresh() {
        // 1. 准备BeanFactory
        prepareBeanFactory();

        // 2. 加载Bean定义
        loadBeanDefinitions();

        // 3. 实例化所有单例Bean
        finishBeanFactoryInitialization();

        // 4. 完成刷新
        finishRefresh();
    }

    private void prepareBeanFactory() {
        System.out.println("准备BeanFactory");
    }

    private void loadBeanDefinitions() {
        System.out.println("加载Bean定义");
        // 扫描@Component、@Service等注解
        // 解析@Bean方法
        // 读取XML配置
    }

    private void finishBeanFactoryInitialization() {
        System.out.println("实例化单例Bean");
        for (String beanName : beanDefinitionMap.keySet()) {
            getBean(beanName);
        }
    }

    private void finishRefresh() {
        System.out.println("完成刷新,发布事件");
    }

    public Object getBean(String name) {
        // 从缓存获取
        Object bean = singletonObjects.get(name);
        if (bean != null) {
            return bean;
        }

        // 创建Bean
        BeanDefinition bd = beanDefinitionMap.get(name);
        bean = createBean(bd);

        // 放入缓存
        singletonObjects.put(name, bean);
        return bean;
    }

    private Object createBean(BeanDefinition bd) {
        // 1. 实例化
        Object bean = instantiate(bd);

        // 2. 属性注入
        populateBean(bean, bd);

        // 3. 初始化
        initializeBean(bean, bd);

        return bean;
    }

    private Object instantiate(BeanDefinition bd) {
        // 反射创建对象
        return null;
    }

    private void populateBean(Object bean, BeanDefinition bd) {
        // 注入依赖
    }

    private void initializeBean(Object bean, BeanDefinition bd) {
        // 调用初始化方法
    }
}

8.2 循环依赖解决

/**
 * 三级缓存解决循环依赖
 */
public class CircularDependencyResolver {

    // 一级缓存:成品对象
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    // 二级缓存:半成品对象
    private Map<String, Object> earlySingletonObjects = new HashMap<>();

    // 三级缓存:对象工厂
    private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    public Object getBean(String beanName) {
        // 先从一级缓存获取
        Object bean = singletonObjects.get(beanName);
        if (bean != null) {
            return bean;
        }

        // 再从二级缓存获取
        bean = earlySingletonObjects.get(beanName);
        if (bean != null) {
            return bean;
        }

        // 从三级缓存获取
        ObjectFactory<?> factory = singletonFactories.get(beanName);
        if (factory != null) {
            bean = factory.getObject();
            earlySingletonObjects.put(beanName, bean);
            singletonFactories.remove(beanName);
            return bean;
        }

        // 创建Bean
        return createBean(beanName);
    }

    private Object createBean(String beanName) {
        // 1. 实例化
        Object bean = new Object();

        // 2. 提前暴露(放入三级缓存)
        singletonFactories.put(beanName, () -> bean);

        // 3. 属性注入(可能触发循环依赖)
        populateBean(bean);

        // 4. 初始化完成,放入一级缓存
        singletonObjects.put(beanName, bean);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);

        return bean;
    }

    private void populateBean(Object bean) {
        // 注入依赖
    }
}
循环依赖解决流程
┌─────────────────────────────────────────┐
│  A依赖BB依赖A                          │
├─────────────────────────────────────────┤
│  1. 创建A,放入三级缓存                  │
│  2. 注入BA                             │
│  3. 创建B,放入三级缓存                  │
│  4. 注入AB(从三级缓存获取A)          │
│  5. B初始化完成,放入一级缓存            │
│  6. A初始化完成,放入一级缓存            │
└─────────────────────────────────────────┘

九、最佳实践

9.1 依赖注入建议

/**
 * ✅ 推荐:使用构造器注入
 */
@Service
public class GoodService {

    private final UserDao userDao;
    private final OrderDao orderDao;

    public GoodService(UserDao userDao, OrderDao orderDao) {
        this.userDao = userDao;
        this.orderDao = orderDao;
    }
}

/**
 * ❌ 不推荐:字段注入
 */
@Service
public class BadService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private OrderDao orderDao;
}

9.2 Bean命名规范

/**
 * Bean命名建议
 */
@Configuration
public class BeanNamingConfig {

    // ✅ 好的命名:清晰表达用途
    @Bean
    public DataSource primaryDataSource() {
        return new HikariDataSource();
    }

    @Bean
    public ThreadPoolExecutor asyncTaskExecutor() {
        return new ThreadPoolExecutor(10, 20, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>());
    }

    // ❌ 不好的命名:含义不清
    @Bean
    public DataSource ds1() {
        return new HikariDataSource();
    }
}

9.3 避免循环依赖

/**
 * ❌ 避免构造器循环依赖
 */
@Service
public class ServiceA {
    private final ServiceB serviceB;

    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

@Service
public class ServiceB {
    private final ServiceA serviceA;

    public ServiceB(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

/**
 * ✅ 解决方案:重新设计
 */
@Service
public class ServiceA {
    private final CommonService commonService;

    public ServiceA(CommonService commonService) {
        this.commonService = commonService;
    }
}

@Service
public class ServiceB {
    private final CommonService commonService;

    public ServiceB(CommonService commonService) {
        this.commonService = commonService;
    }
}

十、总结

核心知识点回顾

Spring IoC核心要点
│
├── 核心概念
│   ├── IoC(控制反转)
│   ├── DI(依赖注入)
│   └── 容器(BeanFactory/ApplicationContext)
│
├── 配置方式
│   ├── XML配置
│   ├── 注解配置
│   └── Java配置
│
├── 依赖注入
│   ├── 构造器注入(推荐)
│   ├── Setter注入
│   └── 字段注入
│
├── Bean管理
│   ├── 生命周期
│   ├── 作用域
│   └── 自动装配
│
└── 高级特性
    ├── 条件化配置
    ├── 事件机制
    └── 循环依赖解决

Spring IoC容器是Spring框架的核心,掌握IoC的原理和使用,是深入学习Spring其他特性的基础。在实际开发中,要灵活运用IoC的各种特性,编写松耦合、易测试、可维护的代码。