啟動入口
@SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class);
}
}
@SpringBootApplication
裡面就包含了
@SpringBootConfiguration
@EnableAutoConfiguration
啟用應用的自動設定功能
@ComponentScan
自動掃描 sub packages 裡面的 Spring Component
啟動 application
SpringApplication.run(Demo1Application.class);
也可以拆開
SpringApplication springApplication = new SpringApplication(Demo1Application.class);
springApplication.run(args);
也可以用 SpringApplicationBuilder
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Demo1Application.class)
.banerMode(Banner.Mode.OFF)
.run(args);
jar 啟動
application 的 main 通常是在 console 啟動時被呼叫,如果打包成 jar,就會是另一種狀況
project 可用 mvn package
打包成 jar
|____org
| |____springframework
| | |____boot
| | | |____loader
| | | | |____ref
| | | | |____net
| | | | |____jarmode
| | | | |____launch
| | | | |____jar
| | | | |____zip
| | | | |____nio
| | | | |____log
|____META-INF
| |____MANIFEST.MF
| |____maven
| | |____tw.com.test
| | | |____demo1
| | | | |____pom.xml
| | | | |____pom.properties
| |____services
| | |____java.nio.file.spi.FileSystemProvider
|____BOOT-INF
| |____classes
| | |____tw
| | | |____com
| | | | |____test
| | | | | |____demo1
| | | | | | |____Demo1Application.class
| | |____application.yml
| |____layers.idx
| |____classpath.idx
| |____lib
BOOT-INF: 啟動 application 所需要的 classes
META-INF: application打包的相關描述檔案
org: spring boot 啟動所需要的引導類別
META-INF/MENIFEST.MF
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.4.2
Build-Jdk-Spec: 17
Implementation-Title: demo1
Implementation-Version: 0.0.1-SNAPSHOT
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: tw.com.test.demo1.Demo1Application
Spring-Boot-Version: 3.3.5
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Main-Class: 啟動的引導類別
Start-Class: application 啟動類別
啟動的 log 可透過設定關閉
spring:
main:
log-startup-info: false
或是
SpringApplication springApplication = new SpringApplication(Demo1Application.class);
springApplication.setLogStartupInfo(false);
springApplication.run(args);
啟動失敗分析
由 FailureAnalyzer interface 處理
ex: PortInUseFailureAnalyzer 可處理重複使用 TCP Port 的 exception
可以自訂一個 PortInUseFailureAnalyzer
package tw.com.test.demo1;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.boot.web.server.PortInUseException;
public class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
return new FailureAnalysis(cause.getPort()+"PortInUse", "check "+cause.getPort(), cause);
}
}
然後在 META-INF/spring.factories
org.springframework.boot.diagnostics.FailureAnalyzer=\
tw.com.test.demo1.PortInUseFailureAnalyzer
也可以自訂自己的 applicaton exception,以及對應的 FailureAnalyzer
啟動 Banner
Text to ASCII Art Generator (TAAG) 這是將 text 轉換為 ascii 文字的網頁工具。
將要列印的 application 文字,轉換為 ascii 後,儲存到 /resources/banner.txt。啟動 application 時,就會看到 banner 已經換掉了。
以下是一些相關設定
# banner.txt encoding
spring.banner.charset=UTF-8
# banner.txt filepath
spring.banner.location=classpath:banner.txt
# console/log/off
spring.main.banner-mode=console
啟動事件與 listener
spring-boot-3.3.5.jar
META-INF/spring.factories 裡面註冊的 listener,這些都實作了 Spring 的 ApplicationListener interface
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
啟動事件的順序
ApplicationStartingEvent
spring application 啟動前發送
ApplicationEnvironmentPreparedEvent
已知要在 context 使用 spring 的 Environment 時,在 context 建立之前發送
ApplicationContextInitializedEvent
ApplicationContext 準備好了,ApplicationContextInitializer 已被呼叫,在 bean 載入前發送
ApplicationPreparedEvent
在 context refresh 前,且在 bean 定義被載入後發送
ApplicationStartedEvent
在 Spring context refresh 以後,在 application / CLI runner 呼叫前發送
AvailabilityChangeEvent
跟著上一個事件後發送,ReadinessState.CORRECT,代表 application 已處於活動狀態
ApplicationReadyEvent
在 application / CLI runner 呼叫後發送
AvailabilityChangeEvent
跟著上一個事件後發送,ReadinessState.ACCEPTING_TRAFFIC,代表 application 已經準備接收 request
ApplicationFailedEvent
在啟動異常時發送
以上只有 SpringApplication 發出的 SpringApplicationEvents 事件。
以下事件會在 ApplicationPreparedEvent 後,ApplicationStartedEvent 前發送
WebServerInitializedEvent
WebServer 啟動後發送。包含 ServletWebServerInitialziedEvent, ReactiveWebServerInitializedEvent
ContextRefreshedEvent
在 ApplicationContext refresh 後發送
自訂事件 listener
Demo1ApplicationListener.java
package tw.com.test.demo1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class Demo1ApplicationListener implements ApplicationListener<AvailabilityChangeEvent> {
@Override
public void onApplicationEvent(AvailabilityChangeEvent event) {
log.info("got event: {}, state: {}", event, event.getState());
if( ReadinessState.ACCEPTING_TRAFFIC == event.getState() ) {
log.info("applcation is started!");
}
}
}
啟動測試
2024-11-15T16:26:43.269+08:00 INFO 4595 --- [ main] t.c.test.demo1.Demo1ApplicationListener : got event: org.springframework.boot.availability.AvailabilityChangeEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5674e1f2, started on Fri Nov 15 16:26:40 CST 2024], state: CORRECT
2024-11-15T16:26:43.273+08:00 INFO 4595 --- [ main] t.c.test.demo1.Demo1ApplicationListener : got event: org.springframework.boot.availability.AvailabilityChangeEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@5674e1f2, started on Fri Nov 15 16:26:40 CST 2024], state: ACCEPTING_TRAFFIC
2024-11-15T16:26:43.273+08:00 INFO 4595 --- [ main] t.c.test.demo1.Demo1ApplicationListener : applcation is started!
Runner
在 application 啟動前,執行一些 code
ApplicationRunner
CommandLineRunner
有 @Component
或是 lambda 的 @Bean
兩種寫法
package tw.com.test.demo1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@SpringBootApplication
@Slf4j
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class);
}
@Component
public class Demo1ApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("ApplicationRunner runner args={}", args);
}
}
// @Bean
// public ApplicationRunner applicationRunner() {
// return new Demo1ApplicationRunner();
// }
@Bean
public ApplicationRunner applicationRunner2() {
return (args) -> {
log.info("CommandLineRunner2 args={}", args);
};
}
@Bean
public CommandLineRunner commandLineRunner() {
return (args) -> {
log.info("CommandLineRunner args={}", args);
};
}
}
執行結果
2024-11-15T16:57:46.247+08:00 INFO 4793 --- [ main] tw.com.test.demo1.Demo1Application : CommandLineRunner args={}
2024-11-15T16:57:46.248+08:00 INFO 4793 --- [ main] tw.com.test.demo1.Demo1Application : CommandLineRunner2 args=org.springframework.boot.DefaultApplicationArguments@d535a3d
2024-11-15T16:57:46.249+08:00 INFO 4793 --- [ main] tw.com.test.demo1.Demo1Application : ApplicationRunner runner args=org.springframework.boot.DefaultApplicationArguments@d535a3d