spring.factories文件的解析源碼API機(jī)制詳解
引言
Spring Boot是一個(gè)用于快速構(gòu)建基于Spring框架的應(yīng)用程序的開(kāi)源框架。它通過(guò)自動(dòng)配置、起步依賴(lài)和內(nèi)嵌服務(wù)器等特性,極大地簡(jiǎn)化了Spring應(yīng)用的開(kāi)發(fā)和部署過(guò)程。本文將深入探討Spring Boot的背景歷史、業(yè)務(wù)場(chǎng)景、功能點(diǎn)以及底層原理,并通過(guò)Java代碼手寫(xiě)模擬Spring Boot的啟動(dòng)過(guò)程,特別是spring.factories文件的解析源碼API機(jī)制。
一、Spring Boot的背景歷史
1.1 Spring Boot的起源與發(fā)展
Spring Boot是由Pivotal團(tuán)隊(duì)開(kāi)發(fā)的一個(gè)框架,它基于Spring框架,旨在簡(jiǎn)化Spring應(yīng)用的開(kāi)發(fā)和部署。Spring Boot最早于2014年發(fā)布,其設(shè)計(jì)初衷是為了應(yīng)對(duì)復(fù)雜的企業(yè)級(jí)應(yīng)用開(kāi)發(fā)中頻繁出現(xiàn)的配置冗余和重復(fù)代碼問(wèn)題。
Spring Boot的發(fā)展歷程可以分為幾個(gè)關(guān)鍵階段:
- 早期發(fā)展(2013-2014年):Spring Boot開(kāi)始開(kāi)發(fā),2014年4月發(fā)布了1.0.0版本,引入了核心特性如自動(dòng)配置、起步依賴(lài)和命令行界面(CLI)。
- 快速發(fā)展(2015-2017年):Spring Boot發(fā)布了多個(gè)版本,不斷引入新功能和改進(jìn),如對(duì)Actuator的增強(qiáng)、更好的測(cè)試支持等,逐漸成為Java開(kāi)發(fā)領(lǐng)域的熱門(mén)框架。
- 成熟與廣泛應(yīng)用(2018年至今):Spring Boot不斷進(jìn)行小版本的更新和改進(jìn),適應(yīng)不斷變化的技術(shù)需求,在云原生應(yīng)用開(kāi)發(fā)、容器化部署等方面發(fā)揮著重要作用。
1.2 Spring Boot的核心特點(diǎn)
Spring Boot的核心特點(diǎn)可以概括為以下幾點(diǎn):
- 自動(dòng)配置:根據(jù)類(lèi)路徑中的依賴(lài)和環(huán)境,自動(dòng)配置Spring應(yīng)用程序,減少手動(dòng)配置的工作量。
- 起步依賴(lài):提供一系列的起步依賴(lài),簡(jiǎn)化項(xiàng)目中的依賴(lài)管理。
- 內(nèi)嵌服務(wù)器:內(nèi)置Tomcat、Jetty或Undertow等服務(wù)器,應(yīng)用可以直接運(yùn)行,無(wú)需外部服務(wù)器。
- 生產(chǎn)就緒:提供監(jiān)控、健康檢查、外部配置等功能,使應(yīng)用能夠在生產(chǎn)環(huán)境中平穩(wěn)運(yùn)行。
二、Spring Boot的業(yè)務(wù)場(chǎng)景與功能點(diǎn)
2.1 業(yè)務(wù)場(chǎng)景
Spring Boot適用于多種業(yè)務(wù)場(chǎng)景,包括但不限于:
- 微服務(wù)架構(gòu):Spring Boot可以快速創(chuàng)建獨(dú)立的、可獨(dú)立部署的微服務(wù)應(yīng)用程序。
- RESTful API開(kāi)發(fā):提供豐富的支持和簡(jiǎn)化開(kāi)發(fā)RESTful API的工具和功能。
- Web應(yīng)用程序開(kāi)發(fā):支持開(kāi)發(fā)各種Web應(yīng)用程序,如單頁(yè)應(yīng)用程序、多頁(yè)應(yīng)用程序、網(wǎng)站等。
- 批處理應(yīng)用程序:提供對(duì)批處理應(yīng)用程序的支持,包括任務(wù)調(diào)度、處理大數(shù)據(jù)量、事務(wù)管理等。
- 數(shù)據(jù)訪問(wèn):簡(jiǎn)化與數(shù)據(jù)庫(kù)和其他數(shù)據(jù)源的集成,通過(guò)自動(dòng)配置和起步依賴(lài)簡(jiǎn)化數(shù)據(jù)訪問(wèn)層的開(kāi)發(fā)。
2.2 功能點(diǎn)
Spring Boot的功能點(diǎn)非常豐富,以下是一些關(guān)鍵功能點(diǎn):
- 自動(dòng)配置:根據(jù)classpath下的依賴(lài)和配置文件的內(nèi)容,自動(dòng)為應(yīng)用程序進(jìn)行配置。
- 起步依賴(lài):提供一系列的起步依賴(lài),用于快速引入常見(jiàn)的第三方庫(kù)和框架。
- 內(nèi)嵌服務(wù)器:內(nèi)置Tomcat、Jetty、Undertow等多個(gè)服務(wù)器,開(kāi)發(fā)者可以將應(yīng)用程序打包成可執(zhí)行的JAR或WAR文件,直接運(yùn)行。
- 監(jiān)控和管理:提供了一些監(jiān)控和管理的工具,如Actuator模塊,幫助開(kāi)發(fā)人員實(shí)時(shí)監(jiān)控和管理應(yīng)用程序的運(yùn)行狀態(tài)。
- 外部化配置:支持外部化配置,可以通過(guò)配置文件、環(huán)境變量等方式靈活地配置應(yīng)用程序。
三、Spring Boot的底層原理
3.1 自動(dòng)配置原理
Spring Boot的自動(dòng)配置機(jī)制是其核心特性之一。它通過(guò)@EnableAutoConfiguration注解實(shí)現(xiàn),根據(jù)類(lèi)路徑中的依賴(lài)自動(dòng)配置合適的Spring組件。自動(dòng)配置的實(shí)現(xiàn)主要依賴(lài)于SpringFactoriesLoader類(lèi)和@EnableAutoConfiguration注解。
在Spring Boot啟動(dòng)時(shí),SpringFactoriesLoader會(huì)掃描類(lèi)路徑下的META-INF/spring.factories文件,加載其中定義的自動(dòng)配置類(lèi)。每個(gè)自動(dòng)配置類(lèi)都會(huì)根據(jù)一定的條件(如類(lèi)路徑中是否存在特定的類(lèi)或Bean)來(lái)決定是否生效。
3.2 spring.factories文件解析源碼API機(jī)制
spring.factories文件是Spring Boot自動(dòng)配置機(jī)制的關(guān)鍵組成部分。它位于類(lèi)路徑下的META-INF目錄中,用于定義Spring Boot的自動(dòng)配置類(lèi)和其他擴(kuò)展點(diǎn)。
3.2.1 spring.factories文件的結(jié)構(gòu)
spring.factories文件是一個(gè)簡(jiǎn)單的屬性文件,其結(jié)構(gòu)如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.autoconfigure.MyAutoConfiguration
每一行定義了一個(gè)擴(kuò)展點(diǎn)的接口名稱(chēng)和對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)名稱(chēng),多個(gè)實(shí)現(xiàn)類(lèi)之間用逗號(hào)分隔。
3.2.2 SpringFactoriesLoader類(lèi)的解析機(jī)制
SpringFactoriesLoader類(lèi)是Spring Boot用于加載spring.factories文件中定義的類(lèi)的工具類(lèi)。其主要方法loadFactories用于加載指定接口的所有實(shí)現(xiàn)類(lèi):
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources("META-INF/spring.factories") :
ClassLoader.getSystemResources("META-INF/spring.factories"));
List<String> factoryNames = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryNamesProperty = properties.getProperty(factoryClassName);
for (String factoryName : StringUtils.commaDelimitedListToStringArray(factoryNamesProperty)) {
factoryNames.add(factoryName.trim());
}
}
return instantiateFactories(factoryClass, factoryNames, classLoader);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
"META-INF/spring.factories"]", ex);
}
}該方法首先通過(guò)classLoader.getResources方法找到所有META-INF/spring.factories文件的URL,然后逐個(gè)加載這些文件的內(nèi)容,解析出指定接口的所有實(shí)現(xiàn)類(lèi)名稱(chēng),最后通過(guò)反射創(chuàng)建這些類(lèi)的實(shí)例并返回。
3.3 內(nèi)嵌服務(wù)器的實(shí)現(xiàn)原理
Spring Boot內(nèi)置了Tomcat、Jetty或Undertow等服務(wù)器,使應(yīng)用可以直接運(yùn)行在這些服務(wù)器上,無(wú)需外部容器。內(nèi)嵌服務(wù)器的實(shí)現(xiàn)原理主要包括以下幾個(gè)步驟:
- 選擇服務(wù)器:根據(jù)項(xiàng)目的依賴(lài)和配置,選擇使用哪種內(nèi)嵌服務(wù)器。例如,如果項(xiàng)目中包含了
spring-boot-starter-web依賴(lài),則默認(rèn)使用Tomcat服務(wù)器。 - 配置服務(wù)器:通過(guò)配置文件或Java配置類(lèi),設(shè)置服務(wù)器的端口號(hào)、上下文路徑、Session超時(shí)時(shí)間等屬性。
- 啟動(dòng)服務(wù)器:在應(yīng)用啟動(dòng)時(shí),創(chuàng)建并啟動(dòng)內(nèi)嵌服務(wù)器。Spring Boot通過(guò)
EmbeddedServletContainerFactory接口及其實(shí)現(xiàn)類(lèi)來(lái)管理內(nèi)嵌服務(wù)器的創(chuàng)建和啟動(dòng)過(guò)程。
四、手寫(xiě)模擬Spring Boot的啟動(dòng)過(guò)程
為了更深入地理解Spring Boot的啟動(dòng)過(guò)程,我們可以通過(guò)Java代碼手寫(xiě)模擬Spring Boot的啟動(dòng)過(guò)程。以下是一個(gè)簡(jiǎn)單的模擬實(shí)現(xiàn):
4.1 定義注解和配置類(lèi)
首先,我們定義一個(gè)自定義的注解@ZhouyuSpringBootApplication,用于標(biāo)識(shí)Spring Boot應(yīng)用的啟動(dòng)類(lèi):
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public @interface ZhouyuSpringBootApplication {
}然后,我們定義一個(gè)配置類(lèi)WebConfig,用于配置Spring MVC和視圖解析器:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfig implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}4.2 創(chuàng)建SpringApplication類(lèi)
接下來(lái),我們創(chuàng)建一個(gè)自定義的SpringApplication類(lèi),用于啟動(dòng)Spring Boot應(yīng)用:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
public class ZhouyuSpringApplication {
public static void run(Class<?> primarySource, String... args) {
ConfigurableApplicationContext context = SpringApplication.run(primarySource, args);
context.close();
}
}4.3 創(chuàng)建啟動(dòng)類(lèi)
最后,我們創(chuàng)建一個(gè)啟動(dòng)類(lèi)MyApp,并使用@ZhouyuSpringBootApplication注解進(jìn)行標(biāo)注:
import com.example.config.WebConfig;
import com.example.boot.ZhouyuSpringBootApplication;
@ZhouyuSpringBootApplication
public class MyApp {
public static void main(String[] args) {
ZhouyuSpringApplication.run(MyApp.class, args);
}
}4.4 模擬spring.factories文件的解析
為了模擬spring.factories文件的解析過(guò)程,我們可以創(chuàng)建一個(gè)工具類(lèi)SpringFactoriesLoader,用于加載指定接口的所有實(shí)現(xiàn)類(lèi):
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
public class SpringFactoriesLoader {
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) throws IOException {
String factoryClassName = factoryClass.getName();
List<String> factoryNames = new ArrayList<>();
Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
try (InputStream is = url.openStream()) {
Properties properties = new Properties();
properties.load(is);
String factoryNamesProperty = properties.getProperty(factoryClassName);
for (String factoryName : factoryNamesProperty.split(",")) {
factoryNames.add(factoryName.trim());
}
}
}
List<T> factories = new ArrayList<>();
for (String factoryName : factoryNames) {
try {
Class<?> factoryClass = Class.forName(factoryName, true, classLoader);
T factory = (T) factoryClass.getDeclaredConstructor().newInstance();
factories.add(factory);
} catch (Exception e) {
throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryName, e);
}
}
return factories;
}
}然后,我們可以在啟動(dòng)類(lèi)中使用這個(gè)工具類(lèi)來(lái)加載并注冊(cè)自動(dòng)配置類(lèi):
import com.example.config.WebConfig;
import com.example.boot.ZhouyuSpringBootApplication;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import java.util.List;
@ZhouyuSpringBootApplication
public class MyApp {
public static void main(String[] args) throws IOException {
List<ConfigurationClassPostProcessor> postProcessors = SpringFactoriesLoader.loadFactories(
ConfigurationClassPostProcessor.class, MyApp.class.getClassLoader());
// 注冊(cè)自動(dòng)配置類(lèi)
for (ConfigurationClassPostProcessor postProcessor : postProcessors) {
// 這里可以添加邏輯來(lái)注冊(cè)自動(dòng)配置類(lèi)
}
ZhouyuSpringApplication.run(MyApp.class, args);
}
}需要注意的是,上述代碼只是一個(gè)簡(jiǎn)單的模擬實(shí)現(xiàn),并沒(méi)有完全覆蓋Spring Boot的啟動(dòng)過(guò)程和自動(dòng)配置機(jī)制的所有細(xì)節(jié)。在實(shí)際應(yīng)用中,Spring Boot的啟動(dòng)過(guò)程和自動(dòng)配置機(jī)制要復(fù)雜得多,涉及多個(gè)組件和類(lèi)的協(xié)同工作。
五、結(jié)論
本文通過(guò)深入探討Spring Boot的背景歷史、業(yè)務(wù)場(chǎng)景、功能點(diǎn)以及底層原理,使讀者對(duì)Spring Boot有了更深入的了解。同時(shí),通過(guò)手寫(xiě)模擬Spring Boot的啟動(dòng)過(guò)程,特別是spring.factories文件的解析源碼API機(jī)制,使讀者能夠更直觀地理解Spring Boot的自動(dòng)配置機(jī)制。希望本文能夠?yàn)樽x者在實(shí)際應(yīng)用中更好地使用Spring Boot提供有益的參考和幫助。
到此這篇關(guān)于spring.factories文件的解析源碼API機(jī)制詳解的文章就介紹到這了,更多相關(guān)spring.factories文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java模擬新浪和騰訊自動(dòng)登錄并發(fā)送微博
這篇文章主要為大家詳細(xì)介紹了Java模擬新浪和騰訊自動(dòng)登錄并發(fā)送微博功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07
RestTemplate請(qǐng)求失敗自動(dòng)重啟機(jī)制精講
這篇文章主要為大家介紹了RestTemplate請(qǐng)求失敗自定義處理的方法,自動(dòng)重試的機(jī)制精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多所進(jìn)步,早日升職加薪2022-03-03
詳解Springboot @Cacheable 注解(指定緩存位置)
這篇文章主要介紹了詳解Springboot @Cacheable 注解(指定緩存位置),使用? @Cacheable ?注解就可以將運(yùn)行結(jié)果緩存,以后查詢(xún)相同的數(shù)據(jù),直接從緩存中取,不需要調(diào)用方法,需要的朋友可以參考下2023-09-09
java使用hashMap緩存保存數(shù)據(jù)的方法
這篇文章主要介紹了java使用hashMap緩存保存數(shù)據(jù)的方法,結(jié)合實(shí)例形式簡(jiǎn)單分析了java基于hashmap讀寫(xiě)緩存數(shù)據(jù)的相關(guān)操作技巧,需要的朋友可以參考下2016-08-08
Java ProcessBuilder執(zhí)行多次CMD命令的使用
本文介紹了Java的ProcessBuilder類(lèi),該類(lèi)用于執(zhí)行外部命令,通過(guò)ProcessBuilder,我們可以在Java程序中靈活地執(zhí)行多次CMD命令,并控制輸入輸出流以及工作目錄等,感興趣的可以了解一下2024-11-11
基于springboot 長(zhǎng)輪詢(xún)的實(shí)現(xiàn)操作
這篇文章主要介紹了基于springboot 長(zhǎng)輪詢(xún)的實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01
Java中TimedCache緩存對(duì)象的詳細(xì)使用教程
TimedCache是一個(gè)泛型類(lèi),它的主要作用通常是在一定時(shí)間范圍內(nèi)對(duì)特定鍵值對(duì)進(jìn)行緩存,并且能夠根據(jù)設(shè)定的時(shí)間策略來(lái)自動(dòng)清理過(guò)期的緩存項(xiàng),本文給大家介紹了Java中TimedCache緩存對(duì)象的詳細(xì)使用教程,需要的朋友可以參考下2024-12-12
Java substring方法實(shí)現(xiàn)原理解析
這篇文章主要介紹了Java substring方法實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05

