您好,登錄后才能下訂單哦!
這篇文章主要講解了“Spring Application怎么配置”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring Application怎么配置”吧!
目前Spring Boot已經發展到2.3.4.RELEASE ,對于它的好處網上也是鋪天蓋地的,這里就不再重復了。直接說重點,從Spring Boot1.x一步步跟著迭代升級到現在的2.3.4也是遇到了很多的坑,了解其新版本的特性是非常重要的,可以幫助我們避免很多不必要的麻煩。
因為我也一直在搞基于Spring Boot技術棧的組件開發工作,最近準備針對基礎組件進行部分重構,所以順便把當前版本的特性從頭在順一遍,就當是回顧總結了,這個回顧只介紹目前版本的一些特性,不對特性展開來敘述,如果有興趣可以@我,后面我也會根據某一塊來進行詳細的分析。喜歡的朋友可以跟著看一看,希望對你有所幫助。
如果應用啟動失敗,Spring Boot會幫我們把大概為什么會啟動失敗的信息打印在日志中,如下面我用6080端口第二次啟動應用就會提示我如下
*************************** APPLICATION FAILED TO START *************************** Description: Embedded servlet container failed to start. Port 6080 was already in use. Action: Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
有了這種友好的提示真是幸福感爆棚啊,而且Spring Boot 還給我們提供了更多的擴展接口FailureAnalyzer,并提供了響應得抽象類AbstractFailureAnalyzer。如果我們不滿足他默認的啟動異常信息,就可以通過FailureAnalyzer 來進行一些定制化開發(比如在異常發生的時候打印堆棧等).FailureAnalyzer的擴展使用了SPI的方式,所以在我們使用的時候需要在應用內創建META-INF/spring.factories,來聲明下我們的實現,下面上個小demo。
/** 首先創建我們自己的類,并且可以根據自己的需要來進行異常攔截,這里我攔截的就是端口占用異常PortInUseException * @ClassName LearningFailureAnalyzer * @Author QIANGLU * @Date 2020/9/23 9:10 下午 * @Version 1.0 */ public class LearningFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> { private static final Logger LOGGER = LoggerFactory.getLogger(LearningFailureAnalyzer.class); @Override protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) { LOGGER.error("我出異常了,哇卡卡卡卡卡卡"); return new FailureAnalysis("端口:" +cause.getPort()+"被占用",cause.getMessage(),rootFailure); } } //第二步就是創建個META-INF/spring.factories 了,如下 org.springframework.boot.diagnostics.FailureAnalyzer=\ com.qianglu.chapter1.failure.LearningFailureAnalyzer //第三布啟動兩次我們的應用,就會發現,打印的信息是我們需要的了 *************************** APPLICATION FAILED TO START *************************** Description: 端口:6080被占用 Action: Port 6080 is already in use
這東西可用場景其實很多很多,大家想一想有沒有點啟發
在Spring Boot剛出的時候,因為啟動加載慢還被人吐槽過,這不,現在懶加載來了。允許你的應用開啟懶加載,你的beans 不需要在項目啟動的時候被創建了,啥時候用啥時候在創建。這樣就能節省你很多啟動時間,但有利就有弊,懶加載這玩意在web應用中會導致你很多web相關的bean也被延遲加載,知道有請求進來才會被初始化,所以在使用的時候一定要注意,否則就會有叫你很懵逼的異常了。
并且官方也說了,你都延遲初始化了,那有些問題可能也會延遲被發現。比如我們以前某些配置配錯了,經常會在啟動的時候就報XXXbean不能被找到之類的。嘿嘿,現在可就不了,一樣的啟動成功,只有在你用的時候給你掉鏈子,就問你怕不怕吧。
還有就是官方提示延遲初始化的,會導致初期jvm 內存表現比較小,但要注意配置足夠的內存給未來對象創建使用(我覺得一般應用這都不是問題,不需要過多關注)。
下面我們就來看看兩種配置方式:
使用SpringApplication調用setLazyInitialization 方法設置
使用配置spring.main.lazy-initialization=true
如果你設置了延遲初始化,又有某些特殊的類想初始化,那可以配置@Lazy(false) 關閉其懶加載。
這玩意說實話我一直不知道有啥用,以前我們都是配置個大佛保平安,娛樂性大于實際吧,當然也許有沒GET到的點。
配置方式也很簡單,就是在你的classpath下放個banner.txt,通過spring.banner.location 配置來指定下文件位置。當然還有很多屬性,什么編碼、gif、version之類的我其實懶得說了,沒啥興趣。
####4、配置你的SpringApplication
咱們一般啟動類都是直接調用SpringApplication.run就行了。但如果你覺得太簡單沒啥意思,那其實SpringApplication.run 里面有很多有意思的屬性你可以去看看,比如我關閉banner
public static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }
當然還有很多配置屬性,你也可以使用application.yml來配置SpringApplication 的屬性。
官方提供了SpringApplicationBuilder 類來幫大家使用流式構建的方式來創建多級的ApplicationContext。SpringApplicationBuilder可以幫助我們構建一種層級關系,如下這種方式等于SpringApplication.run
new SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .bannerMode(Banner.Mode.OFF) .run(args);
這里說的其實就是k8s的Liveness 和 Readiness ,他們已經成為了Spring Boot的核心。
簡單說下,Liveness 和 Readiness 在k8s中代表了應用程序狀態的各個方面。
Liveness 狀態來查看內部情況可以理解為health check,如果Liveness失敗就就意味著應用處于故障狀態并且目前無法恢復,這種情況就重啟吧。
Readiness 狀態用來告訴應用是否已經準備好接受客戶端請求,如果Readiness未就緒那么k8s就不能路由流量過來。
我們可以用代碼來監聽Readiness狀態,并進行我們需要的處理
@Component public class ReadinessStateExporter { @EventListener public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) { switch (event.getState()) { case ACCEPTING_TRAFFIC: // xxxxx break; case REFUSING_TRAFFIC: // xxxxxx break; } } }
我們也能在應用出現故障不能被恢復的時候改變此狀態來進行動態的降級和隔離,這個真是太爽了,有機會建議大家試一試
@Component public class LocalCacheVerifier { private final ApplicationEventPublisher eventPublisher; public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } public void checkLocalCache() { try { //... } catch (CacheCompletelyBrokenException ex) { AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN); } } }
Spring Boot的事件通知機制,簡直是解耦神器,包括Spring Cloud的用的分布式遠程通知機制其實核心也是這個,這是增加了一層中間件來進行消息的傳遞。
有些事件因為實在ApplicationContext創建前就觸發了,所以很多時候不能使用@Bean來聲明這些事件。最好使用SpringApplication.addListeners(…)
和 SpringApplicationBuilder.listeners(…)
來注冊監聽器。
但如果你真是把握不了這些加載時機的話,那有個萬能的辦法就是配置SPI擴展,直接在META-INF/spring.factories 配置,加上你得listener就行了,如:org.springframework.context.ApplicationListener=com.example.project.MyListener
官方介紹了寫在啟動時候會發送的事件順序:
1、ApplicationStartingEvent 在運行開始的時候發送事件
2、ApplicationEnvironmentPreparedEvent 當Environment在上下文中被使用的時候發送事件
3、ApplicationContextInitializedEvent 在所有的bean定義前,ApplicationContext準備好并且ApplicationContextInitializers已經被調用的時候發送事件
4、ApplicationPreparedEvent 刷新配置前、bean的定義加載之后發送事件
5、ApplicationStartedEvent 刷新上下文后,在執行CommandLineRunner的實現之前
6、AvailabilityChangeEvent 發送LivenessState.CORRECT 表面應用是活躍狀態
7、ApplicationReadyEvent 在執行CommandLineRunner接口之后發送
8、AvailabilityChangeEvent 發送ReadinessState.ACCEPTING_TRAFFIC 后代表應用可以接入流量
9、ApplicationFailedEvent 發送應用啟動失敗事件
上面的只是SpringApplicationEvent
的事件,一般咱們也不需要對這些進行操作,帶你得知道它的存在,以免出了問題都不知道怎么找,其實人家Spring Boot已經都發給你了。
一般使用SpringApplication就會為我們正確的創建ApplicationContext類型,用于確定WebApplicationType 也就是應用類型的方式其實很簡單:
如果存在Spring MVC 就使用AnnotationConfigServletWebServerApplicationContext
如果Spring MVC不存 在,但是Spring WebFlux存在,就使用AnnotationConfigReactiveWebServerApplicationContext
都沒有的話就用AnnotationConfigApplicationContext
如果你既用了Spring MVC 又用了Spring WebFlux WebClient,Spring MVC 這一套是默認使用的,除非你設置SpringApplication.setWebApplicationType(WebApplicationType)來強制改變。
如果你想訪問SpringApplication.run(…) 的參數,你其實可以注入一個org.springframework.boot.ApplicationArguments 對象,ApplicationArguments這個接口提供對原始String[] 參數以及已解析的選項和非選項參數的訪問,上demo:
import org.springframework.boot.*; import org.springframework.beans.factory.annotation.*; import org.springframework.stereotype.*; @Component public class MyBean { @Autowired public MyBean(ApplicationArguments args) { boolean debug = args.containsOption("debug"); List<String> files = args.getNonOptionArgs(); // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"] } }
Spring Boot 中的環境變量也注冊了一個CommandLinePropertySource,我們可以使用@Value來獲取某個環境變量。
這倆貨也是我們經常會用到的東西,如果你需要在項目啟動時加載一些東西,那它倆簡直就是神器了,這倆接口都提供了一個run方法,這個方法會在SpringApplication.run(…) 執行完成前被調用。這倆接口適合哪種在應用接收請求前來處理一些東西。
舉個使用例子
import org.springframework.boot.*; import org.springframework.stereotype.*; @Component public class MyBean implements CommandLineRunner { public void run(String... args) { // Do something... } }
如果咱們定義了多個CommandLineRunner或ApplicationRunner實現,有的時候又需要有個先后順序來執行,那就可以用org.springframework.core.annotation.Order 這個注解來定義下。
每個SpringApplication 都會像JVM注冊一個關閉鉤子(shutdown hook ),來確保能夠正常的退出。保證@PreDestroy 注解和DisposableBean 接口這些回調都被執行。
另外,如果你想在使用SpringApplication.exit() 時返回一些特殊的退出代碼,可以實現org.springframework.boot.ExitCodeGenerator接口,傳遞給System.exit() 進行返回。如:
@SpringBootApplication public class ExitCodeApplication { @Bean public ExitCodeGenerator exitCodeGenerator() { return () -> 42; } public static void main(String[] args) { System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args))); } }
ExitCodeGenerator接口可以通過異常實現。遇到此類異常時,Spring Boot返回實現的getExitCode() 方法提供的退出代碼
我們可以使用spring.application.admin.enabled 屬性來開啟管理員功能。開了的話就會把你自己的SpringApplicationAdminMXBean
全部暴露給MBeanServer咯,當然你也可以用這種特性來遠程操作你應用。但你要想明白其中的安全性問題,沒啥必要的話還是不要亂搞。
感謝各位的閱讀,以上就是“Spring Application怎么配置”的內容了,經過本文的學習后,相信大家對Spring Application怎么配置這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。