深入理解依赖注入、Bean 生命周期与容器核心机制
IoC(Inversion of Control,控制反转)是一种设计思想,将对象的创建、配置和生命周期管理的控制权从应用程序代码转移到外部容器(如 Spring IoC 容器)。
DI(Dependency Injection,依赖注入)是实现 IoC 的一种具体方式,通过容器在运行时动态地将依赖关系注入到对象中。
// 传统方式:对象自己创建依赖
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 紧耦合
public void saveUser(User user) {
userDao.save(user);
}
}
// IoC 方式:依赖由容器注入
@Service
public class UserService {
@Autowired
private UserDao userDao; // 松耦合,由 Spring 容器注入
public void saveUser(User user) {
userDao.save(user);
}
}
Spring 提供了两种主要的 IoC 容器:
| 对比维度 | BeanFactory | ApplicationContext |
|---|---|---|
| 加载方式 | 延迟加载(Lazy) | 立即加载(Eager) |
| Bean 创建时机 | 首次调用 getBean() 时 | 容器启动时(单例) |
| 国际化支持 | ❌ 不支持 | ✅ 支持 MessageSource |
| 事件发布 | ❌ 不支持 | ✅ 支持 ApplicationEvent |
| 资源访问 | ❌ 不支持 | ✅ 支持 ResourceLoader |
| AOP 支持 | 需要手动配置 | 自动支持 |
| 内存占用 | 较小 | 较大 |
// 1. BeanFactory 使用示例
Resource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
UserService userService = (UserService) factory.getBean("userService"); // 此时才创建 Bean
// 2. ApplicationContext 使用示例(推荐)
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean(UserService.class); // Bean 已在容器启动时创建
// 3. ApplicationContext 的三种常见实现
// 3.1 从类路径加载配置文件
ApplicationContext context1 = new ClassPathXmlApplicationContext("applicationContext.xml");
// 3.2 从文件系统加载配置文件
ApplicationContext context2 = new FileSystemXmlApplicationContext("C:/config/beans.xml");
// 3.3 基于注解的配置(最常用)
ApplicationContext context3 = new AnnotationConfigApplicationContext(AppConfig.class);
@Service
public class UserService {
private final UserDao userDao;
private final EmailService emailService;
// 推荐:使用构造器注入
@Autowired // Spring 4.3+ 单构造器可省略
public UserService(UserDao userDao, EmailService emailService) {
this.userDao = userDao;
this.emailService = emailService;
}
}
✅ 优点:
❌ 缺点:
@Service
public class UserService {
private UserDao userDao;
private EmailService emailService;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Autowired(required = false) // 可选依赖
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
}
✅ 优点:
❌ 缺点:
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private EmailService emailService;
}
✅ 优点:
❌ 缺点:
@Service
public class UserService {
// 1. 必需依赖使用构造器注入(推荐)
private final UserDao userDao;
private final CacheService cacheService;
// 2. 可选依赖使用 Setter 注入
private EmailService emailService;
@Autowired
public UserService(UserDao userDao, CacheService cacheService) {
this.userDao = userDao;
this.cacheService = cacheService;
}
@Autowired(required = false)
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
public void saveUser(User user) {
userDao.save(user);
cacheService.put(user.getId(), user);
// 可选依赖需要判空
if (emailService != null) {
emailService.sendWelcomeEmail(user);
}
}
}
Spring Bean 的生命周期可以分为以下几个阶段:
@Component
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private String name;
// 1. 构造器
public LifecycleBean() {
System.out.println("1. 构造器:Bean 实例化");
}
// 2. 属性注入
@Autowired
public void setName(String name) {
this.name = name;
System.out.println("2. 属性注入:setName()");
}
// 3. Aware 接口回调
@Override
public void setBeanName(String name) {
System.out.println("3.1 BeanNameAware:setBeanName()");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3.2 BeanFactoryAware:setBeanFactory()");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("3.3 ApplicationContextAware:setApplicationContext()");
}
// 4. 初始化前置处理(由 BeanPostProcessor 实现)
// postProcessBeforeInitialization()
// 5. InitializingBean 接口
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5. InitializingBean:afterPropertiesSet()");
}
// 6. 自定义初始化方法
@PostConstruct
public void init() {
System.out.println("6. @PostConstruct:自定义初始化方法");
}
// 7. 初始化后置处理(由 BeanPostProcessor 实现)
// postProcessAfterInitialization()
// 8. Bean 使用中...
// 9. DisposableBean 接口
@Override
public void destroy() throws Exception {
System.out.println("9. DisposableBean:destroy()");
}
// 10. 自定义销毁方法
@PreDestroy
public void cleanup() {
System.out.println("10. @PreDestroy:自定义销毁方法");
}
}
// BeanPostProcessor 示例
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof LifecycleBean) {
System.out.println("4. BeanPostProcessor:postProcessBeforeInitialization()");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof LifecycleBean) {
System.out.println("7. BeanPostProcessor:postProcessAfterInitialization()");
}
return bean;
}
}
容器启动
↓
实例化 Bean(构造器)
↓
属性注入(@Autowired / setter)
↓
BeanNameAware.setBeanName()
↓
BeanFactoryAware.setBeanFactory()
↓
ApplicationContextAware.setApplicationContext()
↓
BeanPostProcessor.postProcessBeforeInitialization()
↓
@PostConstruct 方法
↓
InitializingBean.afterPropertiesSet()
↓
自定义 init-method
↓
BeanPostProcessor.postProcessAfterInitialization()
↓
Bean 就绪,可以使用
↓
容器关闭
↓
@PreDestroy 方法
↓
DisposableBean.destroy()
↓
自定义 destroy-method
↓
Bean 销毁
整个 Spring IoC 容器中只有一个 Bean 实例,所有请求共享同一个对象。
@Component
@Scope("singleton") // 默认,可省略
public class UserService {
// 容器中只有一个 UserService 实例
}
特点:
每次请求都会创建一个新的 Bean 实例。
@Component
@Scope("prototype")
public class ShoppingCart {
// 每次 getBean() 都会创建新实例
}
特点:
每个 HTTP 请求创建一个 Bean 实例,请求结束后销毁。
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class LoginInfo {
// 每个 HTTP 请求都有独立的 LoginInfo 实例
}
每个 HTTP Session 创建一个 Bean 实例,Session 结束后销毁。
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
// 每个用户会话都有独立的 UserSession 实例
}
整个 ServletContext 生命周期内只有一个 Bean 实例。
@Component
@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AppConfig {
// 整个 Web 应用只有一个 AppConfig 实例
}
每个 WebSocket 连接创建一个 Bean 实例。
// 测试 singleton vs prototype
@SpringBootTest
public class ScopeTest {
@Autowired
private ApplicationContext context;
@Test
public void testSingleton() {
UserService service1 = context.getBean(UserService.class);
UserService service2 = context.getBean(UserService.class);
System.out.println(service1 == service2); // true - 同一个实例
}
@Test
public void testPrototype() {
ShoppingCart cart1 = context.getBean(ShoppingCart.class);
ShoppingCart cart2 = context.getBean(ShoppingCart.class);
System.out.println(cart1 == cart2); // false - 不同实例
}
}
// 在 singleton Bean 中注入 prototype Bean 的问题
@Component
public class OrderService {
@Autowired
private ShoppingCart cart; // 问题:cart 只会注入一次!
// 解决方案1:使用 @Lookup 方法注入
@Lookup
public ShoppingCart getCart() {
return null; // Spring 会动态实现这个方法
}
// 解决方案2:注入 ApplicationContext
@Autowired
private ApplicationContext context;
public void processOrder() {
ShoppingCart cart = context.getBean(ShoppingCart.class);
// 使用 cart...
}
}
| 作用域 | 创建时机 | 销毁时机 | 适用场景 |
|---|---|---|---|
| singleton | 容器启动 | 容器关闭 | 无状态 Bean |
| prototype | 每次 getBean() | 不管理 | 有状态 Bean |
| request | HTTP 请求开始 | HTTP 请求结束 | 请求级数据 |
| session | Session 创建 | Session 销毁 | 用户会话数据 |
@Component
public class A {
@Autowired
private B b; // A 依赖 B
}
@Component
public class B {
@Autowired
private A a; // B 依赖 A
}
public class DefaultSingletonBeanRegistry {
// 一级缓存:存放完全初始化好的单例 Bean
private final Map singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:存放早期暴露的 Bean(已实例化但未初始化)
private final Map earlySingletonObjects = new HashMap<>(16);
// 三级缓存:存放 Bean 工厂对象
private final Map> singletonFactories = new HashMap<>(16);
protected Object getSingleton(String beanName) {
// 1. 从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 从二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 3. 从三级缓存获取
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 从三级缓存移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}
@Component
public class UserService implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private String name;
// 1. 构造器
public UserService() {
System.out.println("1. 构造器执行");
}
// 2. 属性注入
@Autowired
public void setUserDao(UserDao userDao) {
System.out.println("2. 属性注入");
}
// 3. BeanNameAware
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware.setBeanName()");
this.name = name;
}
// 4. BeanFactoryAware
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("4. BeanFactoryAware.setBeanFactory()");
}
// 5. ApplicationContextAware
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
System.out.println("5. ApplicationContextAware.setApplicationContext()");
}
// 6. BeanPostProcessor.postProcessBeforeInitialization()
// 由 Spring 容器调用
// 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 initMethod() {
System.out.println("9. init-method");
}
// 10. BeanPostProcessor.postProcessAfterInitialization()
// 由 Spring 容器调用(AOP 代理在这里创建)
// Bean 使用中...
// 11. @PreDestroy
@PreDestroy
public void preDestroy() {
System.out.println("11. @PreDestroy");
}
// 12. DisposableBean.destroy()
@Override
public void destroy() {
System.out.println("12. DisposableBean.destroy()");
}
// 13. destroy-method
public void destroyMethod() {
System.out.println("13. destroy-method");
}
}
@Configuration
public class BeanConfig {
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public UserService userService() {
return new UserService();
}
}
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring | JDK (JSR-250) |
| 装配方式 | byType | byName → byType |
| required | 支持(默认 true) | 不支持 |
| 作用位置 | 字段、构造器、方法 | 字段、方法 |
@Service
public class UserService {
// 1. 字段注入(不推荐)
@Autowired
private UserDao userDao;
// 2. 构造器注入(推荐)
private final UserDao userDao;
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
// 3. Setter 注入
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
// 4. 多个实现时指定名称
@Autowired
@Qualifier("mysqlUserDao")
private UserDao userDao;
// 5. 可选注入
@Autowired(required = false)
private Optional userDao;
}
@Service
public class UserService {
// 1. 默认按名称注入
@Resource
private UserDao userDao; // 查找名为 "userDao" 的 Bean
// 2. 指定名称
@Resource(name = "mysqlUserDao")
private UserDao userDao;
// 3. 按类型注入(找不到同名 Bean 时)
@Resource
private UserDao dao; // 按类型查找 UserDao
}
@Configuration
public class DataSourceConfig {
// 1. @ConditionalOnProperty:根据配置属性
@Bean
@ConditionalOnProperty(name = "datasource.type", havingValue = "mysql")
public DataSource mysqlDataSource() {
return new MysqlDataSource();
}
// 2. @ConditionalOnClass:类存在时
@Bean
@ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
public DataSource dataSource() {
return new DataSource();
}
// 3. @ConditionalOnMissingBean:Bean 不存在时
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() {
return new H2DataSource();
}
// 4. @ConditionalOnBean:Bean 存在时
@Bean
@ConditionalOnBean(DataSource.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// 5. @Profile:环境配置
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new H2DataSource();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
return new MysqlDataSource();
}
}
// 1. 实现 Condition 接口
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String os = context.getEnvironment().getProperty("os.name");
return os != null && os.toLowerCase().contains("linux");
}
}
// 2. 使用自定义条件
@Configuration
public class AppConfig {
@Bean
@Conditional(LinuxCondition.class)
public Service linuxService() {
return new LinuxService();
}
}
// 用于自己编写的类
@Component
public class UserService {
@Autowired
private UserDao userDao;
public void save(User user) {
userDao.save(user);
}
}
// 衍生注解
@Service // 业务层
@Repository // 数据访问层
@Controller // 控制层
@RestController // REST 控制层
// 用于第三方类或需要复杂初始化的类
@Configuration
public class AppConfig {
// 1. 第三方类
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/db");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
// 2. 需要参数的 Bean
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// 3. 条件装配
@Bean
@ConditionalOnMissingBean
public UserService userService() {
return new UserService();
}
}
| 特性 | @Component | @Bean |
|---|---|---|
| 作用位置 | 类上 | 方法上 |
| 适用场景 | 自己编写的类 | 第三方类 |
| 扫描方式 | 组件扫描 | 配置类 |
| 灵活性 | 较低 | 较高 |
@Configuration
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService() {
// 多次调用 userDao() 返回同一个实例
UserService service = new UserService();
service.setUserDao(userDao()); // 第一次调用
service.setUserDao(userDao()); // 第二次调用,返回同一个实例
return service;
}
}
// Spring 会为 @Configuration 类创建 CGLIB 代理
// 拦截 @Bean 方法调用,保证单例
@Component
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService() {
// 多次调用 userDao() 返回不同实例
UserService service = new UserService();
service.setUserDao(userDao()); // 第一次调用,创建新实例
service.setUserDao(userDao()); // 第二次调用,又创建新实例
return service;
}
}
// Spring 不会为 @Component 类创建代理
// 直接调用方法,每次都创建新实例
// Lite 模式:不创建代理,提升性能
@Configuration(proxyBeanMethods = false)
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService(UserDao userDao) {
// 通过参数注入,而不是方法调用
return new UserService(userDao);
}
}
// ApplicationContext 继承 BeanFactory
public interface ApplicationContext extends
EnvironmentCapable, // 环境配置
ListableBeanFactory, // 列举 Bean
HierarchicalBeanFactory, // 分层
MessageSource, // 国际化
ApplicationEventPublisher, // 事件发布
ResourcePatternResolver // 资源加载
{
// ...
}
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 加载方式 | 延迟加载 | 立即加载 |
| 国际化 | 不支持 | 支持 |
| 事件机制 | 不支持 | 支持 |
| BeanPostProcessor | 需手动注册 | 自动注册 |
| 资源加载 | 不支持 | 支持 |
// 延迟加载
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
// 获取 Bean 时才创建
UserService service = factory.getBean(UserService.class);
// 立即加载(容器启动时创建所有单例 Bean)
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 或使用注解配置
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// Bean 已经创建好了
UserService service = context.getBean(UserService.class);
// 国际化
String message = context.getMessage("welcome", null, Locale.CHINA);
// 事件发布
context.publishEvent(new UserRegisteredEvent(user));
// 资源加载
Resource resource = context.getResource("classpath:config.properties");
// 继承 ApplicationEvent
public class UserRegisteredEvent extends ApplicationEvent {
private 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 void register(User user) {
// 保存用户
userDao.save(user);
// 发布事件
eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
}
}
// 方式1:实现 ApplicationListener 接口
@Component
public class EmailListener implements ApplicationListener {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
User user = event.getUser();
// 发送欢迎邮件
emailService.sendWelcomeEmail(user.getEmail());
}
}
// 方式2:使用 @EventListener 注解(推荐)
@Component
public class UserEventListener {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
User user = event.getUser();
// 发送欢迎邮件
emailService.sendWelcomeEmail(user.getEmail());
}
// 异步监听
@Async
@EventListener
public void handleUserRegisteredAsync(UserRegisteredEvent event) {
// 异步处理
}
// 条件监听
@EventListener(condition = "#event.user.vip == true")
public void handleVipUserRegistered(UserRegisteredEvent event) {
// 只处理 VIP 用户
}
}
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("event-");
executor.initialize();
return executor;
}
}
// 默认情况下,单例 Bean 在容器启动时创建
@Component
public class HeavyService {
public HeavyService() {
System.out.println("HeavyService 创建(容器启动时)");
// 执行耗时的初始化操作...
}
}
// 延迟到第一次使用时才创建
@Component
@Lazy
public class HeavyService {
public HeavyService() {
System.out.println("HeavyService 创建(第一次使用时)");
}
}
// 在注入时使用 @Lazy
@Service
public class UserService {
@Autowired
@Lazy
private HeavyService heavyService; // 注入代理对象,延迟创建
public void doSomething() {
heavyService.process(); // 第一次调用时才创建 HeavyService
}
}
@Configuration
public class AppConfig {
// 所有 Bean 都延迟加载
@Bean
public static LazyInitializationBeanFactoryPostProcessor lazyInit() {
return new LazyInitializationBeanFactoryPostProcessor();
}
}
// 或在 application.properties 中配置
// spring.main.lazy-initialization=true
@Component
public class A {
@Autowired
@Lazy // 延迟注入,解决循环依赖
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
# messages.properties(默认)
welcome=Welcome
user.name=Username
user.password=Password
# messages_zh_CN.properties(中文)
welcome=欢迎
user.name=用户名
user.password=密码
# messages_en_US.properties(英文)
welcome=Welcome
user.name=Username
user.password=Password
@Configuration
public class I18nConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.CHINA);
return resolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang"); // URL 参数名
return interceptor;
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LocaleChangeInterceptor localeChangeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor);
}
}
@RestController
public class UserController {
@Autowired
private MessageSource messageSource;
@GetMapping("/welcome")
public String welcome(Locale locale) {
// 根据 locale 获取对应语言的消息
return messageSource.getMessage("welcome", null, locale);
}
@GetMapping("/user/error")
public String error(Locale locale) {
// 带参数的消息
return messageSource.getMessage("user.not.found",
new Object[]{"张三"}, locale);
}
}
// 访问示例:
// http://localhost:8080/welcome?lang=zh_CN // 返回"欢迎"
// http://localhost:8080/welcome?lang=en_US // 返回"Welcome"
<!-- Thymeleaf -->
<h1 th:text="#{welcome}"></h1>
<label th:text="#{user.name}"></label>
<!-- JSP -->
<spring:message code="welcome"/>
<spring:message code="user.name"/>