【spring原理】Bean的作用域与生命周期

Bean的作用域

在编程中,Bean的作用域(Scope) 是指一个Bean对象的生命周期及其在应用上下文中的可见性。特别是在Spring框架中,Bean的作用域决定了一个Bean是如何被创建、共享和销毁的。以下是Spring中常用的Bean作用域及其特点:


1. Singleton(单例,默认作用域)

  • 描述: 整个Spring容器中仅存在一个共享的Bean实例。
  • 特点 :
    • 每次请求该Bean时,都会返回同一个实例。
    • 默认作用域,适用于无状态的Bean。
  • 应用场景: 大多数服务类、工具类、无状态组件。

2. Prototype(原型)

  • 描述: 每次请求时都会创建一个新的Bean实例。
  • 特点 :
    • 每次注入或通过ApplicationContext.getBean()获取时,都会返回一个新的对象。
    • Spring容器只负责创建实例,生命周期交由调用方管理。
  • 应用场景: 需要保持独立状态的组件,例如每个用户的会话对象。

3. Request

  • 描述: 在Web应用中,为每个HTTP请求创建一个新的Bean实例。
  • 特点 :
    • 每个HTTP请求会对应一个独立的Bean实例。
    • 仅在请求周期内有效,请求结束后自动销毁。
  • 应用场景: 与单个HTTP请求相关的状态信息。

4. Session

  • 描述: 在Web应用中,为每个HTTP会话创建一个Bean实例。
  • 特点 :
    • 在同一个HTTP会话中共享该Bean实例。
    • 会话结束后,Bean实例会被销毁。
  • 应用场景: 与用户会话相关的数据存储,例如用户购物车。

5. Application

  • 描述: 在Web应用的整个ServletContext范围内共享一个Bean实例。
  • 特点 :
    • 所有请求和会话共享同一个Bean实例。
  • 应用场景: 应用级别的全局资源,例如配置或缓存。

6. WebSocket(在Spring 4.0+引入)

  • 描述: 为每个WebSocket会话创建一个Bean实例。
  • 特点 :
    • 在WebSocket连接的整个生命周期内共享。
  • 应用场景: WebSocket交互中需要保持的会话状态。

使用示例

在Spring配置中可以通过@Scope注解指定Bean的作用域:

java 复制代码
@Component
@Scope("prototype")  // 定义为原型作用域
public class MyBean {
    // Bean的实现
}

或者在XML配置中:

XML 复制代码
<bean id="myBean" class="com.example.MyBean" scope="prototype"/>

作用域总结

  • 单例原型可以在所有Spring应用中使用。
  • RequestSessionApplicationWebSocket作用域主要用于Web应用。
  • 选择作用域时应根据Bean的用途和生命周期要求来决定。

Bean的生命周期

在Spring中,Bean的生命周期是指一个Bean从创建到销毁的整个过程。Spring容器通过多种机制对Bean的生命周期进行管理,包括初始化、依赖注入以及销毁等。以下是Spring中Bean生命周期的主要阶段及相关机制:


1. Bean的定义和加载

  • Spring通过配置文件(XML、Java配置类)或注解(如@Component@Bean)定义Bean。
  • Spring容器在启动时解析这些定义,并将其加载为BeanDefinition对象。

2. Bean的实例化

  • Spring容器根据BeanDefinition创建Bean实例。
  • 使用Java反射机制或工厂方法来实例化对象。

3. 属性赋值(依赖注入)

  • Spring通过**依赖注入(DI, Dependency Injection)**将Bean的依赖项设置到其属性中。
  • 注入方式包括构造器注入、Setter注入或通过字段注入(使用@Autowired等注解)。

4. Bean初始化

Bean初始化阶段包括以下步骤:

  1. 执行Aware接口的方法 (如果实现了相关接口):
    • BeanNameAware: 注入Bean的名称。
    • BeanFactoryAware: 注入BeanFactory对象。
    • ApplicationContextAware: 注入ApplicationContext对象。
  2. 执行BeanPostProcessorpostProcessBeforeInitialization方法 :
    • 容器会调用所有已注册的BeanPostProcessorpostProcessBeforeInitialization方法,允许在初始化之前对Bean进行处理。
  3. 调用初始化方法 :
    • 如果实现了InitializingBean接口,调用其afterPropertiesSet()方法。
    • 如果配置了自定义的初始化方法(通过@Bean(initMethod = "methodName")或XML配置中的init-method),则执行该方法。
  4. 执行BeanPostProcessorpostProcessAfterInitialization方法 :
    • 容器会调用所有已注册的BeanPostProcessorpostProcessAfterInitialization方法,允许在初始化之后对Bean进行进一步处理。

5. Bean的使用

  • Bean已经完全初始化,可以被应用程序使用。
  • 在整个生命周期中,根据Bean的作用域,决定是单例共享还是按需创建。

6. Bean的销毁

当容器关闭时,Bean进入销毁阶段:

  1. 调用DisposableBean接口的destroy()方法(如果实现了该接口)。
  2. 执行自定义销毁方法 :
    • 如果配置了自定义销毁方法(通过@Bean(destroyMethod = "methodName")或XML配置中的destroy-method),则执行该方法。
  3. 释放资源 :
    • Spring容器释放与Bean相关的所有资源。

Bean生命周期示意图

  1. 定义和加载 →
  2. 实例化 →
  3. 属性赋值(依赖注入) →
  4. 初始化(Aware接口、BeanPostProcessor、初始化方法) →
  5. 使用 →
  6. 销毁(DisposableBean、自定义销毁方法)

示例代码

使用注解的生命周期管理
java 复制代码
@Component
public class MyBean implements InitializingBean, DisposableBean {
    @Override
    public void afterPropertiesSet() {
        System.out.println("InitializingBean: afterPropertiesSet called");
    }

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

    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct: init method called");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: cleanup method called");
    }
}

总结

Spring中的Bean生命周期可以通过接口、注解和配置灵活管理,关键阶段包括实例化、依赖注入、初始化和销毁。开发者可以在这些阶段自定义行为,以满足特定需求,例如资源初始化和清理工作。

相关推荐
在努力的前端小白2 小时前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
一叶飘零_sweeeet5 小时前
从繁琐到优雅:Java Lambda 表达式全解析与实战指南
java·lambda·java8
艾伦~耶格尔5 小时前
【集合框架LinkedList底层添加元素机制】
java·开发语言·学习·面试
一只叫煤球的猫5 小时前
🕰 一个案例带你彻底搞懂延迟双删
java·后端·面试
最初的↘那颗心6 小时前
Flink Stream API 源码走读 - print()
java·大数据·hadoop·flink·实时计算
JH30736 小时前
Maven的三种项目打包方式——pom,jar,war的区别
java·maven·jar
带刺的坐椅7 小时前
轻量级流程编排框架,Solon Flow v3.5.0 发布
java·solon·workflow·flow·solon-flow
David爱编程8 小时前
线程调度策略详解:时间片轮转 vs 优先级机制,面试常考!
java·后端
阿冲Runner8 小时前
创建一个生产可用的线程池
java·后端
写bug写bug9 小时前
你真的会用枚举吗
java·后端·设计模式