Java?Spring原理之Bean的作用域、Bean的生命周期及Spring自動配置詳解
Spring原理
Bean的作用域
- 概念:從Context中獲取對象,得到的都是同一個,這種行為模式,就稱為bean的作用域
多次獲取,拿到的Bean的對象都是同一個
- 在Spring中支持6種作用域,后4種在Spring MVC環(huán)境才生效
(1) singleton:單例作用域
每個Spring IoC容器內同名稱的bean只有一個實例(單例)(默認)
(2) prototype:原型作用域(多例作用域)
每次使用該bean時會創(chuàng)建新的實例(非單例)
(3) request:請求作用域
每個HTTP 請求生命周期內, 創(chuàng)建新的實例(web環(huán)境中, 了解)
(4) session:會話作用域
每個HTTP Session生命周期內, 創(chuàng)建新的實例(web環(huán)境中, 了解)
(5) Application: 全局作用域
每個ServletContext生命周期內, 創(chuàng)建新的實例(web環(huán)境中, 了解)
(6) websocket:HTTP WebSocket 作用域
每個WebSocket生命周期內, 創(chuàng)建新的實例(web環(huán)境中,了解)
驗證是單例的
- 從context中獲取對象
- 屬性注入獲取對象
@Configuration
public class BeanConfig {
@Bean
public User user1(){
return new User(1,"zhangsan");
}
// 聲明作用的范圍(聲明了一個單例的作用域)
// 聲明了一個單例的對象
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
// @Scope("singleton")
@Bean
public User singleUser(){
return new User();
}
}
// 有多個@Autowired的時候,指定名稱使用哪個
@Resource(name = "singleUser")
private User singleUser;
@RequestMapping("scope")
@RestController
public class BeanScopeController {
@Autowired
private ConfigurableApplicationContext context;
// 有多個@Autowired的時候,指定名稱使用哪個
@Resource(name = "singleUser")
private User singleUser;
@RequestMapping("/single")
public String single(){
// 1. 從context中獲取對象
String user = (String) context.getBean("singleUser");
// 2. 屬性注入獲取對象
return "從context中獲取的對象 " + System.identityHashCode(user)
+ "屬性注入獲取的對象" + System.identityHashCode(singleUser);
}
}
- 結果展示:可以看出他們獲取的是同一個對象

多例的作用域
- 多例模式(原型模式)
屬性注入在程序啟動的時候會創(chuàng)建一個對象,之后再重新啟動,才會改變
context獲取的對象,每次重新啟動都會重新獲取對象,因此每次對象都會發(fā)生變化

//對象
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public User prototypeUser(){
return new User();
}
// 注解
@Resource(name = "prototypeUser")
private User prototypeUser;
@RequestMapping("/phototype")
public String phototype(){
// 1. 從context中獲取對象
User user = (User) context.getBean("prototypeUser");
// 2. 屬性注入獲取對象
return "從context中獲取的對象 " + System.identityHashCode(user)
+ "屬性注入獲取的對象" + System.identityHashCode(prototypeUser);
}展示效果:每次刷新,拿到的不是同一個對象,每次請求都會生成一個新的對象

出現(xiàn)的問題:沒有驗證成功的原因是我們寫的是同一個User對象,@Data中的hashcode()會根據(jù)id判斷他們是否是同一個對象,**這里的new User()都是同一個對象,那么這里就判斷了他們是同一個對象,Spring進行了優(yōu)化,**因此每次request刷新都不變,理論上每次刷新,都會創(chuàng)建一個新的對象,每次都會變化
這里就要使用jdk,自帶的toString()方法,jdk有hashcode()方法,用自帶的toString()方法,它每次new都會生成不同的對象,因此可以看出request,每次都是變化的了
所以這里不同@Data,而用@Getter和@Setter

對上面問題的再一次解釋:
Spring使用了代理模式,所以代理的User,每次都是同一個


Spring中才有代理模式:

request的作用域
- @RequestScope等同于@Scope,這兩者含義是一樣的

- 雖然是同一個對象,但是每次請求都會重新創(chuàng)建對象

// request的作用域
@RequestScope
@Bean
public User requestUser(){
return new User();
}
// 注解的方式
@Resource(name = "requestUser")
private User requestUser;
@RequestMapping("/request")
public String request(){
// 1. 從context中獲取對象
User user = (User) context.getBean("requestUser");
// 2. 屬性注入獲取對象
return "從context中獲取的對象 " + System.identityHashCode(user)
+ "屬性注入獲取的對象" + System.identityHashCode(requestUser);
}
session的作用域
- 在不同的瀏覽器下,是不同的會話,自然會出現(xiàn)不同的地址
@SessionScope
@Bean
public User sessionUser(){
return new User();
}
@Resource(name = "sessionUser")
private User sessionUser;
@RequestMapping("/session")
public String session(){
// 1. 從context中獲取對象
User user = (User) context.getBean("sessionUser");
// 2. 屬性注入獲取對象
return "從context中獲取的對象 " + System.identityHashCode(user)
+ "屬性注入獲取的對象" + System.identityHashCode(sessionUser);
}
- 效果展示:
如果是同一個瀏覽器,并且沒有清除cookie,那么session不會發(fā)生變化
如果是不同的瀏覽器,就是不同的cookie,session自然會發(fā)生變化

application的作用域
application的作用域:在整個應用中都是同一個的,和我們的單例一樣,在同一個應用中都是同一個
兩者的區(qū)別:一個web容器中(一個tomcat中),可以部署多個服務(多個ApplicationContext),而一個Web容器中有多個ServletContext - 每個Web應用都有自己獨立的ServletContext實例
一個tomcat可以啟動多個web服務

@ApplicationScope
@Bean("applicationUser")// 指定名字
public User applicationUser(){
return new User();
}
// 注解注入
@Resource(name = "applicationUser")
private User applicationUser;
@RequestMapping("/application")
public String application(){
// 1. 從context中獲取對象
User user = (User) context.getBean("applicationUser");
// 2. 屬性注入獲取對象
return "從context中獲取的對象 " + user
+ "屬性注入獲取的對象" + applicationUser;
}
- 在不同的瀏覽器中,進行展示,都是同一個

Bean的生命周期
代碼的使用
- 對象的生命周期:生命周期指的是一個對象從誕生到銷毀的整個生命過程, 我們把這個過程就叫做一個對象的生命周期。
Bean 的生命周期分為以下5個部分:
2. 實例化(為Bean分配內存空間)
3. 屬性賦值(Bean注入和裝配, 比如 @AutoWired )
4. 初始化
a. 執(zhí)行各種通知, 如 BeanNameAware , BeanFactoryAware ,
ApplicationContextAware 的接口方法.
b. 執(zhí)行初始化方法
? xml定義 init-method
? 使用注解的方式 @PostConstruct
? 執(zhí)行初始化后置方法( BeanPostProcessor )
5. 使用Bean
6. 銷毀Bean
a. 銷毀容器的各種方法, 如 @PreDestroy , DisposableBean 接口方法, destroy-
method
舉個例子:

2. 寫一個案例,來驗證Bean的生命周期
// BeanLifeComponent
@Component
public class BeanLifeComponent {
private User user;
// 構造
public BeanLifeComponent() {
System.out.println("執(zhí)行構造方法~");
}
// 屬性注入
// 指定注入的對象
// 表示注入的user1對象
@Qualifier("user1")
@Autowired
public void setUser1(User user) {
this.user = user;
System.out.println("屬性注入~");
}
// 初始化
// 使用@PostConstruct實現(xiàn)初始化
@PostConstruct // 這個用的比較多
public void init(){
System.out.println("執(zhí)行初始化方法~");
}
// 使用
public void use(){
System.out.println("執(zhí)行use方法~");
}
// 銷毀
// 基本上不會用
@PreDestroy // pre表示 bean 銷毀前執(zhí)行,銷毀的時候就直接清理對象了
public void destroy(){
System.out.println("執(zhí)行destroy銷毀方法~");
}
}
// 測試方法
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringConfigApplication.class, args);
BeanLifeComponent lifeComponent = context.getBean(BeanLifeComponent.class);
lifeComponent.use();
// 有不手動點擊結束進程的方式來執(zhí)行destroy方法
// ((AbstractApplicationContext)context).destroy();
}
展示效果:

手動關閉進程:

源碼閱讀
了解生命周期的分類
- bean的實例化,屬性注入,bean的初始化

2. 執(zhí)行各種通知,這些通知都是在初始化方法之前執(zhí)行,屬性注入之后執(zhí)行的


SpringBoot自動配置
這些注解的底層就是Spring自動配置的
元注解:是注解其他注解的注解


有選擇地導入配置類

總結
到此這篇關于Java Spring原理之Bean的作用域、Bean的生命周期及Spring自動配置的文章就介紹到這了,更多相關Java Spring原理詳解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Springboot Thymeleaf模板文件調用Java類靜態(tài)方法
這篇文章主要介紹了Springboot Thymeleaf模板文件調用Java類靜態(tài)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2007-09-09
springboot+mybatis+redis 二級緩存問題實例詳解
Mybatis默認沒有開啟二級緩存,需要在全局配置(mybatis-config.xml)中開啟二級緩存。本文講述的是使用Redis作為緩存,與springboot、mybatis進行集成的方法。需要的朋友參考下吧2017-12-12
SpringBoot實現(xiàn)多文件上傳的詳細示例代碼
文件上傳中并沒有什么太多的知識點,下面這篇文章主要給大家介紹了關于SpringBoot實現(xiàn)多文件上傳的詳細示例,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-03-03
spring?boot+vue實現(xiàn)JSAPI微信支付的完整步驟
JSAPI支付是用戶在微信中打開商戶的H5頁面,商戶在H5頁面通過調用微信支付提供的JSAPI接口調起微信支付模塊完成支付,下面這篇文章主要給大家介紹了關于spring?boot+vue實現(xiàn)JSAPI微信支付的相關資料,需要的朋友可以參考下2022-05-05
Java實現(xiàn)的連續(xù)奇數(shù)(n+2*x)是合數(shù)的算法題暴力算法
這篇文章主要介紹了Java實現(xiàn)的連續(xù)奇數(shù)(n+2*x)是合數(shù)的算法題暴力算法,本文包含運算結果和實現(xiàn)代碼,需要的朋友可以參考下2014-09-09
springcloud 中 zuul 修改請求參數(shù)信息的方法
這篇文章主要介紹了springcloud 中 zuul 修改請求參數(shù)信息的方法,需要的朋友可以參考下2018-02-02

