1. 啟動類與main
方法
- 入口點:Spring Boot應用通常有一個帶有
@SpringBootApplication
注解的主類,并包含一個public static void main(String[] args)
方法。@SpringBootApplication
是一個組合注解,包含了:@Configuration
: 標記該類為配置類。@EnableAutoConfiguration
: 自動根據classpath中的依賴進行配置。@ComponentScan
: 自動掃描指定包及其子包下的組件(如@Component
,?@Service
,?@Repository
,?@Controller
等)。
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
2. 創建SpringApplication
實例
- 構造函數:
- 推斷應用類型:檢查classpath中是否存在特定的類(如Servlet、Reactive相關的類),以確定是Servlet還是Reactive應用。
- 加載初始器和監聽器:從
META-INF/spring.factories
文件中加載默認的ApplicationContextInitializer
和ApplicationListener
。
3.?SpringApplication.run()
?方法執行
環境準備
- 創建并配置Environment:基于命令行參數、系統屬性、環境變量等初始化
Environment
對象。- 可以通過
--spring.config.location
或SPRING_CONFIG_LOCATION
環境變量指定外部配置文件的位置。
- 可以通過
- 觸發事件:發布
ApplicationEnvironmentPreparedEvent
事件,允許外部工具或開發者自定義環境設置。- 可以通過實現
ApplicationListener<ApplicationEnvironmentPreparedEvent>
來自定義邏輯。
- 可以通過實現
打印Banner
- 如果啟用了banner,則顯示項目啟動的圖形化標識。
- 可以通過設置
spring.main.banner-mode
為off
來關閉banner。
- 可以通過設置
創建ApplicationContext
- 根據應用類型選擇合適的
ApplicationContext
實現(例如,對于Web應用通常是AnnotationConfigServletWebServerApplicationContext
)。- 對于非Web應用,可能是
AnnotationConfigApplicationContext
。
- 對于非Web應用,可能是
加載Sources
- 將所有指定的source(通常是帶有
@Configuration
注解的類)注冊到ApplicationContext
中。- 這包括了自動掃描到的組件和顯式聲明的配置類。
刷新上下文前的準備工作
- 觸發
ApplicationContextInitializedEvent
事件。 - 調用所有的
ApplicationContextInitializer
進行額外的配置。- 這些initializer可以在刷新之前對context進行進一步的定制。
4. ApplicationContext刷新過程
BeanFactory準備
- 設置bean工廠的各種屬性,包括轉換服務、屬性編輯器等。
- 配置了諸如
PropertyEditorRegistrar
等用于處理屬性值轉換的機制。
- 配置了諸如
BeanDefinition加載
- 掃描classpath:尋找帶有
@Component
,?@Service
,?@Repository
,?@Controller
等注解的類,并將其注冊為bean definitions。- 使用
ClassPathScanningCandidateComponentProvider
掃描指定包下的組件。 - 條件注解(如
@ConditionalOnClass
,?@ConditionalOnMissingBean
等)確保僅在滿足特定條件時才生效。
- 使用
自動配置
- 自動配置機制:通過
@EnableAutoConfiguration
觸發自動配置過程。它會根據classpath中的依賴自動配置相應的beans。- 自動配置類位于
spring-boot-autoconfigure
模塊中,它們通過spring.factories
文件被發現并加載。 - 每個自動配置類都可能有條件注解,確保僅在滿足特定條件時才生效。
- 自動配置類位于
BeanFactoryPostProcessor執行
- 處理各種后處理器,如
PropertySourcesPlaceholderConfigurer
用于解析占位符。- 解析
${...}
形式的屬性值,替換為實際值。
- 解析
Bean實例化
- 根據bean definitions實例化單例bean,并進行依賴注入。
- 初始化bean時,可能還會執行一些生命周期回調方法,如
@PostConstruct
標注的方法。 - 如果需要AOP代理,則在此階段生成代理對象。
- 初始化bean時,可能還會執行一些生命周期回調方法,如
5. 刷新完成后的工作
- 觸發ContextRefreshedEvent:表示
ApplicationContext
已完全刷新。 - 執行CommandLineRunner/ApplicationRunner beans:如果有任何實現了
CommandLineRunner
或ApplicationRunner
接口的beans,它們的方法會被調用。- 這些runner可以用來執行最后的初始化操作。
6. 應用就緒
- 觸發ApplicationReadyEvent:表示應用已經準備好接收請求或執行預定的任務。
- 開啟web服務器:如果是Web應用,此時嵌入式的Tomcat服務器將會啟動,并開始監聽HTTP請求。
7. 錯誤處理
- 錯誤處理機制:Spring Boot提供了強大的錯誤處理機制,包括但不限于自定義錯誤頁面、全局異常處理器等,以增強應用的健壯性。
- 可以通過實現
ErrorController
來自定義錯誤頁面。 - 使用
@ControllerAdvice
和@ExceptionHandler
來處理全局異常。
- 可以通過實現
額外細節
-
外部化配置:支持多種方式的外部化配置,如命令行參數、環境變量、properties/yaml文件等。
- 可以通過
application.properties
或application.yml
文件進行配置。 - 支持使用
@Value
注解直接注入配置值。 - 可以通過
spring.profiles.active
指定激活的profile,從而加載不同的配置。
- 可以通過
-
健康檢查和度量:通過Actuator模塊提供的端點,可以監控應用的健康狀況和性能指標。
- 提供了諸如
/actuator/health
、/actuator/metrics
等端點。 - 可以自定義健康指示器(Health Indicator)來擴展健康檢查功能。
- 提供了諸如
-
日志配置:Spring Boot默認支持多種日志框架,并可以通過簡單的配置定制日志級別和輸出格式。
- 支持Logback、Log4j2等日志框架,默認使用Logback。
- 可以通過
logging.level.*=DEBUG
等配置項調整日志級別。
關鍵技術細節
- 條件注解:如
@ConditionalOnClass
,?@ConditionalOnMissingBean
等,使得Spring Boot能夠根據當前環境動態地啟用或禁用某些配置。 - 事件驅動模型:Spring Boot在整個啟動過程中使用了大量的事件發布和監聽機制,這使得開發者可以在應用啟動的不同階段插入自定義邏輯。
- 例如,可以通過實現
ApplicationListener<ApplicationStartedEvent>
來自定義啟動邏輯。
- 例如,可以通過實現
示例代碼片段
以下是一個更完整的示例,展示了如何使用Spring Boot的基本結構,并結合了一些高級特性和配置:
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication app = new SpringApplication(DemoApplication.class);// 關閉bannerapp.setBannerMode(Banner.Mode.OFF);// 添加自定義的ApplicationContextInitializerapp.addInitializers(new MyCustomApplicationContextInitializer());app.run(args);}
}@Component
public class MyCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("MyCommandLineRunner executed");}
}@Configuration
public class MyCustomConfig {@Bean@ConditionalOnMissingBean(name = "customBean")public String customBean() {return "This is a custom bean";}
}// 自定義健康檢查
@Component
public class CustomHealthIndicator extends AbstractHealthIndicator {@Overrideprotected void doHealthCheck(Health.Builder builder) throws Exception {builder.up().withDetail("custom", "Everything is OK!");}
}// 全局異常處理器
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(value = Exception.class)public ResponseEntity<Object> exception(Exception exception) {return new ResponseEntity<>("An error occurred: " + exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);}
}// 自定義ApplicationContextInitializer
public class MyCustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment environment = applicationContext.getEnvironment();// 自定義環境配置Map<String, Object> map = new HashMap<>();map.put("my.custom.property", "customValue");environment.getPropertySources().addFirst(new MapPropertySource("customProperties", map));}
}