在 Spring 和 Spring Boot 程序中,不同的作用域(Scope)管理 Bean 的创建和销毁周期。以下是对每种作用域的详细解释以及在单例(singleton)中注入其他作用域 Bean 时的解决方法:
作用域(Scope)类型
singleton
- 描述:整个应用程序中只有一个实例,默认的作用域。
- 生命周期:容器启动时创建(如果没有设置延迟加载),容器关闭时销毁。
prototype
- 描述:每次请求 Bean 时都会创建一个新的实例。
- 生命周期:每次使用时创建,不会自动销毁,需要手动调用
DefaultListableBeanFactory.destroyBean(bean)
销毁。request
- 描述:每个 HTTP 请求都会创建一个新的 Bean 实例。
- 生命周期:每次请求用到此 Bean 时创建,请求结束时销毁。
session
- 描述:每个 HTTP 会话会创建一个新的 Bean 实例。
- 生命周期:每个会话用到此 Bean 时创建,会话结束时销毁。
application
- 描述:整个 Web 应用程序范围内只有一个实例。
- 生命周期:Web 容器启动时创建,容器停止时销毁。
globalSession
- 描述:用于 Portlet 应用程序中的全局会话范围。
- 状态:已经废弃,不再推荐使用。
解决在 singleton 中注入其他作用域 Bean 的问题
当在 singleton Bean 中注入其他作用域(如 request
或 session
)的 Bean 时,会遇到生命周期不匹配的问题。以下是几种解决方法:
@Lazy
- 描述:延迟初始化 Bean,只有在真正使用时才会创建 Bean 实例。
- 用法:在注入时使用
@Lazy
注解。@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
- 描述:使用代理模式,将 Bean 的实例包装在代理对象中,解决生命周期不匹配的问题。
- 用法:在定义 Bean 时使用
@Scope
注解并设置proxyMode
。ObjectFactory
- 描述:使用
ObjectFactory
接口来延迟获取 Bean 实例。- 用法:注入
ObjectFactory
并在需要时获取实例。ApplicationContext.getBean
- 描述:通过
ApplicationContext
的getBean
方法手动获取 Bean 实例。- 用法:注入
ApplicationContext
并在需要时获取 Bean。
通过上述方法,可以有效解决在单例作用域中注入其他作用域 Bean 的问题,确保 Bean 的生命周期管理符合预期。