SpringBoot - 自動裝配

欢乐豆123發表於2024-08-07

SpringBoot - 自動裝配

SpringBoot 最核心的功能就是自動裝配,

Starter 作為 SpringBoot 的核心功能之一,基於自動配置程式碼提供了自動配置模組及依賴的能力,讓軟體整合變得簡單、易用。使用 SpringBoot 時,我們只需引人對應的 Starter,SpringBoot 啟動時便會自動載入相關依賴,整合相關功能,這便是 SpringBoot 的自動裝配功能。

簡單概括其自動配置的原理:由@SpringBootAppliction組合註解中的@EnableAutoConfiguration註解開啟自動配置,載入 spring.factories 檔案中註冊的各種 AutoConfiguration 配置類,當其 @Conditional 條件註解生效時,例項化該配置類中定義的 Bean,並注入 Spring 上下文。


SpringBoot 自動裝配過程涉及以下主要內容:@EnableAutoConfiguration: 掃描類路徑下的META-INF/spring.factories檔案,並載入其中中註冊的 AutoConfiguration 配置類,開啟自動裝配;

spring.factories:配置檔案,位於 jar 包的 META-INF 目錄下,按照指定格式註冊了 AutoConfiguration 配置類;AutoConfiguration 類:自動配置類,SpringBoot 的大量以 xxxAutoConfiguration 命名的自動配置類,定義了三方元件整合 Spring 所需初始化的 Bean 和條件;@Conditional 條件註解及其行生註解:使用在 AutoConfiguration 類上,設定了配置類的例項化條件;Starter:三方元件的依賴及配置,包括 SpringBoot 預置元件和自定義元件,往往會包含 spring.factories 檔案、AutoConfiguration 類和其他配置類。其功能間的作用關係如下圖:


1. @EnableAutoConfiguration

2. @AutoConfigurationImportSelector

@EnableAutoConfiguration的自動配置功能是透過@Import註解匯入的ImportSelector來完成的。 @Import(AutoConfigurationlmportSelector.class)是@EnableAutoConfiguration註解的組成部分,也是自動配置功能的核心實現者。下面講解@Import的基本使用方法和ImportSelector的實現類AutoConfigurationlmportSelector。
2. @Import
@Import註解,提供了匯入配置類的功能。SpringBoot 的原始碼中,有大量的EnableXXX類都使用了該註解,瞭解@Import有助於我們理解 SpringBoot 的自動裝配,@Import有以下三個用途:

透過@Import引入@Configuration註解的類;
匯入實現了ImportSelector或ImportBeanDefinitionRegistrar的類;
透過@lmport匯入普通的POJO。

3. AutoConfigurationlmportSelector 實現類
@Import的許多功能都需要藉助介面ImportSelector來實現,ImportSelector決定可引人哪些 @Configuration的註解類,ImportSelector介面原始碼如下:
java 程式碼解讀複製程式碼public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}

ImportSelector介面只提供了一個引數為AnnotationMetadata的方法,返回的結果為一個字串陣列。其中引數AnnotationMetadata內包含了被@Import註解的類的註解資訊。在selectimports方法內可根據具體實現決定返回哪些配置類的全限定名,將結果以字串陣列的形式返回。如果實現了介面ImportSelector的類的同時又實現了以下4個Aware介面,那麼 Spring 保證在呼叫ImportSelector之前會先呼叫Aware介面的方法。這4個介面為:EnvironmentAware、BeanFactoryAware、 BeanClassLoaderAware和ResourceLoaderAware。
在AutoConfigurationlmportSelector的原始碼中就實現了這4個介面:


四、@Conditional 註解

@Conditional 註解允許你根據特定的條件來動態配置 Spring Bean。換句話說,只有在特定條件滿足的情況下,Spring 才會例項化和注入標註了 @Conditional 的 Bean。

@Conditional 註解本身並不包含具體的條件邏輯,而是依賴於實現了 Condition 介面的類來定義條件邏輯。使用時需要將實現了 Condition 介面的類作為引數傳遞給 @Conditional 註解。

1. Condition 介面

1 package org.springframework.context.annotation;
2 
3 import org.springframework.core.type.AnnotatedTypeMetadata;
4 
5 @FunctionalInterface
6 public interface Condition {
7     // 決定條件是否匹配
8     boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
9 }

matches方法的第一個引數為ConditionContext,可透過該介面提供的方法來獲得 Spring 應用的上下文資訊;matches方法的第二個引數為AnnotatedTypeMetadata,該介面提供了訪問特定類或方法的註解功能,可以用來檢查帶有@Bean註解的方法上是否還有其他註解。

2. conditional

1 @Target({ElementType.TYPE, ElementType.METHOD})
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 public @interface Conditional {
5     Class<? extends Condition>[] value();
6 }

@Conditional 註解唯一的元素屬性value是介面 Condition 的陣列,只有在陣列中指定的所有Conditionmatches方法都返回true的情況下,被註解的類才會被載入

3. @Conditional 的衍生註解

Spring 提供了一些常用的 @Conditional 註解,用於處理常見的條件邏輯:

  • @ConditionalOnProperty: 根據配置屬性來判斷是否注入 Bean。
  • @ConditionalOnClass: 當類路徑中存在特定的類時注入 Bean。
  • @ConditionalOnMissingBean: 當容器中不存在特定的 Bean 時注入。
  • @ConditionalOnBean: 當容器中存在特定的 Bean 時注入。
  • @ConditionalOnWebApplication: 只有在 Web 應用環境中才注入 Bean。
  • @ConditionalOnExpression: 根據 SpEL 表示式的結果來判斷是否注入 Bean。

透過一個舉例,我們看下衍生註解是如何發揮作用的。

1)spring.factories檔案

我們在spring.factories檔案中看到這一行自動配置類:

2)SpringApplicationAdminJmxAutoConfiguration實現類

其中有一個SpringApplicationAdminJmxAutoConfiguration實現類

1 # Auto Configure
2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
3 org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
4 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
5 org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
6 org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
7 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

找到SpringApplicationAdminJmxAutoConfiguration這個類的原始碼:

 1 @AutoConfiguration(
 2     after = {JmxAutoConfiguration.class}
 3 )
 4 @ConditionalOnProperty(
 5     prefix = "spring.application.admin",
 6     value = {"enabled"},
 7     havingValue = "true",
 8     matchIfMissing = false
 9 )
10 public class SpringApplicationAdminJmxAutoConfiguration {
11     
12     //...
13     
14     public SpringApplicationAdminJmxAutoConfiguration() {
15     }
16 
17     //...
18 }    

3)@ConditionalOnProperty 註解

 1 @Retention(RetentionPolicy.RUNTIME)
 2 @Target({ElementType.TYPE, ElementType.METHOD})
 3 @Documented
 4 @Conditional({OnPropertyCondition.class})
 5 public @interface ConditionalOnProperty {
 6     String[] value() default {};
 7 
 8     String prefix() default "";
 9 
10     String[] name() default {};
11 
12     String havingValue() default "";
13 
14     boolean matchIfMissing() default false;
15 }

這個註解中,各個屬性的作用
1. prefix 指定了屬性的字首

比如:prefix = "spring.application.admin",它表示所有相關屬性都應該以 spring.application.admin 開頭。

例如,這裡的完整屬性名是 spring.application.admin.enabled。

2. value 指定了具體的屬性名

value = {"enabled"},在這個例子中,它是 enabled。

與字首結合,這個屬性的完整名是 spring.application.admin.enabled。

3. havingValue 指定了配置屬性的期望值

havingValue = "true",只有當 spring.application.admin.enabled 的值為 true 時,條件才會滿足。

例如,只有在 application.properties 或 application.yml 檔案中配置了 spring.application.admin.enabled=true 時,註解標註的配置才會生效。

4. matchIfMissing 指定了當配置屬性缺失時是否預設匹配

matchIfMissing = false

如果 matchIfMissing 設定為 true,即使配置檔案中沒有 spring.application.admin.enabled 屬性,條件也會匹配。

如果 matchIfMissing 設定為 false(如本例), 當配置檔案中沒有 spring.application.admin.enabled 屬性時,條件不會匹配。


參考連結:https://juejin.cn/post/7137095650160115743

相關文章