前言
在 Spring 中,那些組成應用程序的主體及由 Spring IOC 容器所管理的對象,被稱之為 bean。簡單地講,bean 就是由 IOC 容器初始化、裝配及管理的對象,除此之外,bean 就與應用程序中的其他對象沒有什么區別了。而 bean 的定義以及 bean 相互間的依賴關系將通過配置元數據來描述。
Spring中的bean默認都是單例的。
1. 概念引入
我們來用一個案例進行演示:
假設現在有?個公共的 Bean,提供給 A ?戶和 B ?戶使?,然?在使?的途中 A ?戶卻“悄悄”地修改了公共 Bean 的數據,導致 B ?戶在使?時發?了預期之外的邏輯錯誤。
我們預期的結果是,公共Bean可以在自己的類中進行修改,但不能影響其他類.
代碼如下:
有一個公共的Bean對象Users
@Componentpublic class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("李四"); return user;}}
?A 用戶使用時,進行了修改操作:
@Controller
public class BeanScopesController {@Autowiredprivate User user1;public User getUser1() {User user = user1;System.out.println("Bean 原 Name:" + user.getName());user.setName("王五"); return user;}
}
B 用戶再去使用公共 Bean 的時候:
@Controller
public class BeanScopesController2 {@Autowiredprivate User user1;public User getUser1() {User user = user1;return user;}
}
打印 A 用戶和 B 用戶公共 Bean 的值:
public class BeanScopesTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BeanScopesController beanScopesController = context.getBean(BeanScopesController.class);System.out.println("A 對象修改之后 Name:" + beanScopesController.getUser1().toString());BeanScopesController2 beanScopesController2 = context.getBean(BeanScopesController2.class);System.out.println("B 對象讀取到的 Name:" + beanScopesController2.getUser1().toString());}
}
最終輸出:
Bean 原 name: 李四
A 對象修改之后 Name: 1:王五
B 對象讀取到的?Name: 1:王五
原因分析:
操作以上問題的原因是因為 Bean 默認情況下是單例狀態(singleton),也就是所有?的使用的都是同?個對象,之前我們學單例模式的時候都知道,使用單例可以很大程度上提高性能,所以在 Spring 中Bean 的作用域默認也是 singleton ?單例模式。
2. 作?域定義
限定程序中變量的可?范圍叫做作?域,或者說在源代碼中定義變量的某個區域就叫做作?域。? Bean 的作?域是指 Bean 在 Spring 整個框架中的某種?為模式,?如 singleton 單例作?域,就 表示 Bean 在整個 Spring 中只有?份,它是全局共享的,那么當其他?修改了這個值之后,那么另? 個?讀取到的就是被修改的值。
2.1 Bean的6種作用域
- singleton:單例作?域
- prototype:原型作?域(多例作?域)
- request:請求作?域
- session:回話作?域
- application:全局作?域
- websocket:HTTP WebSocket 作?域
singleton?:只在加載的時候創建對象,后續如果發生改變,重新請求會得到改變之后的Bean對象。
prototype :每次獲取的對象就是初始對象
request?:請求作用域:一次http請求一個Bean對象
session :? 會話作用域:一次會話使用一個Bean對象,相對于Request作用域更廣。
application :? 全局作用域:一個httpServletContext中共用一個Bean對象一個上下文里面進行共享Bean對象
websocket? :WebSocket的每次會話中,保存了?個Map結構的頭信息,將?來包裹客戶端消息頭。第一次初始化后,直到WebSocket結束都是同?個Bean。
2.2 設置作?域
設置作用域的方式有兩種:?
3. Spring的執行流程
Bean 執?流程(Spring 執?流程):啟動 Spring 容器 -> 實例化 Bean(分配內存空間,從?到 有) -> Bean 注冊到 Spring 中(存操作) -> 將 Bean 裝配到需要的類中(取操作)。
3.1 Bean ?命周期
1.實例化 Bean(為 Bean 分配內存空間)2.設置屬性(Bean 注?和裝配)3.Bean 初始化????????實現了各種 Aware 通知的?法,如 BeanNameAware、BeanFactoryAware、????????ApplicationContextAware 的接??法;????????執? BeanPostProcessor 初始化前置?法;????????執? @PostConstruct 初始化?法,依賴注?操作之后被執?;????????執???指定的 init-method ?法(如果有指定的話);????????執? BeanPostProcessor 初始化后置?法。4.使? Bean5.銷毀 Bean