1. 程式人生 > >Spring Boot註解

Spring Boot註解

自動配置

Spring使用@Configuration作為配置的註解,當Spring發現某個類使用了@Configuration標註了,就去將該類下尋找使用@Bean註解的方法建立bean並放入到容器中 @Configuration 在這裡插入圖片描述

spring boot的自動配置是通過@ConditionalOnXxx(@ConditionalOnClass、@ConditionalOnMissingBean等) 來實現的,該型別的註解都是基於@Conditional註解來實現的

關於自動配置可以通過瀏覽spring-boot-autoconfigure.jar下的spring.factories配置檔案,檢視所有的自動配置在這裡插入圖片描述

理解Spring Boot的自動配置先要理解@Conditional註解 @Bean: 將當前物件放入到Spring的IOC容器中來管理 @Conditional:滿足特定條件時才會建立一個Bean放入到IOC容器,SpringBoot就是利用這個特性進行自動配置的 在這裡插入圖片描述

寫一個小示例來理解下@Conditional的作用: 在不同的作業系統中列舉某個目錄下的檔案的命令是不同的,類unix系統使用ls命令,windows命令使用dir命令。現在定義兩個類分別對應著兩種系統,只將當前系統對應的類放入到IOC容器中,另一個類不放進IOC中 程式碼: OnWindowsCondition

public
class OnWindowsCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return conditionContext.getEnvironment().getProperty("os.name").contains("Windows"); } }

OnUnixCondition

public class
OnUnixCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String osName = conditionContext.getEnvironment().getProperty("os.name"); return osName.contains("unix") || osName.contains("linux") || osName.contains("Mac OS X"); } }

ListService

public interface ListService {
    public String cmd();
}
public class WindowsListService implements ListService {
    @Override
    public String cmd() {
        return "dir";
    }
}
public class UnixListService implements ListService {
    @Override
    public String cmd() {
        return "ls";
    }
}

ListSesrviceConfig 使用@Bean來標註將物件放入到IOC容器中,但是如果有@Conditional只有在滿足條件註解才會將物件放入到IOC容器中,不滿足就不會放入容器

@Configuration
public class ListSesrviceConfig {

    @Bean
    @Conditional(OnWindowsCondition.class)
    public ListService windowsListService(){
        return new WindowsListService();
    }

    @Bean
    @Conditional(OnUnixCondition.class)
    public ListService unixListService(){
        return new UnixListService();
    }

}

main() 在這裡插入圖片描述 會根據context.getEnvironment().getProperty(“os.name”)獲取當前的系統環境.在Windows電腦上執行就會裝載 WindowsListService,在Linux等環境上執行就會裝載UnixListService

@ConditionalOnXxx都是組合@Conditional元註解,使用了不同的條件Condition

  • @ConditionalOnBean:當容器裡有指定Bean的條件下
  • @ConditionalOnClass:當類路徑下有指定類的條件下
  • @ConditionalOnExpression:基於SpEL表示式作為判斷條件
  • @ConditionalOnJava:基於JV版本作為判斷條件
  • @ConditionalOnJndi:在JNDI存在的條件下差在指定的位置
  • @ConditionalOnMissingBean:當容器裡沒有指定Bean的情況下
  • @ConditionalOnMissingClass:當類路徑下沒有指定類的條件下
  • @ConditionalOnNotWebApplication:當前專案不是Web專案的條件下
  • @ConditionalOnProperty:指定的屬性是否有指定的值
  • @ConditionalOnResource:類路徑是否有指定的資源
  • @ConditionalOnSingleCandidate:當指定Bean在容器中只有一個,或者雖然有多個但是指定首選Bean
  • @ConditionalOnWebApplication:當前專案是Web專案的條件下

@SpringBootApplication

啟動入口:Application

@SpringBootApplication
public class SpringBootDemoApplication {

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

@SpringBootApplication 是一個複合註解,由以下3個註解組成:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

其中@SpringBootConfiguration實際上是@Configuration 在這裡插入圖片描述

@SpringBootConfiguration 在這裡插入圖片描述

將@SpringBootApplication註解替換成其等價的三個註解是完全的相等的,可以啟動並正常訪問 在這裡插入圖片描述

@ComponentScan

元件掃描這注解,即使沒有使用過註解也經常在spring的配置檔案中使用過 <context:component-scan base-package=“com.xxx.xxx”/>, 元件掃描就是掃描指定的包下的類,並載入符合條件的元件(比如@Component、@Service、@Repository等)或者bean定義,最終將這些bean定義載入到IoC容器中,如果不指定basePackage則預設Spring框架實現會從宣告@ComponentScan所在類的package進行掃描。Spring Boot 中的@ComponentScan沒有指定basePackage,所以會從.下開始掃描,所以,一般Application類要放在groupId.artifactId包下

@Configuration

@Configuration 就是指的Java Config(Java 配置),是一個Ioc容器類,相當於傳統專案中見到的一個spring 的xml配置檔案 在這裡插入圖片描述 在這裡插入圖片描述 一個空Java Config類 相當於一個空的xml配置檔案,都是用來作為配置bean的容器

在這裡插入圖片描述 在這裡插入圖片描述 在xml中配置一個bean,就等於在Java Config中定義一個方法,使用@Bean註解就相當於xml中的bean標籤,bean標籤中的id就是方法的名稱, bean標籤中的class就是Java Config中的返回值,Java Config中的方法的內部就是建立一個例項

在這裡插入圖片描述 在這裡插入圖片描述 xml中一個bean的屬性需要引用另一個bean時,在Java Config中需要先定義出需要的依賴類,然後通過Setter方法或者構造方法給依賴的屬性賦值,從而創建出一個完整的例項

@EnableAutoConfiguration

在這裡插入圖片描述 Spring中有很多以Enable開頭的註解,其作用就是藉助@Import來收集並註冊特定場景相關的bean,並載入到IoC容器。@EnableAutoConfiguration就是藉助@Import來收集所有符合自動配置條件的bean定義,並載入到IoC容器

@EnableAutoConfiguration通過@Import中的AutoConfigurationImportSelector,可以幫助SpringBoot應用將所有符合條件的@Configuration配置都載入到當前SpringBoot建立並使用的IoC容器(ApplicationContext) 在這裡插入圖片描述

SpringFactoriesLoader 主要功能就是從指定的配置檔案META-INF/spring.factories載入配置。配合@EnableAutoConfiguration使用的話,它更多是提供一種配置查詢的功能支援,即根據@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查詢的Key, 獲取對應的一組@Configuration類 在這裡插入圖片描述

spring.factories 在這裡插入圖片描述

@EnableAutoConfiguration自動配置就是從classpath中搜尋所有的META-INF/spring.factories配置檔案,並將其中org.springframework.boot.autoconfigure.EnableutoConfiguration對應的配置項通過反射(Java Refletion)例項化為對應的標註了@Configuration的JavaConfig形式的IoC容器配置類,然後彙總為一個並載入到IoC容器。 SpringApplication的run方法的實現是我們本次旅程的主要線路,該方法的主要流程大體可以歸納如下:

  1. 如果我們使用的是SpringApplication的靜態run方法,那麼,這個方法裡面首先要建立一個SpringApplication物件例項,然後呼叫這個建立好的SpringApplication的例項方法。在SpringApplication例項初始化的時候,它會提前做幾件事情: 根據classpath裡面是否存在某個特徵類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應該建立一個為Web應用使用的ApplicationContext型別。 使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationContextInitializer。 使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationListener。 推斷並設定main方法的定義類。
  2. SpringApplication例項初始化完成並且完成設定後,就開始執行run方法的邏輯了,方法執行伊始,首先遍歷執行所有通過SpringFactoriesLoader可以查詢到並載入的SpringApplicationRunListener。呼叫它們的started()方法,告訴這些SpringApplicationRunListener,“嘿,SpringBoot應用要開始執行咯!”。
  3. 建立並配置當前Spring Boot應用將要使用的Environment(包括配置要使用的PropertySource以及Profile)。
  4. 遍歷呼叫所有SpringApplicationRunListener的environmentPrepared()的方法,告訴他們:“當前SpringBoot應用使用的Environment準備好了咯!”。
  5. 如果SpringApplication的showBanner屬性被設定為true,則列印banner。
  6. 根據使用者是否明確設定了applicationContextClass型別以及初始化階段的推斷結果,決定該為當前SpringBoot應用建立什麼型別的ApplicationContext並建立完成,然後根據條件決定是否新增ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,當然,最重要的,將之前準備好的Environment設定給建立好的ApplicationContext使用。
  7. ApplicationContext建立好之後,SpringApplication會再次藉助Spring-FactoriesLoader,查詢並載入classpath中所有可用的ApplicationContext-Initializer,然後遍歷呼叫這些ApplicationContextInitializer的initialize(applicationContext)方法來對已經建立好的ApplicationContext進行進一步的處理。
  8. 遍歷呼叫所有SpringApplicationRunListener的contextPrepared()方法。
  9. 最核心的一步,將之前通過@EnableAutoConfiguration獲取的所有配置以及其他形式的IoC容器配置載入到已經準備完畢的ApplicationContext。
  10. 遍歷呼叫所有SpringApplicationRunListener的contextLoaded()方法。
  11. 呼叫ApplicationContext的refresh()方法,完成IoC容器可用的最後一道工序。
  12. 查詢當前ApplicationContext中是否註冊有CommandLineRunner,如果有,則遍歷執行它們。
  13. 正常情況下,遍歷執行SpringApplicationRunListener的finished()方法、(如果整個過程出現異常,則依然呼叫所有SpringApplicationRunListener的finished()方法,只不過這種情況下會將異常資訊一併傳入處理) 去除事件通知點後,整個流程如下: 在這裡插入圖片描述