最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot自動裝配原理解析

 更新時間:2024年11月15日 10:22:26   作者:碼上一元  
Spring Boot自動裝配是指在Spring Boot應用啟動時,根據(jù)類路徑下的jar包依賴、Bean定義、各種配置文件等信息,自動配置Spring應用上下文的Bean,本文給大家詳細解析了SpringBoot自動裝配原理,需要的朋友可以參考下

什么是Spring Boot自動裝配

Spring Boot自動裝配是指在Spring Boot應用啟動時,根據(jù)類路徑下的jar包依賴、Bean定義、各種配置文件等信息,自動配置Spring應用上下文的Bean。

這種機制極大地簡化了配置工作,使得開發(fā)者可以更加專注于業(yè)務邏輯的實現(xiàn)。

在深入自動裝配原理前,我們先看下 SPI 機制。

SPI 機制

SPI(Service Provider Interface)是一種動態(tài)替換服務提供者的機制。它允許一個服務接口有多個服務提供者,并且在程序運行時動態(tài)選擇一個服務提供者。

SPI又分為 JDK SPISpring SPI。

JDK SPI

在 Java 平臺上,SPI 通常是通過 java.util.ServiceLoader 類實現(xiàn)的,這種機制在Java標準庫中廣泛應用,如JDBC驅動的管理。

SPI可以很靈活的讓接口和實現(xiàn)分離,讓服務提供者只提供接口,第三方來實現(xiàn),然后可以使用配置文件的方式來實現(xiàn)替換或者擴展。

工作原理

Java SPI 的工作原理基于以下幾個步驟:

  • 定義服務接口:首先定義一個服務接口(或抽象類),作為服務的規(guī)范。
  • 提供服務實現(xiàn):編寫接口的具體實現(xiàn)類。
  • 注冊服務實現(xiàn):在 META-INF/services 目錄下創(chuàng)建一個以接口全限定名為名的文件,文件內容為接口實現(xiàn)類的全限定名。
  • 加載服務實現(xiàn):使用 java.util.ServiceLoader 來加載并使用這些實現(xiàn)。

舉例說明一下:

(1)創(chuàng)建一個 DemoDAO 的接口

public interface DemoDao {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->}

(2)分別創(chuàng)建兩個實現(xiàn)類

public class MysqlDao implements DemoDao {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->}
public class OracleDao implements DemoDao {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->}

(3)在resources下新建META-INF/services/目錄,在該目錄下新建接口全限定名的文件com.study.spring.z_spi.DemoDao,文件內容是上面那兩個實現(xiàn)類。

com.study.spring.z_spi.MysqlDao
com.study.spring.z_spi.OracleDao

(4)使用 JDK 提供的ServiceLoader來測試下

public class JdkSpiApplication {
    public static void main(String[] args) {
        ServiceLoader<DemoDao> demoDaos = ServiceLoader.load(DemoDao.class);
        demoDaos.iterator().forEachRemaining(t -> {
            System.out.println(t);
        });
    }
}

輸出結果 :
com.study.spring.z_spi.MysqlDao@6e8cf4c6
com.study.spring.z_spi.OracleDao@12edcd21

JDBC DriverManager

Java SPI 機制在JDBC驅動管理中的應用主要體現(xiàn)在JDBC 4.0及以上版本的驅動自動發(fā)現(xiàn)和加載上。

在JDBC4.0之前,連接數(shù)據(jù)庫的時候,通常會用Class.forName(“com.mysql.jdbc.Driver”)先加載數(shù)據(jù)庫相關的驅動,然后再進行獲取連接等的操作。
而JDBC4.0之后不需要用Class.forName(“com.mysql.jdbc.Driver”)來加載驅動,直接獲取連接就可以了,這種方式就是使用了Java的SPI擴展機制來實現(xiàn)。

定義服務接口

在JDBC中,服務接口是由Java平臺定義的java.sql.Driver接口,所有的JDBC驅動都必須實現(xiàn)這個接口,以提供與數(shù)據(jù)庫建立連接的能力。

提供服務實現(xiàn)

數(shù)據(jù)庫廠商(如MySQL、Oracle等)為它們的數(shù)據(jù)庫提供JDBC驅動程序,這些驅動程序實現(xiàn)了java.sql.Driver接口。

注冊服務提供者

JDBC驅動的注冊是通過在驅動程序的JAR包中的META-INF/services目錄下創(chuàng)建一個名為java.sql.Driver的文件來完成的。這個文件包含了實現(xiàn)java.sql.Driver接口的驅動類的全限定名。當JVM啟動時,它會查找這個文件,并加載其中指定的驅動類。

在這里插入圖片描述

加載服務提供者

在JDBC 4.0及以上版本中,DriverManager類在初始化時會使用Java的SPI機制自動加載所有在META-INF/services/java.sql.Driver文件中指定的驅動類。
這是通過ServiceLoader類實現(xiàn)的,它會查找并加載所有可用的JDBC驅動實現(xiàn)。

在這里插入圖片描述

連接管理

當應用程序嘗試通過DriverManager.getConnection()方法連接數(shù)據(jù)庫時,DriverManager會遍歷所有已加載的驅動實例,嘗試建立連接。一旦某個驅動成功建立連接,它就會返回這個連接,并且不會繼續(xù)嘗試其他的驅動實例。

SpringBoot SPI 機制

Spring Boot 對 SPI 機制進行了擴展,以支持其自動配置和模塊化架構。

Spring Boot 利用 spring.factories (從 SpringBoot 2.7 起自動配置不推薦使用 /META-INF/spring.factories 文件,而是在/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)文件,這個文件列出了與自動配置相關的接口及其實現(xiàn)類,Spring Boot 啟動時會加載這些配置。

spring.factories

這個文件里面使用鍵值對的格式列出了多種服務類型及其對應的實現(xiàn)類,常見的服務類型包括:

  • org.springframework.boot.autoconfigure.EnableAutoConfiguration:用于自動配置。
  • org.springframework.context.ApplicationListener:用于應用事件監(jiān)聽器。
  • org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider:用于模板引擎的可用性判斷。
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

不使用SPI

現(xiàn)在我們先來看下,不使用 SPI 機制,怎么實現(xiàn) bean 的配置。

新建一個項目,將新類MyAppDemo注入 IOC 容器。

在這里插入圖片描述

在另一個項目 demo 中,引入 myApp 的依賴,并測試調用 test 方法。

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

@SpringBootTest
class StarterDemoApplicationTests {

	@Autowired
	private ApplicationContext applicationContext;

	@Test
	void contextLoads() {
		MyAppDemo demo = applicationContext.getBean(MyAppDemo.class);
		demo.test();
	}
}

測試發(fā)現(xiàn)找不到該 bean 對象

在這里插入圖片描述

為什么引入的第三方依賴包中的 bean 沒有生效呢?

  • 原因是因為,在類上添加@Component注解來聲明bean對象時,還需要保證@Component注解能被Spring的組件掃描到。
  • SpringBoot項目中的@SpringBootApplication注解,具有包掃描的作用,但是它只會掃描啟動類所在的當前包以及子包。
  • 當前包:com.starter.demo, 第三方依賴中提供的包:com.myapp.demo(掃描不到)

所以,有兩種方案可以解決

  • @ComponentScan 組件掃描第三方依賴的包路徑;
  • @Import 導入(使用@Import導入的類會被Spring加載到IOC容器中)。

@ComponentScan 組件掃描

@SpringBootApplication
@ComponentScan(basePackages = {"com.starter","com.myapp"})
public class StarterDemoApplication {

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

缺點:當需要引入大量的第三方依賴,就需要在啟動類上配置大量要掃描的包,這種方式會很繁瑣。

Import 導入

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	Class<?>[] value();
}

從源碼可以看到,導入形式有以下幾種

  • 普通類
  • 配置類
  • ImportSelector的實現(xiàn)類
  • ImportBeanDefinitionRegistrar的實現(xiàn)類

導入普通類

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

導入配置類

去掉MyAppDemo類上的@Component注解,新建一個MyAppConfig配置類。

@Configuration
public class MyAppConfig {
    @Bean
    public MyAppDemo myAppDemo() {
        return new MyAppDemo();
    }
}

在啟動類上導入配置類

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

導入ImportSelector的實現(xiàn)類

新建 ImportSelector的實現(xiàn)類

public class MyAppImportSelector implements ImportSelector {

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.myapp.demo.MyAppDemo"};
    }
}

在啟動類上導入MyAppImportSelector

@SpringBootApplication
@Import(MyAppImportSelector.class)
public class StarterDemoApplication {

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

導入ImportBeanDefinitionRegistrar的實現(xiàn)類

新建 ImportBeanDefinitionRegistrar 的實現(xiàn)類

public class MyAppImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MyAppDemo.class);


        registry.registerBeanDefinition("myAppDemoTest", builder.getBeanDefinition());
    }
}

在啟動類上導入MyAppImportBeanDefinitionRegistrar

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

模塊裝配

通過@Import 注解,我們可以導入第三方依賴包中的配置類。

但是基于上面的方式,我們在引入第三方依賴時,還要知道第三方依賴中有哪些配置類和哪些Bean對象?相當麻煩!

而第三方依賴自己最清楚自己有哪些配置類、有那些 Bean 對象,它提供一個注解,通過這個注解,外部系統(tǒng)可以引入自己所需要的 Bean 對象。

這個注解一般都以@EnableXxx開頭,注解中封裝的就是@Import注解,外部系統(tǒng)在使用時只需要加上@EnableXxxxx注解即可。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyAppConfig.class)
public @interface EnableMyApp {}
@SpringBootApplication
@EnableMyApp
public class StarterDemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(StarterDemoApplication.class, args);
	}
}

spring 中的模塊裝配,是在3.1 之后引入了大量的@EnableXXX 注解,來快速整合激活相對應的模塊。
如:
● EnableTransactionManagement :開啟注解事務驅動
● EnableWebMvc :激活 SpringWebMvc
● EnableAspectJAutoProxy :開啟注解 AOP 編程
● EnableScheduling :開啟調度功能(定時任務)
模塊裝配的核心原則:自定義注解+@Import 導入組件

使用SPI

即使是采用@EnableXXX注解,還是覺得麻煩怎么辦?

我想引入第三方依賴后,直接就去使用它,而不是再單獨寫一個什么什么注解。

下面我們來看看基于 Spring 的 SPI 機制怎么去實現(xiàn)。

在在resources目錄下創(chuàng)建META-INF 目錄,并新建 spring.factories文件,文件內容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.myapp.demo.MyAppConfig
@Configuration
public class MyAppConfig {

    @Bean
    public MyAppDemo myAppDemo() {
        return new MyAppDemo();
    }
}

我們只是引入了第三方依賴包,并沒有手動配置,也沒有寫什么注解啊,就可以通過IOC容器或DI依賴拿到bean對象了,這就是SpringBoot自動配置的強大之處。

自動裝配源碼

從 SpringBoot 核心注解說起

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

重點看@EnableAutoConfiguration,核心中的核心,重點中的重點。

在這里插入圖片描述

點進去 AutoConfigurationImportSelector

在這里插入圖片描述

可以看到 AutoConfigurationImportSelector 實現(xiàn)了 DeferredImportSelector,而DeferredImportSelector 又繼承了ImportSelector。

AutoConfigurationImportSelector類中重寫了ImportSelector接口的selectImports()方法:

在這里插入圖片描述

在這里插入圖片描述

再點進去

在這里插入圖片描述

可以看到這個getCandidateConfigurations()方法,就是去獲取META-INF/spring.factories文件中配置類的集合。

再接著點點點

在這里插入圖片描述

在這里插入圖片描述

以上就是SpringBoot自動裝配原理解析的詳細內容,更多關于SpringBoot自動裝配的資料請關注腳本之家其它相關文章!

相關文章

  • SpringCloud中@EnableDiscoveryClient注解詳解

    SpringCloud中@EnableDiscoveryClient注解詳解

    @EnableDiscoveryClient是Spring Cloud提供的一個核心注解,用于啟用服務發(fā)現(xiàn)功能,本文就來介紹一下SpringCloud中@EnableDiscoveryClient注解,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2026-02-02
  • Java實現(xiàn)學生成績管理系統(tǒng)

    Java實現(xiàn)學生成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Java三大特性之多態(tài)詳解

    Java三大特性之多態(tài)詳解

    多態(tài)是繼封裝、繼承之后,面向對象的第三大特性。多態(tài): 是指同一行為,具有多個不同表現(xiàn)形式。本文將來和大家詳細說說Java中的多態(tài),需要的可以了解一下
    2022-10-10
  • SpringBoot中的WebSocketSession原理詳解

    SpringBoot中的WebSocketSession原理詳解

    這篇文章主要介紹了SpringBoot中的WebSocketSession原理詳解,傳統(tǒng)的?HTTP?協(xié)議是無法支持實時通信的,因為它是一種無狀態(tài)協(xié)議,每次請求都是獨立的,無法保持連接。為了解決這個問題,WebSocket?協(xié)議被引入,需要的朋友可以參考下
    2023-07-07
  • java使用文件流實現(xiàn)查看下載次數(shù)

    java使用文件流實現(xiàn)查看下載次數(shù)

    這篇文章主要為大家詳細介紹了java使用文件流實現(xiàn)查看下載次數(shù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Java中序列化與反序列化的定義及代碼示例

    Java中序列化與反序列化的定義及代碼示例

    序列化是將對象狀態(tài)轉換為可存儲或傳輸格式的過程,反序列化則是將存儲或傳輸格式恢復為原始對象的逆過程,這篇文章主要介紹了Java中序列化與反序列化的相關資料,需要的朋友可以參考下
    2024-10-10
  • 五分鐘教你手寫 SpringBoot 本地事務管理實現(xiàn)

    五分鐘教你手寫 SpringBoot 本地事務管理實現(xiàn)

    這篇文章主要介紹了五分鐘教你手寫 SpringBoot 本地事務管理實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02
  • Java查詢MongoDB數(shù)據(jù)庫案例大全

    Java查詢MongoDB數(shù)據(jù)庫案例大全

    這篇文章主要給大家介紹了關于Java查詢MongoDB數(shù)據(jù)庫的一些相關案例,Java可以使用MongoDB的官方Java驅動程序來連接和操作MongoDB數(shù)據(jù)庫,需要的朋友可以參考下
    2023-07-07
  • SpringBoot中的Controller用法示例詳解

    SpringBoot中的Controller用法示例詳解

    Controller是SpringBoot里最基本的組件,他的作用是把用戶提交來的請求通過對URL的匹配,分配給不同的接收器,再進行處理,然后向用戶返回結果,這篇文章主要介紹了SpringBoot中的Controller用法,需要的朋友可以參考下
    2023-06-06
  • Java 如何創(chuàng)建和使用ExecutorService

    Java 如何創(chuàng)建和使用ExecutorService

    ExecutorService 是 Java 中用來管理和執(zhí)行多線程任務的一種高級工具,可以有效地管理線程的生命周期和任務的執(zhí)行過程,特別是在需要處理大量并發(fā)任務時尤為有用,本文給大家介紹Java 如何創(chuàng)建和使用ExecutorService,感興趣的朋友一起看看吧
    2025-05-05

最新評論

大兴区| 平远县| 社旗县| 桃园县| 兰州市| 丹江口市| 潍坊市| 北辰区| 岑溪市| 神池县| 喀什市| 上饶县| 府谷县| 永康市| 武穴市| 晋州市| 策勒县| 建昌县| 全椒县| 合山市| 玉门市| 峡江县| 克山县| 海城市| 五河县| 得荣县| 镇远县| 西畴县| 遂宁市| 安龙县| 岳西县| 嘉义县| 烟台市| 南康市| 张掖市| 旬邑县| 修文县| 云浮市| 原阳县| 尤溪县| 扎赉特旗|