SpringBoot自動配置原理流程

前言

新公司太忙了,都沒啥空更新博客,就隨便記錄一下以前的學習筆記吧。SpringBoot是基于Spring上的衍生框架,只要看懂了Spring的話,學這個就比較簡單了;SpringBoot也是在當前微服務時代下流行的框架,并且該框架采用了自動配置,所以只要簡單的配置一下就可以直接使用了,省去了很多做配置的時間,可以說是開箱即用。當前SpringBoot版本號為2.1.15.RELEASE版本

使用SpringBoot

這個可以借鑒一下官網:快速創建SpringBoot?Initializer

我們新建一個maven項目,然后在pom.xml添加一下兩種依賴中的一種即可

<!--添加父模塊-->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.15.RELEASE</version>
</parent>
<!--添加依賴管理-->
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.1.15.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

由于在SpringBoot框架中采用模塊化形式,所以如果想要使用哪些模塊,可直接引入spring-boot-starter-xxxx模塊,例如:

<!-- test模塊 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- Web模塊 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 操作數據庫模塊 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 操作redis模塊 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

引用好對應的模塊之后,接下來就是打包了,一般采用SpringBoot自己封裝的打包plugin工具,打成可執行包,如果要打成普通的引入jar包的話,那就不需要引入這個plugin了;

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins>
</build>

然后就是啟動了,在主類加上相應的配置,就可以使用了

@SpringBootApplication
public class App {public static void main( String[] args ) {SpringApplication.run(App.class, args);}
}

啟動原理

簡單的使用講過,接下來開始講講源碼啦

@SpringBootApplication

注解主要作用是標識當前類為啟動類,通過SpringBoot打包后的jar中找到該類,并啟動當前應用,常用的屬性有:

exclude:去除指定自動配置類。

scanBasePackages:掃描路徑同ComponentScan一致

該注解源碼中包含一下注解:

//設置為配置類相當于@Configuration,可自行點進去閱讀
@SpringBootConfiguration
//自動配置注解,該注解包含@Import注解
@EnableAutoConfiguration
//開啟掃描路徑,默認為啟動類同路徑下所有包
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

@EnableAutoConfiguration

該注解為表示自動配置,SpringBoot中自動配置,開箱即用的精髓都在于這個自動配置注解,該注解引用了@Import注解,去掃描spring.factories文件下的

org.springframework.boot.autoconfigure.EnableAutoConfiguration

?對應的的自動配置類,并加載相關Bean注入到IOC容器當中

SpringApplication

該類是應用啟動的主類,點進去看一下會發現其實就是創建SpringApplication對象并且調用run方法:

創建對象

讀取累路徑下META-INF/spring.factories文件中的相關屬性,并且拿到對應的Class對象

@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");//保存主配置類this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();//讀取spring.factories中ApplicationContextInitializer相關配置setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//讀取spring.factories中ApplicationListener相關配置setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();
}

在SpringBoot默認的spring.factories文件中對應的ApplicationListener和ApplicationContextInitializer對應的示例:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

拿到這些類,并執行對應的方法:

ApplicationContextInitializer

配置在META-INF/spring.factories文件中,配置示例如上,繼承接口并實現initialize方法,在Spring初始化之前執行該方法:

public class AppListenerStarter implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("AppListenerStarter ... ");}}

SpringApplicationRunListener

配置在META-INF/spring.factories文件中,配置示例如上,繼承接口并實現initialize方法,在Spring初始化之前執行該方法:

public class AppListener implements SpringApplicationRunListener {//必須要有參構造方法public AppListener(SpringApplication application, String[] args) {}@Overridepublic void starting() {System.out.println("AppListener starting...");}@Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {Object o = environment.getSystemProperties().get("os.name");System.out.println("AppListener environmentPrepared..." + o);}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {System.out.println("AppListener contextPrepared...");}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("AppListener contextLoaded...");}@Overridepublic void started(ConfigurableApplicationContext context) {System.out.println("AppListener ConfigurableApplicationContext started...");}@Overridepublic void running(ConfigurableApplicationContext context) {System.out.println("AppListener running...");}@Overridepublic void failed(ConfigurableApplicationContext context, Throwable exception) {System.out.println("AppListener failed...");}}

執行結果為:

?調用run方法

//計時器,用來記錄Spring容器啟動花費的時間
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//從spring.factories文件中獲取SpringApplicationRunListener實現類
SpringApplicationRunListeners listeners = getRunListeners(args);
//開始執行對應的監聽器
listeners.starting();
try {//封裝命令行參數ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//封裝監聽器和參數ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);//打印Banner日志,就是那個SpringBoot的大LOGOBanner printedBanner = printBanner(environment);//創建指定SpringIOC容器context = createApplicationContext();//獲取spring.factories文件中SpringBootExceptionReporter對應的Class,默認值為FailureAnalyzersexceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//執行監聽器中的contextPrepared()方法prepareContext(context, environment, listeners, applicationArguments, printedBanner);//刷新IOC容器,即調用Spring中的refresh方法(掃描,加載),優先加載業務組件中的,然后在加載spring.factories文件中自動配置的類refreshContext(context);afterRefresh(context, applicationArguments);//計時停止stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//開始調用監聽器中的started方法listeners.started(context);//回調ApplicationRunner和CommandLineRunner接口的實現類方法callRunners(context, applicationArguments);
}
catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);
}try {//調用監聽器running方法listeners.running(context);
}
catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);
}
return context;

至此,SpringBoot啟動流程結束了,自動配置就是將spring.factories文件中的指定配置類全部加載到容器中,優先加載業務Bean,后加載自動配置類中的Bean。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/537094.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/537094.shtml
英文地址,請注明出處:http://en.pswp.cn/news/537094.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法:對象方式數組去重

var arr [3, 1, 1, 4 , 2 , 4 , 2 , 4 , 2, 1, 1, 3, 3, 3];var ary[];var obj{};for(var i0;i<arr.length;i){var curarr[i];if(!obj[cur]){obj[cur]cur;ary.push(cur);}}console.log(ary); 復制代碼

python實現路由功能_python 實現重啟路由器

有一些服務&#xff0c;需要動態IP&#xff0c;所以我們用重啟路由器的方法實現。人工重啟不可選&#xff0c;用定時腳本執行即可。貼代碼&#xff0c;每種路由器&#xff0c;提示不一樣。需要路由器有telnet功能才行。#!/usr/bin/env python# -*- coding: utf-8 -*-import tel…

SpringBoot自定義Starter(自動配置類)

前言 SpringBoot其實從誕生以來圍繞的核心就是快速構建項目&#xff0c;快速構建的前提是有人幫你做好輪子&#xff0c;開發者只要拿來即用就好了&#xff0c;而造好輪子的人就是SpringBoot的開發者&#xff0c;引入自動配置的形式幫助開發者快速創建項目&#xff0c;而自動配…

Java并發編程之synchronized關鍵字解析

前言 公司加班太狠了&#xff0c;都沒啥時間充電&#xff0c;這周終于結束了。這次整理了Java并發編程里面的synchronized關鍵字&#xff0c;又稱為隱式鎖&#xff0c;與JUC包中的Lock顯示鎖相對應&#xff1b;這個關鍵字從Java誕生開始就有&#xff0c;稱之為重量級鎖&#xf…

raidrive安裝失敗_記一次RaiDrive映射OneDrive遇到的問題

大概在1周以前&#xff0c;出于需要存放直播錄像的原因&#xff0c;根據別人的視頻教程去自己動手搞了個5T網盤的帳號。(體驗一下&#xff0c;其實我還同時存一份在百度云&#xff0c;怕不穩定)用RaiDrive創建OneDrive的映射&#xff0c;在這步驟點確定后&#xff0c;會彈出微軟…

通過代理模式 + 責任鏈模式實現對目標執行方法攔截和增強功能

前言 最近需要實現一個插件功能&#xff0c;但是如果做成兩個接口的話&#xff08;即執行前和執行后&#xff09;&#xff0c;那么會降低插件的可玩性&#xff0c;所以需做成類似AOP的環繞通知形式&#xff0c;所以就使用到了責任鏈模式和代理模式進行實現。 介紹 代理模式(P…

Javascript基礎之-原型(prototype)

首先呢&#xff0c;prototype是對象里的一個內置屬性&#xff0c;并且呢&#xff0c;這個屬性是對于其他對象的一個引用。所以呢&#xff0c;思考下面的例子&#xff1a; var obj {a: 2 } var myObj Object.create(obj); console.log(myObj.a); // 2 console.log(myObj obj)…

Oracle查詢今天、昨天、本周、上周、本月、上月數據

查詢今天數據&#xff1a; SELECT COUNT(1) FROM T_CALL_RECORDS WHERE TO_CHAR(T_RKSJ,YYYY-MM-DD)TO_CHAR(SYSDATE,YYYY-MM-DD)&#xff1b; 查詢昨天數據&#xff1a; SELECT COUNT(1) FROM T_CALL_RECORDS WHERE TO_CHAR(T_RKSJ,YYYY-MM-DD)TO_CHAR(SYSDATE-1,YYYY-MM-DD)&…

usb一轉多 樹莓派zero_樹莓派 Zero USB/以太網方式連接配置教程

樹莓派 Zero 之所以成為一款非常棒的單板計算機并不全因為它小巧的尺寸和便宜的價格&#xff0c;還得益于它便捷、易用的特性。在加裝了 Zero Quick Plug 或 microUSB/USB 轉換頭之后&#xff0c;將樹莓派 Zero 和電腦連接起來。樹莓派 Zero 即可配置成 USB/以太網設備&#xf…

vscode Go 1.11.4 編譯錯誤 need Delve built by Go 1.11 or later

更新golang的版本為1.11.4之后vscode編譯錯誤&#xff1a;executables built by Go 1.11 or later need Delve built by Go 1.11 or later 原因是delve的版本太老了&#xff0c;需要更新&#xff0c;且delve的github地址已經更換&#xff0c;很多教程里的地址是不對的 新地址安…

oppo的sd卡在哪里打開_oppo的sd卡在哪里打開

大家好&#xff0c;我是時間財富網智能客服時間君&#xff0c;上述問題將由我為大家進行解答。以oppo A91為例&#xff0c;其sd卡可直接在文件管理頁面的存儲里面即可打開。OPPO A91的屏幕為6.4英寸&#xff0c;主屏分辨率2400乘以1080像素&#xff0c;機身顏色有暗夜星辰&…

Navicat使用教程:使用Navicat Query Analyzer優化查詢性能(第1部分)

下載Navicat Monitor最新版本Navicat Monitor 是一套安全、簡單而且無代理的遠程服務器監控工具。它具有強大的功能使你的監控發揮最大效用。受監控的服務器包括 MySQL、MariaDB 和 Percona Server&#xff0c;并與 Amazon RDS、Amazon Aurora、Oracle Cloud、Microsoft Azure …

dg oracle 切換模式_Oracle數據庫 DGbroker三種保護模式的切換

1.三種保護模式– Maximum protection在Maximum protection下&#xff0c; 可以保證從庫和主庫數據完全一樣&#xff0c;做到zero data loss.事務同時在主從兩邊提交完成&#xff0c;才算事務完成。如果從庫宕機或者網絡出現問題&#xff0c;主從庫不能通訊&#xff0c;主庫也立…

軟件包管理

應用程序&#xff1a;程序&#xff1a;Architecture C語言&#xff1a;源代碼-->&#xff08;編譯&#xff09; 二進制格式腳本&#xff1a;解釋器&#xff08;二進制程序&#xff09; 源代碼-->編譯-->鏈接-->運行程序&#xff1a;指令數據指令&#xff1a;芯片CP…

工業機器人碼垛教學實施_工業機器人應用案例碼垛詳解

工業機器人應用案例碼垛詳解隨著科技的進步以及現代化進程的加快&#xff0c;人們對搬運速度的要求越來越高&#xff0c;傳統的人工碼垛只能應用在物料輕便、尺寸和形狀變化大、吞吐量小的場合&#xff0c;這已經遠遠不能滿足工業的需求&#xff0c;機器人碼垛機應運而生。機器…

第一家云創大數據產業學院在佛山職業技術學院掛牌

2019年1月10日&#xff0c;“云創大數據產業學院揭牌暨戰略合作協議簽署儀式”在佛山職業技術學院電子信息學院會議室舉行。云創大數據總裁劉鵬教授、市場部經理單明月&#xff0c;佛山職業技術學院電子信息學院院長唐建生、副院長田鈞、學院辦公室主任趙雪章、信息工程系主任喬…

String與StringBuffer和StringBuilder的根本區別

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

16進制 ksh_AIX系統中如何統計進程打開的文件數目

作者&#xff1a;李燁楠 中國建設銀行來自微信公眾號&#xff1a;平臺人生環境: AIX 6.1 AIX7.1前言:用戶有時需要統計一個進程打開的文件數目&#xff0c;比如&#xff0c;在當前打開文件句柄使用量是否超過用戶資源限制(/etc/security/limits)中 nofiles的取值時。那么&#…

前端Http協議緩存初解

[TOC] 簡介 用戶獲取網絡資源&#xff0c;需要通過非常長的網絡去服務器上請求資源,另外服務端為了應對大量的用戶請求而不斷的提升硬件性能與帶寬。這對用戶與服務端都非常的不友好。而緩存就是為了解決用戶請求速度與釋放服務器壓力而生的。 為什么我會寫Http緩存&#xff0c…

詳解java訪問修飾符

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…