SpringBoot框架底層原理解析
SpringBoot底層原理
一 配置優(yōu)先級(jí)
1.配置方式
Springboot中支持三種配置方式,分別為:
- application.properties
- application.yml
- application.yaml
2.配置優(yōu)先級(jí)
當(dāng)存在多份配置文件時(shí),配置文件會(huì)按照它們的優(yōu)先級(jí)生效。
優(yōu)先級(jí)從高到底分別為:application.peoperties>
application.yml>
application.yaml
目前 application.yml 是最主流的方式
3.其他配置方式
Springboot除了以上常見的三種配置方式之外,還支持Java系統(tǒng)屬性
配置和命令行參數(shù)
配置。
1.Java系統(tǒng)屬性配置示例
# 在 java 命令后使用 —D 命令,然后書寫需要配置的屬性即可 # 示例中配置了項(xiàng)目的運(yùn)行端口為8081,即server.port=8081 java -Dserver.port=8081 -jar [packageName].jar
2.命令行參數(shù)配置示例
# 在jar包名稱之后,使用雙橫杠(--),后面緊跟配置的參數(shù)即可 java -jar [packageName].jar --server.port=8082
二 Bean管理
1.獲取bean對(duì)象
默認(rèn)情況下,Springboot項(xiàng)目在啟動(dòng)時(shí)會(huì)自動(dòng)創(chuàng)建bean,并且將這些bean都存放在IOC容器中。
如果想手動(dòng)獲取這些bean,則可以通過以下幾種示例。
首先需要注入ApplicationContext對(duì)象。
在 Spring框架
中,ApplicationContext是一個(gè)接口,代表了Spring容器
,它負(fù)責(zé)管理Spring應(yīng)用程序中所有的bean,同時(shí)提供了一些方法來獲取Bean,注冊(cè)Bean,是整個(gè)Spring應(yīng)用的核心。
默認(rèn)情況下,一個(gè)Bean的名稱是它的類名名稱,然后將首字母小寫。
例如 DeptController,它在IOC容器中的默認(rèn)名稱為 deptController
@Autowired private ApplicationContext applicationContext; @Test void test1(){ //1.根據(jù)bean的名稱來獲取bean對(duì)象 EmpServiceImpl empServiceImpl1= (EmpServiceImpl) applicationContext.getBean("empServiceImpl"); System.out.println(empServiceImpl1); //2.根據(jù)bean的類型來獲取bean對(duì)象 EmpServiceImpl empServiceImpl2= applicationContext.getBean(EmpServiceImpl.class); System.out.println(empServiceImpl2); //3.根據(jù)bean的類型和名稱來獲取bean對(duì)象 // 以下方法和示例,在bean的默認(rèn)名稱被修改且有多個(gè)同類型的bean時(shí),尤為有用。 EmpServiceImpl empServiceImpl3= applicationContext.getBean("empServiceImpl",EmpServiceImpl.class); System.out.println(empServiceImpl3); }
運(yùn)行以上示例,可以看出,bean在IOC容器中,默認(rèn)是單例
存在的。
如果想要實(shí)現(xiàn)每次使用時(shí)都是一個(gè)新的bean,則需要通過bean的作用域
來進(jìn)行配置。
2.bean的作用域
在Spring中,bean支持五種作用域,后三種在web環(huán)境下才能生效。
默認(rèn)情況下,Bean對(duì)象在項(xiàng)目啟動(dòng)時(shí)就會(huì)默認(rèn)實(shí)例化。如果不希望在項(xiàng)目啟動(dòng)時(shí)就初始化,可以使用@Lazy
注解,讓Bean對(duì)象延遲初始化,直到第一次使用該Bean時(shí)才會(huì)進(jìn)行初始化。
@Service @Lazy public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService{ //code... }
設(shè)置Bean的作用域,則需要通過@Scope
注解來實(shí)現(xiàn)。
以下示例中,我們將Bean的作用域設(shè)置為 prototype
,即每次使用該Bean時(shí)都會(huì)創(chuàng)建新對(duì)象。
@Service @Scope("prototype") public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService{ //code... }
現(xiàn)在再次運(yùn)行前邊獲取Bean對(duì)象的代碼示例,可以發(fā)現(xiàn),三次獲取到的Bean對(duì)象,已經(jīng)不是同一個(gè)。
3.聲明第三方bean
如果要申明的Bean來自第三方,是無法通過@Component及衍生注解來申明的,這個(gè)時(shí)候就需要使用@Bean
注解。
以 SAXReader 類為例,創(chuàng)建一個(gè)返回值為SAXReader對(duì)象
的方法,方法名稱就是以后被ICO管理的Bean對(duì)象名稱。
//將方法的返回值交給IOC容器管理,稱為IOC容器的Bean對(duì)象 @Bean public SAXReader saxReader(){ return new SAXReader(); }
在以后需要用到 SAXReader 對(duì)象
的時(shí)候,直接注入即可,不用去實(shí)例化。
@Autowired private SAXReader saxReader; @Test void test2() throws DocumentException { Document document = saxReader.read("xxx"); }
注意:一般情況下,我們通常會(huì)將所有需要申明的第三方bean對(duì)象統(tǒng)一放在一個(gè)配置類中,這樣更加方便維護(hù)。
@Configuration public class BeanAutoConfig { // 可以通過@Bean注解的 name /value 屬性來定義bean的名稱 // 默認(rèn)情況下,bean的名稱就是方法名 @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
在聲明第三方bean對(duì)象時(shí),如果需要進(jìn)行依賴注入,則只需要指定方法形參即可。Spring會(huì)根據(jù)類型進(jìn)行自動(dòng)裝配。
// EmpServiceImpl對(duì)象是要注入的bean對(duì)象 @Bean public RestTemplate restTemplate(EmpServiceImpl empServiceImpl){ empServiceImpl.[xxx]; return new RestTemplate(); }
三 Springboot原理
1.Springboot起步依賴
Springboot整合了以前web開發(fā)需要用的一些依賴項(xiàng),目前使用Springboot開發(fā)web項(xiàng)目,只需要引入 spring-boot-start-web
依賴即可。
歸根結(jié)底,SPringboot起步依賴的原理就是maven的依賴傳遞
。
2.自動(dòng)配置
當(dāng)Springboot項(xiàng)目啟動(dòng)后,Springboot中的一些配置類,bean對(duì)象就會(huì)自動(dòng)存入到IOC容器中,不需要我們手動(dòng)去申明。從而簡(jiǎn)化了開發(fā),省去了繁瑣的配置。
3.管理第三方包中的Bean
1.配置實(shí)現(xiàn)方式1:@ComponentScan 組件掃描
在啟動(dòng)類上使用 @ComponentScan
注解,重新配置包掃描路徑。@ComponentScan
的basePackages
參數(shù)支持?jǐn)?shù)據(jù)格式,當(dāng)有多個(gè)第三方包時(shí),可使用數(shù)組形式申明。
@ComponentScan(basePackages = "xxx1")
或
@ComponentScan(basePackages = { "xxx1", "xxx2" })
注意:使用@ComponentScan
申明時(shí),當(dāng)前Springboot項(xiàng)目
中的包路徑也必須包含在內(nèi),否則當(dāng)前項(xiàng)目中的bean將會(huì)被無法識(shí)別。
缺點(diǎn):當(dāng)項(xiàng)目較大時(shí),引入大量的第三方依賴,此時(shí)啟動(dòng)類將會(huì)顯得臃腫。
2.配置實(shí)現(xiàn)方式2:@Import 組件導(dǎo)入
使用@Import導(dǎo)入的類會(huì)被Spring加載到容器中??梢詫?dǎo)入普通類,配置類,以及 ImportSelector 接口的實(shí)現(xiàn)類,支持?jǐn)?shù)組。
@Import({xx1.class,xx2.class})
實(shí)現(xiàn)ImportSelector 接口,這里最核心的就是 selectImports方法
,它返回了需要?jiǎng)?chuàng)建Bean對(duì)象的全部類。
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //此處的數(shù)組內(nèi)容為需要導(dǎo)入的Bean對(duì)象的全類名,有多少寫多少 return new String[]{"springboot.demo.GoodStudent"}; } }
然后在啟動(dòng)類上使用@Import
注解即可。
@Import({MyImportSelector.class})
單純使用 @Import
接口聲明第三方Bean,缺點(diǎn)很明顯。
3.配置實(shí)現(xiàn)方式3:第三方依賴提供注解
實(shí)際項(xiàng)目中,具體第三方依賴需要導(dǎo)入哪些Bean,只有第三方依賴自己知道。所以可以由第三方依賴提供注解,然后在項(xiàng)目中引入即可。
此類型注解一般均由 Enable
開頭,原理是在自定義注解中封裝 @Import
注解。
示例:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import({ MybatisPlusConfig.class, CorsConfig.class, SpringWebConfig.class, BeanAutoConfig.class, RedisConfig.class }) public @interface EnableShawnConfig { }
在第三方依賴包中定義一個(gè)EnableShawnConfig
注解,然后使用 @Import
將需要配置的Bean對(duì)象都引入進(jìn)來。最后再在項(xiàng)目中使用該注解即可。
@EnableShawnConfig @SpringBootApplication public class ShawnServerSystemApplication { public static void main(String[] args) { SpringApplication.run(ShawnServerSystemApplication.class, args); } }
4.自動(dòng)配置原理分析
Springboot核心注解:@SpringBootApplication
@SpringBootApplication
下的重要注解:
- @SpringBootConfiguration:申明當(dāng)前注解也是一個(gè)配置類,因?yàn)锧SpringBootConfiguration中也申明了@Configuration注解。所以可以直接在啟動(dòng)類中申明第三方的bean對(duì)象。
- @EnableAutoConfiguration:Springboot自動(dòng)配置的核心注解,它聲明了@Import(AutoConfigurationImportSelector.class),AutoConfigurationImportSelector是ImportSelector接口的實(shí)現(xiàn)類,實(shí)現(xiàn)了 selectImports 方法。selectImports 方法返回了需要?jiǎng)?chuàng)建Bean對(duì)象的全部信息。
- @ComponentScan:組件掃描,默認(rèn)掃描當(dāng)前引導(dǎo)類及其所在的子包。
自動(dòng)配置最核心的注解就是@EnableAutoConfiguration
,由源碼可知,selectImports 方法
會(huì)讀取一個(gè)固定目錄下后綴名為.imports
的文件。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()) .getCandidates(); Assert.notEmpty(configurations, "No auto configuration classes found in " + "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
springboot3.x中,META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,配置了需要?jiǎng)?chuàng)建Bean對(duì)象的全類名
在Springboot2.x中,是通過兩個(gè)關(guān)鍵文件來讀取配置好的全類名的。
spring.factories
是早起Springboot版本中自動(dòng)配置的文件,在后續(xù)版本中已經(jīng)逐漸不再使用。
5.@Conditinal注解
@Conditinal
注解的作用:按照一定的條件判斷,在滿足條件后才會(huì)注冊(cè)對(duì)應(yīng)的Bean對(duì)象到IOC容器中
它可以作用在類
和方法
上。
@Conditinal
本身是一個(gè)父級(jí)注解,它衍生除了很多子級(jí)注解
- @ConditionalOnClass:判斷環(huán)境中是否存在字節(jié)碼文件,有則注冊(cè)bean對(duì)象到IOC容器
- @ConditionalOnMissingBean:判斷環(huán)境中有沒有對(duì)應(yīng)的Bean(根據(jù)類型和名稱),沒有則注冊(cè)Bean對(duì)象到IOC容器
- @ConditionalOnProperty:判斷配置文件中是否有對(duì)應(yīng)屬性和值,有則注冊(cè)bean對(duì)象到IOC容器
到此這篇關(guān)于SpringBoot框架底層原理解析的文章就介紹到這了,更多相關(guān)SpringBoot底層原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
200行java代碼實(shí)現(xiàn)2048小游戲
這篇文章主要為大家詳細(xì)介紹了200行java代碼實(shí)現(xiàn)2048小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04java實(shí)現(xiàn)統(tǒng)一異常處理的示例
一個(gè)全局異常處理類需要處理三類異常1.業(yè)務(wù)類異常,2.運(yùn)行時(shí)異常 ,3.Error,本文給大家介紹java實(shí)現(xiàn)統(tǒng)一異常處理的示例,感興趣的朋友一起看看吧2021-06-06Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例
這篇文章主要介紹了Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例,值得一提的是所謂的雙向冒泡排序并不比普通的冒泡排序效率來得高,注意相應(yīng)的時(shí)間復(fù)雜度,需要的朋友可以參考下2016-04-04Spring Boot 實(shí)例化bean如何選擇代理方式
這篇文章主要為大家介紹了Spring Boot實(shí)例化bean如何選擇代理方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07IntelliJ IDEA失焦自動(dòng)重啟服務(wù)的解決方法
在使用 IntelliJ IDEA運(yùn)行 SpringBoot 項(xiàng)目時(shí),你可能會(huì)遇到一個(gè)令人困擾的問題,一旦你的鼠標(biāo)指針離開當(dāng)前IDE窗口,點(diǎn)擊其他位置時(shí), IDE 窗口會(huì)失去焦點(diǎn),你的 SpringBoot 服務(wù)就會(huì)自動(dòng)重啟,所以本文給大家介紹了IntelliJ IDEA失焦自動(dòng)重啟服務(wù)的解決方法2023-10-10logback輸出日志屏蔽quartz的debug等級(jí)日志方式
這篇文章主要介紹了logback輸出日志屏蔽quartz的debug等級(jí)日志方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java中SPI機(jī)制的實(shí)現(xiàn)詳解
SPI(Service?Provider?Interface),是?JDK?內(nèi)置的一種服務(wù)提供發(fā)現(xiàn)機(jī)制,可以用來啟用框架擴(kuò)展和替換組件,下面我們就來看看Java中SPI機(jī)制的具體實(shí)現(xiàn)2024-01-01java實(shí)現(xiàn)簡(jiǎn)易貪吃蛇游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易貪吃蛇游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12