一、Spring Bean的作用域有哪些?
Spring框架支持以下五种Bean的作用域:
- Singleton:这是默认的作用域,在每个Spring IoC容器中只有一个Bean的实例(IoC初始化后)。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
- Prototype:每次 getBean() 都会创建一个新的Bean实例。
- Request:每次HTTP请求都会产生一个新的Bean(请求Bean)。在当前的HTTP 请求内有效。
- Session:每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 Bean),在当前的 HTTP session 内有效。
- Global Session/application:每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
问题1:
Spring框架默认的作用域为Singleton,是说在每个Spring IoC容器中只有一个Bean的实例,但是为啥在Prototype作用域下每次请求都会创建一个新的Bean实例呢,这个不冲突吗
不冲突。在Spring框架中,Singleton和Prototype作用域的定义是不同的。
Singleton作用域是默认的作用域,当没有明确指定Bean的作用域时,Spring会为这个Bean创建一个Singleton作用域的实例。这意味着在同一个Spring IoC容器中,只有一个Bean的实例。当你在应用程序中多次获取同一个Singleton Bean时,你实际上是在访问同一个Bean实例。
而Prototype作用域是另一种类型的作用域,每次请求都会创建一个新的Bean实例。当你在应用程序中多次获取同一个Prototype Bean时,每次都会创建一个新的实例。这种作用域适用于那些需要经常创建新实例的Bean,例如,每次用户请求都需要一个新的实例。
因此,虽然Singleton和Prototype作用域在名称上看起来相似,但它们在实际应用中的行为是不同的。Singleton作用域适用于那些只需要一个实例的Bean,而Prototype作用域适用于那些每次请求都需要新实例的Bean。这就是为什么在Prototype作用域下每次请求都会创建一个新的Bean实例,这与Singleton作用域并不冲突。
问题2:那在程序中如何指定Bean的作用域呢
指定Bean的作用域的方式(和声明一个类为Bean的方式一样),有两种,具体如下:
- 方式1:在ApplicationContext.xml文件中的< bean >元素中添加scope属性
在Spring框架中,你可以通过在Bean的配置中指定作用域来改变Bean实例化的行为。具体来说,你可以在Bean的配置中使用scope属性来指定作用域。
xml
<bean id="exampleBean" class="examples.ExampleBean" scope="singleton"/>
在上面的例子中,scope属性的值为singleton,表示这个Bean的作用域是Singleton。
- 方式2:注解的方式,通过@Scope注解
如果你使用注解配置Bean,你可以在@Component或@Bean注解中使用scope属性,如下所示:
java@Component
@Scope("singleton")
public class ExampleBean { // ...
}
二、Spring Bean的生命周期
Spring Bean的生命周期可以包括以下阶段:
实例化-》属性赋值-》自定义初始化-》使用-》自定义销毁-》销毁
- 实例化:当Spring容器启动时首先会进行Bean的实例化,会根据配置文件或注解等方式创建Bean的实例(默认情况下Spring Bean的作用域为Singleton,实例化后IOC容器中有唯一的Bean实例)。
- 属性赋值:在实例化后,Spring会自动为Bean的属性进行注入,可以通过配置文件或注解等方式进行属性注入。
- 自定义初始化:在属性注入完成后,Bean会调用自定义的初始化方法进行一些额外的初始化操作,可以通过实现InitializingBean接口(初始化bean接口)或使用@PostConstruct注解定义方法。
- 使用:当所有Bean都初始化完成后,就可以通过Spring容器获取Bean实例并进行使用了。
- 自定义销毁:在使用完后,可以定义自定义的销毁方法,通过实现DisposableBean接口或使用@PreDestroy注解定义方法。
- 销毁:当Bean不再需要使用时,会被销毁,释放占用的资源。
总之,Spring Bean的生命周期包括了实例化、属性赋值、自定义初始化、使用、自定义销毁和销毁等阶段,这些阶段可以通过实现接口或使用注解等方式进行自定义操作,使应用程序更加灵活和易于维护。