Spring IoC容器详解
一、知识概述
IoC(Inversion of Control,控制反转)是 Spring 框架的核心思想,它将对象的创建和管理权从应用程序代码转移到了容器中。DI(Dependency Injection,依赖注入)是 IoC 的实现方式,通过容器将依赖关系注入到组件中。
Spring IoC 容器主要负责:
- Bean 的实例化:创建 Bean 对象
- 依赖注入:自动装配 Bean 之间的依赖关系
- 生命周期管理:管理 Bean 的完整生命周期
- 作用域管理:控制 Bean 的作用范围
理解 IoC 容器的工作原理,是掌握 Spring 框架的基础。
二、知识点详细讲解
2.1 IoC 核心概念
控制反转(IoC)
传统开发中,对象需要主动获取依赖:
// 传统方式
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 主动创建
}
IoC 模式中,依赖由容器注入:
// IoC 方式
public class UserService {
private UserDao userDao; // 容器注入
}
依赖注入(DI)方式
- 构造器注入:通过构造方法注入依赖
- Setter 注入:通过 setter 方法注入依赖
- 字段注入:通过 @Autowired 注解直接注入字段(不推荐)
2.2 Bean 的生命周期
实例化 → 属性赋值 → 初始化 → 使用 → 销毁
│ │ │ │ │
↓ ↓ ↓ ↓ ↓
创建对象 注入依赖 调用初始化 业务方法 调用销毁
生命周期回调
-
初始化回调
@PostConstructInitializingBean.afterPropertiesSet()- 自定义 init-method
-
销毁回调
@PreDestroyDisposableBean.destroy()- 自定义 destroy-method
2.3 Bean 的作用域
| 作用域 | 描述 | 适用场景 |
|---|---|---|
| singleton | 单例,整个容器中只有一个实例 | 无状态 Bean |
| prototype | 每次获取都创建新实例 | 有状态 Bean |
| request | 每个 HTTP 请求一个实例 | Web 应用 |
| session | 每个 HTTP 会话一个实例 | Web 应用 |
| application | 整个 ServletContext 一个实例 | Web 应用 |
2.4 自动装配
装配模式
- no:不自动装配,显式指定依赖
- byName:按名称自动装配
- byType:按类型自动装配
- constructor:按构造方法自动装配
自动装配注解
- @Autowired:按类型注入,可配合 @Qualifier 指定名称
- @Resource:按名称注入(JSR-250)
- @Inject:按类型注入(JSR-330)
2.5 条件装配
Spring 4 引入了条件化装配:
- @Conditional:自定义条件
- @Profile:环境配置
- @ConditionalOnProperty:属性条件
- @ConditionalOnClass:类存在条件
- @ConditionalOnBean:Bean 存在条件
三、代码示例
3.1 依赖注入示例
示例1:构造器注入(推荐)
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
// 接口定义
public interface UserDao {
User findById(Long id);
}
// 实现类
@Repository
public class UserDaoImpl implements UserDao {
@Override
public User findById(Long id) {
return new User(id, "User-" + id);
}
}
// 服务类 - 构造器注入
@Service
public class UserService {
private final UserDao userDao;
private final OrderService orderService;
// 单构造器可省略 @Autowired
public UserService(UserDao userDao, OrderService orderService) {
this.userDao = userDao;
this.orderService = orderService;
}
public User getUser(Long id) {
return userDao.findById(id);
}
}
// 辅助类
public class User {
private Long id;
private String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "'}";
}
}
@Service
public class OrderService {
public String getOrder(Long userId) {
return "Order for user " + userId;
}
}
示例2:Setter 注入
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MessageService {
private MessageSender emailSender;
private MessageSender smsSender;
// Setter 注入 - 可选依赖
@Autowired
public void setEmailSender(MessageSender emailSender) {
this.emailSender = emailSender;
}
@Autowired(required = false) // 可选依赖
public void setSmsSender(MessageSender smsSender) {
this.smsSender = smsSender;
}
public void sendMessage(String message, String type) {
if ("email".equals(type) && emailSender != null) {
emailSender.send(message);
} else if ("sms".equals(type) && smsSender != null) {
smsSender.send(message);
}
}
}
public interface MessageSender {
void send(String message);
}
@Component
public class EmailSender implements MessageSender {
@Override
public void send(String message) {
System.out.println("发送邮件: " + message);
}
}
示例3:字段注入(不推荐)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BadPracticeService {
@Autowired // 字段注入 - 不推荐使用
private UserDao userDao;
@Autowired
private List<MessageSender> senders; // 注入所有匹配类型的 Bean
public User getUser(Long id) {
return userDao.findById(id);
}
}
// 问题:
// 1. 无法在容器外使用
// 2. 无法设置可选依赖
// 3. 难以单元测试
// 4. 违反单一职责原则
3.2 Bean 生命周期示例
import org.springframework.beans.factory.*;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
@Component
public class LifecycleBean implements InitializingBean, DisposableBean,
BeanNameAware, BeanFactoryAware {
private String beanName;
private BeanFactory beanFactory;
// 1. 实例化(构造方法)
public LifecycleBean() {
System.out.println("1. 构造方法执行");
}
// 2. BeanNameAware 回调
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("2. BeanNameAware: " + name);
}
// 3. BeanFactoryAware 回调
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
System.out.println("3. BeanFactoryAware 设置完成");
}
// 4. 属性注入(由容器完成)
// 5. @PostConstruct 初始化
@PostConstruct
public void postConstruct() {
System.out.println("5. @PostConstruct 初始化");
}
// 6. InitializingBean 回调
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6. InitializingBean.afterPropertiesSet()");
}
// 7. 自定义 init-method
public void customInit() {
System.out.println("7. 自定义 init-method");
}
// 业务方法
public void doSomething() {
System.out.println("Bean 正常工作...");
}
// 8. @PreDestroy 销毁
@PreDestroy
public void preDestroy() {
System.out.println("8. @PreDestroy 销毁");
}
// 9. DisposableBean 回调
@Override
public void destroy() throws Exception {
System.out.println("9. DisposableBean.destroy()");
}
// 10. 自定义 destroy-method
public void customDestroy() {
System.out.println("10. 自定义 destroy-method");
}
}
// 配置类
@Configuration
@ComponentScan
public class LifecycleConfig {
@Bean(initMethod = "customInit", destroyMethod = "customDestroy")
public LifecycleBean lifecycleBean() {
return new LifecycleBean();
}
}
// 测试
public class LifecycleDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(LifecycleConfig.class);
LifecycleBean bean = context.getBean(LifecycleBean.class);
bean.doSomething();
context.close();
}
}
// 输出:
// 1. 构造方法执行
// 2. BeanNameAware: lifecycleBean
// 3. BeanFactoryAware 设置完成
// 5. @PostConstruct 初始化
// 6. InitializingBean.afterPropertiesSet()
// 7. 自定义 init-method
// Bean 正常工作...
// 8. @PreDestroy 销毁
// 9. DisposableBean.destroy()
// 10. 自定义 destroy-method
3.3 Bean 作用域示例
import org.springframework.context.annotation.*;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.web.context.WebApplicationContext;
// 单例 Bean
@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class SingletonBean {
private int counter = 0;
public int increment() {
return ++counter;
}
public int getCounter() {
return counter;
}
}
// 原型 Bean
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeBean {
private String id = java.util.UUID.randomUUID().toString().substring(0, 8);
public String getId() {
return id;
}
}
// Request 作用域(Web 环境)
@Component
@Scope(WebApplicationContext.SCOPE_REQUEST)
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
private String requestId = java.util.UUID.randomUUID().toString();
public String getRequestId() {
return requestId;
}
}
// Session 作用域(Web 环境)
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionScopedBean {
private String sessionId;
private java.util.Date loginTime;
public void init(String sessionId) {
this.sessionId = sessionId;
this.loginTime = new java.util.Date();
}
public String getSessionInfo() {
return "Session: " + sessionId + ", Login: " + loginTime;
}
}
// 测试
@Configuration
@ComponentScan
public class ScopeDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ScopeDemo.class);
// 单例测试
SingletonBean singleton1 = context.getBean(SingletonBean.class);
SingletonBean singleton2 = context.getBean(SingletonBean.class);
System.out.println("单例测试:");
System.out.println("singleton1.increment() = " + singleton1.increment());
System.out.println("singleton2.increment() = " + singleton2.increment());
System.out.println("singleton1 == singleton2: " + (singleton1 == singleton2));
// 原型测试
System.out.println("\n原型测试:");
PrototypeBean prototype1 = context.getBean(PrototypeBean.class);
PrototypeBean prototype2 = context.getBean(PrototypeBean.class);
System.out.println("prototype1.id = " + prototype1.getId());
System.out.println("prototype2.id = " + prototype2.getId());
System.out.println("prototype1 == prototype2: " + (prototype1 == prototype2));
context.close();
}
}
// 输出:
// 单例测试:
// singleton1.increment() = 1
// singleton2.increment() = 2
// singleton1 == singleton2: true
//
// 原型测试:
// prototype1.id = a1b2c3d4
// prototype2.id = e5f6g7h8
// prototype1 == prototype2: false
3.4 自动装配示例
import org.springframework.beans.factory.annotation.*;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.*;
import java.util.*;
// 多个实现类的自动装配
public interface PaymentProcessor {
void process(double amount);
}
@Component
@Qualifier("alipay")
public class AlipayProcessor implements PaymentProcessor {
@Override
public void process(double amount) {
System.out.println("支付宝支付: ¥" + amount);
}
}
@Component
@Qualifier("wechat")
public class WechatPayProcessor implements PaymentProcessor {
@Override
public void process(double amount) {
System.out.println("微信支付: ¥" + amount);
}
}
@Component
@Primary // 默认选择
public class DefaultPayProcessor implements PaymentProcessor {
@Override
public void process(double amount) {
System.out.println("默认支付方式: ¥" + amount);
}
}
// 服务类 - 自动装配
@Service
public class PaymentService {
// 使用 @Primary 的 Bean
private final PaymentProcessor defaultProcessor;
// 使用 @Qualifier 指定 Bean
private final PaymentProcessor alipayProcessor;
// 注入所有匹配类型的 Bean
private final Map<String, PaymentProcessor> processorMap;
public PaymentService(
@Autowired PaymentProcessor defaultProcessor,
@Autowired @Qualifier("alipay") PaymentProcessor alipayProcessor,
@Autowired Map<String, PaymentProcessor> processorMap) {
this.defaultProcessor = defaultProcessor;
this.alipayProcessor = alipayProcessor;
this.processorMap = processorMap;
}
public void payDefault(double amount) {
defaultProcessor.process(amount);
}
public void payByAlipay(double amount) {
alipayProcessor.process(amount);
}
public void payByType(String type, double amount) {
PaymentProcessor processor = processorMap.get(type + "PayProcessor");
if (processor != null) {
processor.process(amount);
} else {
System.out.println("不支持的支付方式: " + type);
}
}
}
@Configuration
@ComponentScan
public class AutowireDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AutowireDemo.class);
PaymentService service = context.getBean(PaymentService.class);
service.payDefault(100);
service.payByAlipay(200);
service.payByType("wechat", 300);
context.close();
}
}
// 输出:
// 默认支付方式: ¥100.0
// 支付宝支付: ¥200.0
// 微信支付: ¥300.0
3.5 条件装配示例
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.boot.autoconfigure.condition.*;
// 自定义条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
String name();
String value();
}
// 自定义条件
class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(
ConditionalOnSystemProperty.class.getName());
String name = (String) attributes.get("name");
String value = (String) attributes.get("value");
String systemValue = System.getProperty(name);
return value.equals(systemValue);
}
}
// 条件装配的 Bean
@Configuration
public class ConditionalConfig {
@Bean
@ConditionalOnSystemProperty(name = "env", value = "dev")
public DataSource devDataSource() {
return new DataSource("dev-db", "dev-user");
}
@Bean
@ConditionalOnSystemProperty(name = "env", value = "prod")
public DataSource prodDataSource() {
return new DataSource("prod-db", "prod-user");
}
@Bean
@ConditionalOnClass(name = "java.sql.Driver")
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public FeatureService featureService() {
return new FeatureService();
}
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() {
return new DataSource("default-db", "default-user");
}
}
// 数据源模拟类
public class DataSource {
private final String url;
private final String username;
public DataSource(String url, String username) {
this.url = url;
this.username = username;
}
@Override
public String toString() {
return "DataSource{url='" + url + "', username='" + username + "'}";
}
}
public class JdbcTemplate {
private final DataSource dataSource;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
}
public class FeatureService {
public void doSomething() {
System.out.println("Feature enabled!");
}
}
// Profile 示例
@Configuration
public class ProfileConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new DataSource("jdbc:mysql://localhost:3306/dev", "dev");
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
return new DataSource("jdbc:mysql://prod-server:3306/prod", "prod");
}
@Bean
@Profile("test")
public DataSource testDataSource() {
return new DataSource("jdbc:h2:mem:testdb", "sa");
}
}
// 测试
public class ConditionalDemo {
public static void main(String[] args) {
// 设置环境
System.setProperty("env", "dev");
System.setProperty("feature.enabled", "true");
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ConditionalConfig.class);
DataSource dataSource = context.getBean(DataSource.class);
System.out.println("DataSource: " + dataSource);
if (context.containsBean("featureService")) {
FeatureService feature = context.getBean(FeatureService.class);
feature.doSomething();
}
context.close();
}
}
3.6 循环依赖解决
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;
// 循环依赖示例
@Component
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void doSomething() {
System.out.println("ServiceA working");
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
public void doSomething() {
System.out.println("ServiceB working");
}
}
// 解决方案1:使用 @Lazy
@Component
public class ServiceA2 {
private final ServiceB2 serviceB;
@Autowired
public ServiceA2(@Lazy ServiceB2 serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB2 {
private final ServiceA2 serviceA;
@Autowired
public ServiceB2(ServiceA2 serviceA) {
this.serviceA = serviceA;
}
}
// 解决方案2:使用 Setter 注入
@Component
public class ServiceA3 {
private ServiceB3 serviceB;
@Autowired
public void setServiceB(ServiceB3 serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB3 {
private ServiceA3 serviceA;
@Autowired
public void setServiceA(ServiceA3 serviceA) {
this.serviceA = serviceA;
}
}
// 解决方案3:重构设计,避免循环依赖
public interface CommonService {
void doSomething();
}
@Component
public class ServiceA4 {
private final CommonService commonService;
public ServiceA4(CommonService commonService) {
this.commonService = commonService;
}
}
@Component
public class ServiceB4 implements CommonService {
@Override
public void doSomething() {
System.out.println("ServiceB working");
}
}
// 测试
@Configuration
@ComponentScan
public class CircularDependencyDemo {
public static void main(String[] args) {
try {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(CircularDependencyDemo.class);
System.out.println("容器启动成功");
ServiceA2 serviceA = context.getBean(ServiceA2.class);
serviceA.doSomething();
context.close();
} catch (Exception e) {
System.out.println("循环依赖异常: " + e.getMessage());
}
}
}
四、实战应用场景
4.1 分层架构的依赖注入
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.context.annotation.*;
import java.util.*;
// 实体类
public class User {
private Long id;
private String username;
private String email;
// 构造器、getter、setter
public User() {}
public User(Long id, String username, String email) {
this.id = id;
this.username = username;
this.email = email;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
@Override
public String toString() {
return "User{id=" + id + ", username='" + username + "', email='" + email + "'}";
}
}
// Repository 层
public interface UserRepository {
User findById(Long id);
User save(User user);
List<User> findAll();
}
@Repository
public class UserRepositoryImpl implements UserRepository {
private final Map<Long, User> storage = new HashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
@Override
public User findById(Long id) {
return storage.get(id);
}
@Override
public User save(User user) {
if (user.getId() == null) {
user.setId(idGenerator.getAndIncrement());
}
storage.put(user.getId(), user);
return user;
}
@Override
public List<User> findAll() {
return new ArrayList<>(storage.values());
}
}
// Service 层
public interface UserService {
User getUser(Long id);
User createUser(String username, String email);
List<User> getAllUsers();
}
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final NotificationService notificationService;
public UserServiceImpl(UserRepository userRepository,
NotificationService notificationService) {
this.userRepository = userRepository;
this.notificationService = notificationService;
}
@Override
public User getUser(Long id) {
return userRepository.findById(id);
}
@Override
public User createUser(String username, String email) {
User user = new User(null, username, email);
User saved = userRepository.save(user);
notificationService.notifyUserCreated(saved);
return saved;
}
@Override
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
// 通知服务
public interface NotificationService {
void notifyUserCreated(User user);
}
@Service
public class EmailNotificationService implements NotificationService {
@Override
public void notifyUserCreated(User user) {
System.out.println("发送邮件通知: 用户 " + user.getUsername() + " 已创建");
}
}
// 配置类
@Configuration
@ComponentScan
public class LayeredArchitectureDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(LayeredArchitectureDemo.class);
UserService userService = context.getBean(UserService.class);
// 创建用户
User user1 = userService.createUser("张三", "zhangsan@example.com");
User user2 = userService.createUser("李四", "lisi@example.com");
// 查询用户
System.out.println("\n所有用户:");
userService.getAllUsers().forEach(System.out::println);
context.close();
}
}
4.2 多数据源配置
import org.springframework.context.annotation.*;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.util.Map;
import java.util.HashMap;
// 数据源配置
@Configuration
public class MultiDataSourceConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
// 简化示例
@Bean
@Primary
public DataSource primaryDataSourceSimple() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/primary_db");
ds.setUsername("root");
ds.setPassword("password");
return ds;
}
@Bean
public DataSource secondaryDataSourceSimple() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/secondary_db");
ds.setUsername("root");
ds.setPassword("password");
return ds;
}
}
// 动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void setDataSource(String name) {
CONTEXT.set(name);
}
public static void clearDataSource() {
CONTEXT.remove();
}
@Override
protected Object determineCurrentLookupKey() {
return CONTEXT.get();
}
}
// 动态数据源配置
@Configuration
public class DynamicDataSourceConfig {
@Bean
public DataSource dynamicDataSource(
DataSource primaryDataSource,
DataSource secondaryDataSource) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("primary", primaryDataSource);
targetDataSources.put("secondary", secondaryDataSource);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(primaryDataSource);
return dynamicDataSource;
}
}
// 数据源切换注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value() default "primary";
}
// 切面实现
@Aspect
@Component
public class DataSourceAspect {
@Around("@annotation(dataSource)")
public Object around(ProceedingJoinPoint point, DataSource dataSource) throws Throwable {
try {
DynamicDataSource.setDataSource(dataSource.value());
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
}
// 使用示例
@Service
public class OrderService {
@DataSource("primary")
public void saveOrder(Order order) {
// 使用主数据源
}
@DataSource("secondary")
public List<Order> queryOrders() {
// 使用从数据源
return new ArrayList<>();
}
}
五、IoC 容器实现原理
5.1 容器启动流程
1. Resource 定位 → 找到配置文件
2. BeanDefinition 加载 → 解析配置,生成 BeanDefinition
3. BeanDefinition 注册 → 注册到 BeanDefinitionRegistry
4. Bean 实例化 → 创建 Bean 实例
5. 依赖注入 → 注入依赖关系
6. 生命周期回调 → 执行初始化回调
5.2 BeanFactory vs ApplicationContext
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 实例化时机 | 延迟实例化 | 启动时实例化 |
| 国际化 | 不支持 | 支持 |
| 事件发布 | 不支持 | 支持 |
| AOP 集成 | 需手动配置 | 自动支持 |
| 资源访问 | 不支持 | 支持 |
5.3 BeanPostProcessor 扩展点
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@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 java.lang.reflect.Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("Before: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After: " + method.getName());
return result;
}
);
}
}
六、总结与最佳实践
最佳实践
-
依赖注入方式选择
- 构造器注入:强制依赖
- Setter 注入:可选依赖
- 避免字段注入
-
作用域选择
- 无状态 Bean:singleton(默认)
- 有状态 Bean:prototype
- Web 请求相关:request/session
-
循环依赖避免
- 重构设计,消除循环依赖
- 使用 @Lazy 延迟加载
- 使用 Setter 注入
-
配置方式选择
- 简单配置:@Component + @ComponentScan
- 复杂配置:@Configuration + @Bean
- 条件配置:@Conditional 系列
常见问题
-
NoSuchBeanDefinitionException
- 检查组件扫描配置
- 检查 Bean 名称匹配
-
NoUniqueBeanDefinitionException
- 使用 @Primary 或 @Qualifier
-
BeanCreationException
- 检查构造方法参数
- 检查循环依赖
-
BeanCurrentlyInCreationException
- 存在循环依赖
- 使用 @Lazy 解决
Spring IoC 容器是 Spring 框架的核心,理解其工作原理对于正确使用 Spring 至关重要。通过依赖注入,可以实现松耦合、易测试的代码结构,提高代码的可维护性和可扩展性。