SpringBean管理與Spring Boot自動配置原理解析
Spring 原理深入探索
1. Bean 的作用域和生命周期
1.1 Bean 的作用域
在Spring中,Bean的作用域(Scope)決定了Bean的實例化方式以及其生命周期。以下是Spring中常見的Bean作用域:
| 作用域 | 說明 |
|---|---|
| singleton | 每個Spring IoC容器內(nèi)同名稱的bean只有?個實例(單例)(默認 ) |
| prototype | 每次使用該bean時會創(chuàng)建新的實例(非單例) |
| request | 每個HTTP 請求生命周期內(nèi), 創(chuàng)建新的實例 |
| session | 每個HTTP Session生命周期內(nèi), 創(chuàng)建新的實例 |
| application | 每個ServletContext生命周期內(nèi), 創(chuàng)建新的實例 |
| websocket | 每個WebSocket生命周期內(nèi), 創(chuàng)建新的實例 |
我們直接上代碼 后面根據(jù)運行結(jié)果觀察Bean的作用域。
創(chuàng)建一個Dog實體類:
public class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}創(chuàng)建一個DogCompoent類(交給Spring進行管理):
@Component
public class DogCompoent {
@Bean
public Dog dog(){
return new Dog();
}
// 單例
@Bean
public Dog singleDog(){
return new Dog();
}
// 多例
@Bean
@Scope("prototype")
public Dog prototypeDog(){
return new Dog();
}
//request
@Bean
@RequestScope
public Dog requestDog(){
return new Dog();
}
//session
@Bean
@SessionScope
public Dog sessionDog(){
return new Dog();
}
//application
@Bean
@ApplicationScope
public Dog applicationDog(){
return new Dog();
}
}定義一個controller類:
@RestController
@RequestMapping("/dog")
public class DogController {
@Autowired
ApplicationContext context;
// 單例作用域
@Resource(name = "singleDog")
Dog singleDog;
// 多例作用域(原型)
@Resource(name="prototypeDog")
Dog prototypeDog;
//
@Resource(name = "requestDog")
Dog requestDog;
//
@Resource(name = "sessionDog")
Dog sessionDog;
//
@Resource(name = "applicationDog")
Dog applicationDog;
@RequestMapping("/singleton")
public String singleton(){
Dog contextDog = context.getBean("singleDog", Dog.class);
return "contextDog"+contextDog+",resource"+singleDog;
}
@RequestMapping("/prototype")
public String prototype(){
Dog contextDog = context.getBean("prototypeDog", Dog.class);
return "contextDog"+contextDog+",resource"+prototypeDog;
}
@RequestMapping("/request")
public String request(){
Dog contextDog = context.getBean("requestDog", Dog.class);
return "contextDog"+contextDog+",resource"+ requestDog;
}
@RequestMapping("/session")
public String session(){
Dog contextDog = context.getBean("sessionDog", Dog.class);
return "contextDog"+contextDog+",resource"+ sessionDog;
}
@RequestMapping("/application")
public String application(){
Dog contextDog = context.getBean("applicationDog", Dog.class);
return "contextDog"+contextDog+",resource"+ applicationDog;
}
}啟動類:
@SpringBootApplication
public class SpringPrincipleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}啟動項目: 測試不同作用域的Bean取到的對象是否一樣:
Singleton(單例)- Spring默認的作用域,所有客戶端共享同一個Bean實例。
- 適用于無狀態(tài)Bean。
單例作用域的Bean:http://127.0.0.1:8080:/dog/singleton

多次訪問, 得到的都是同?個對象, 并且 @Autowired 和applicationContext.getBean()也是同?個對象。

Prototype(原型)- 每次注入或獲取Bean時,都會創(chuàng)建一個新的實例。
- 適用于有狀態(tài)Bean。
原型作用域的Bean:http://127.0.0.1:8080:/dog/prototype

觀察ContextDog, 每次獲取的對象都不?樣(注入的對象在Spring容器啟動時, 就已經(jīng)注入了, 所以多次請求也不會發(fā)生變化)

Request(請求范圍)- 每個HTTP請求創(chuàng)建一個新的Bean實例。
- 適用于Web應(yīng)用中的請求相關(guān)數(shù)據(jù)。
- request作用域的Bean:
http://127.0.0.1:8080:/dog/request

在?次請求中, @Autowired 和 applicationContext.getBean() 也是同?個對象.但是每次請求, 都會重新創(chuàng)建對象.

Session(會話范圍)- 每個HTTP會話創(chuàng)建一個新的Bean實例。
- 適用于用戶會話相關(guān)數(shù)據(jù)。
session作用域的Bean:http://127.0.0.1:8080:/dog/session


在一個session當中,多次請求,獲取的對象都是同一個。
但是我們換一個瀏覽器訪問會重新創(chuàng)建對象(另外一個session)
Application(應(yīng)用范圍)- 每個ServletContext創(chuàng)建一個Bean實例。
session作用域的Bean:http://127.0.0.1:8080:/dog/application

在?個應(yīng)用中, 多次訪問都是同一個對象.
Application scope就是對于整個web容器來說, bean的作?域是ServletContext級別的. 這個和
singleton有點類似,區(qū)別在于: Application scope是ServletContext的單例, singleton是?個
ApplicationContext的單例. 在?個web容器中ApplicationContext可以有多個。
1.2 Bean 的生命周期
Bean的生命周期從創(chuàng)建到銷毀,Spring對其進行了詳細的管理:
Bean的創(chuàng)建
- 通過構(gòu)造器或工廠方法創(chuàng)建Bean實例。
依賴注入
- 根據(jù)配置注入Bean的依賴項。
初始化回調(diào)
- 調(diào)用Bean的初始化方法(如
@PostConstruct注解標注的方法)。 - Spring的
InitializingBean接口或自定義初始化方法。
Bean可用
- Bean已經(jīng)準備就緒,可以被應(yīng)用程序使用。
銷毀回調(diào)
- 當應(yīng)用上下文關(guān)閉時,調(diào)用Bean的銷毀方法。
- 如
@PreDestroy注解標注的方法,或DisposableBean接口。
創(chuàng)建一個BeanLifeComponent類繼承BeanNameAware來說明Bean的生命周期從創(chuàng)建到銷毀。
代碼:
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BeanLifeComponent implements BeanNameAware {
//
// @Autowired
private DogCompoent dogCompoent;
//1. 實例化
public BeanLifeComponent() {
System.out.println("執(zhí)行構(gòu)造方法....");
}
// 2.屬性賦值(seter方法注入)
@Autowired
public void setDogCompoent(DogCompoent dogCompoent) {
this.dogCompoent = dogCompoent;
System.out.println("執(zhí)行屬性賦值");
}
//獲取Bean的名稱
@Override
public void setBeanName(String name) {
System.out.println("執(zhí)行BeanNameAware,beanName:"+name);
}
// 初始化方法
@PostConstruct
public void init(){
System.out.println("初始化方法...");
}
// 4.使用Bean
public void use(){
System.out.println("使用Bean,執(zhí)行use 方法");
}
// 5.銷毀Bean
@PreDestroy
public void destroy(){
System.out.println("銷毀bean");
}
}啟動項目:

進行測試:
@Test
void testBean(){
BeanLifeComponent bean = context.getBean(BeanLifeComponent.class);
bean.use();
}
可以看到使用Bean成功了。
流程:

2. Spring Boot 自動配置流程
SpringBoot的自動配置就是當Spring容器啟動后, ?些配置類, bean對象等就自動存入到了IoC容器中,不需要我們手動去聲明, 從而簡化了開發(fā), 省去了繁瑣的配置操作。
SpringBoot自動配置, 就是指SpringBoot是如何將依賴jar包中的配置類以及Bean加載到Spring IoC容器中的Spring Boot通過自動配置(Auto-Configuration)簡化了配置過程,以下是其核心流程:
數(shù)據(jù)準備

import org.springframework.context.annotation.Configuration;
//第三方
@Configuration
public class Sliqverconfig {
public void study(){
System.out.println("Sliqverconfig study... ");
}
}獲取Sliqverconfig這個Bean
寫測試用例:
@Autowired
ApplicationContext context;
@Test
void testBean(){
Sliqverconfig bean = context.getBean(Sliqverconfig.class);
System.out.println(bean);
}
可以看到測試報錯,那這個是什么原因呢?
原因分析
Spring通過五?注解和 @Bean 注解可以幫助我們把Bean加載到SpringIoC容器中, 以上有個前提就是這些注解類需要和SpringBoot啟動類在同?個目錄下 ( @SpringBootApplication 標注的類 就是SpringBoot項目的啟動類。

可以看到這個Sliqverconfig類并不和啟動類在同一個包下面。
這個Sliqverconfig類相當于第三方包,那我們怎么樣把這個包,交給Spring管理這些Bean呢?
解決方案
我們需要指定路徑或者引入的文件, 告訴Spring, 讓Spring進行掃描到.
常見的解決方法有兩種:
1. @ComponentScan 組件掃描
@ComponentScan(basePackages = "com.config")
@SpringBootApplication
public class SpringPrincipleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}再進行測試:

獲取成功.
2. @Import
導(dǎo)入類
@Import(Sliqverconfig.class)
@SpringBootApplication
public class SpringPrincipleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}再進行測試:

獲取成功.
導(dǎo)? ImportSelector 接口實現(xiàn)類
public class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.config.Sliqverconfig"};
}
}啟動類:
@Import(MyRegistrar.class)
@SpringBootApplication
public class SpringPrincipleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}再進行測試:

獲取成功.
問題:
但是他們都有?個明顯的問題, 就是使用者需要知道第三方依賴中有哪些Bean對象或配置類. 如果漏掉其中?些Bean, 很可能導(dǎo)致我們的項目出現(xiàn)大的事故.這對程序員來說非常不友好.
依賴中有哪些Bean, 使用時候需要配置哪些bean, 第三方依賴最清楚, 那能否由第三方依賴來做這件事呢?
比較常見的方法就是第三方依賴給我們提供?個注解, 這個注解?般都以@EnableXxxx開頭的注解,注解中封裝的就是 @Import 注解.
第三?依賴提供注解.
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//注解
//類
@Target(ElementType.TYPE)
//生命周期
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)//指定要導(dǎo)入的類
public @interface EnableSliqversConfig {
}注解中封裝 @Import 注解, 導(dǎo)入MySelector.class
啟動類:
直接使用第三方提供的注解:
//通過第三方注解 @EnableSliqversConfig
@EnableSliqversConfig
@SpringBootApplication
public class SpringPrincipleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}再進行測試:

獲取成功.
Spring boot 配置流程如下:

3.總結(jié)
Spring的Bean管理和生命周期機制是其核心功能,而Spring Boot的自動配置流程則大大簡化了配置工作,幫助開發(fā)者快速構(gòu)建應(yīng)用。
到此這篇關(guān)于SpringBean管理與Spring Boot自動配置原理解析的文章就介紹到這了,更多相關(guān)Spring Boot自動配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java多線程之異步Future機制的原理和實現(xiàn)
這篇文章主要為大家詳細介紹了Java多線程之異步Future機制的原理和實現(xiàn),感興趣的小伙伴們可以參考一下2016-08-08
Spring?Boot?3.1中整合Spring?Security和Keycloak的方法
本文介紹在最新的SpringBoot3.1版本之下,如何將Keycloak和Spring?Security一起跑起來,文中結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2023-06-06
shiro并發(fā)人數(shù)登錄控制的實現(xiàn)代碼
在做項目中遇到這樣的需求要求每個賬戶同時只能有一個人登錄或幾個人同時登錄,如果是同時登錄的多人,要么不讓后者登錄,要么踢出前者登錄,怎么實現(xiàn)這樣的功能呢?下面小編給大家?guī)砹藄hiro并發(fā)人數(shù)登錄控制的實現(xiàn)代碼,一起看看吧2017-09-09
一文搞懂SpringMVC中@InitBinder注解的使用
@InitBinder方法可以注冊控制器特定的java.bean.PropertyEditor或Spring Converter和 Formatter組件。本文通過示例為大家詳細講講@InitBinder注解的使用,需要的可以參考一下2022-06-06

