Skip to content

Spring Core / IoC 容器

Spring IoC 容器是整个 Spring 生态的基础。理解 Bean 的生命周期和依赖注入原理,是掌握 Spring 的关键。

IoC 与 DI

IoC(控制反转):对象的创建和依赖关系的管理,从代码中转移到容器。

DI(依赖注入):容器在创建对象时,自动注入其依赖的其他对象。

java
// 传统方式:手动创建依赖
public class OrderService {
    private UserRepository userRepo = new UserRepositoryImpl();  // 强耦合
    private OrderRepository orderRepo = new OrderRepositoryImpl();
}

// IoC 方式:依赖由容器注入
@Service
public class OrderService {
    private final UserRepository userRepo;
    private final OrderRepository orderRepo;

    // 构造器注入(推荐)
    public OrderService(UserRepository userRepo, OrderRepository orderRepo) {
        this.userRepo = userRepo;
        this.orderRepo = orderRepo;
    }
}

ApplicationContext

java
// ApplicationContext 是 Spring IoC 容器的核心接口
// 常用实现:
// - AnnotationConfigApplicationContext(注解配置)
// - ClassPathXmlApplicationContext(XML 配置,旧式)
// - AnnotationConfigWebApplicationContext(Web 应用)

@Configuration
@ComponentScan("com.example")
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        return ds;
    }
}

// 启动容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = ctx.getBean(OrderService.class);

Bean 的三种注入方式

java
@Service
public class UserService {

    // 1. 构造器注入(推荐)
    // 优点:依赖不可变,便于测试,避免循环依赖
    private final UserRepository userRepo;
    private final EmailService emailService;

    public UserService(UserRepository userRepo, EmailService emailService) {
        this.userRepo = userRepo;
        this.emailService = emailService;
    }

    // 2. Setter 注入(可选依赖)
    private NotificationService notificationService;

    @Autowired(required = false)
    public void setNotificationService(NotificationService ns) {
        this.notificationService = ns;
    }

    // 3. 字段注入(不推荐,但常见)
    // 缺点:无法在非 Spring 环境测试,隐藏依赖关系
    @Autowired
    private AuditService auditService;
}

Bean 的作用域

java
// singleton(默认):容器中只有一个实例
@Bean
@Scope("singleton")
public UserService userService() { ... }

// prototype:每次获取都创建新实例
@Bean
@Scope("prototype")
public ShoppingCart shoppingCart() { ... }

// request:每个 HTTP 请求一个实例(Web 应用)
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST,
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public RequestContext requestContext() { ... }

// session:每个 HTTP Session 一个实例
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION,
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public UserSession userSession() { ... }

Bean 生命周期

实例化(Instantiation)

属性填充(Populate Properties)

BeanNameAware.setBeanName()

BeanFactoryAware.setBeanFactory()

ApplicationContextAware.setApplicationContext()

BeanPostProcessor.postProcessBeforeInitialization()

@PostConstruct / InitializingBean.afterPropertiesSet() / init-method

BeanPostProcessor.postProcessAfterInitialization()

Bean 就绪,可以使用

容器关闭

@PreDestroy / DisposableBean.destroy() / destroy-method
java
@Component
public class DatabasePool implements InitializingBean, DisposableBean {

    private ConnectionPool pool;

    @PostConstruct
    public void init() {
        System.out.println("1. @PostConstruct 初始化");
        pool = new ConnectionPool();
        pool.initialize();
    }

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

    @PreDestroy
    public void cleanup() {
        System.out.println("3. @PreDestroy 清理");
        pool.shutdown();
    }

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

BeanPostProcessor — 扩展点

java
// BeanPostProcessor 是 Spring 最重要的扩展点之一
// AOP、@Autowired、@Value 等都通过它实现

@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("初始化前: " + beanName);
        return bean;  // 可以返回代理对象
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("初始化后: " + beanName);
        // AOP 就在这里创建代理对象
        return bean;
    }
}

条件注册

java
// @Conditional — 条件化 Bean 注册
@Configuration
public class DataSourceConfig {

    // 只在有 MySQL 驱动时注册
    @Bean
    @ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
    public DataSource mysqlDataSource() { ... }

    // 只在配置了 app.datasource.url 时注册
    @Bean
    @ConditionalOnProperty(prefix = "app.datasource", name = "url")
    public DataSource customDataSource() { ... }

    // 只在没有其他 DataSource Bean 时注册
    @Bean
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource defaultDataSource() { ... }

    // 只在特定 Profile 激活时注册
    @Bean
    @Profile("production")
    public DataSource productionDataSource() { ... }
}

@Value 与 @ConfigurationProperties

java
// @Value 注入单个配置
@Component
public class AppConfig {
    @Value("${app.name:MyApp}")          // 带默认值
    private String appName;

    @Value("${app.max-connections:100}")
    private int maxConnections;

    @Value("#{systemProperties['user.home']}")  // SpEL 表达式
    private String userHome;
}

// @ConfigurationProperties 绑定配置组(推荐)
@ConfigurationProperties(prefix = "app.database")
@Component
public class DatabaseProperties {
    private String url;
    private String username;
    private String password;
    private int maxPoolSize = 10;
    private Duration connectionTimeout = Duration.ofSeconds(30);

    // getter/setter 或使用 @ConstructorBinding(不可变)
}
yaml
# application.yml
app:
  database:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret
    max-pool-size: 20
    connection-timeout: 30s

事件机制

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

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

    public User getUser() { return user; }
}

// 发布事件
@Service
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public User register(RegisterRequest req) {
        User user = createUser(req);
        eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
        return user;
    }
}

// 监听事件
@Component
public class EmailNotificationListener {

    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        sendWelcomeEmail(event.getUser());
    }

    // 异步监听
    @EventListener
    @Async
    public void onUserRegisteredAsync(UserRegisteredEvent event) {
        sendSmsNotification(event.getUser());
    }

    // 条件监听
    @EventListener(condition = "#event.user.vip == true")
    public void onVipUserRegistered(UserRegisteredEvent event) {
        sendVipGift(event.getUser());
    }
}

IoC 最佳实践

  1. 优先使用构造器注入,保证依赖不可变
  2. 避免循环依赖(构造器注入会在启动时报错,及早发现)
  3. 使用 @ConfigurationProperties 而非大量 @Value
  4. 合理使用 @Profile 区分环境配置
  5. 善用 @Conditional 实现灵活的条件装配

系统学习 Java 生态,深入底层架构