掃碼關注公眾號,領取更多資源
@
目錄- Spring Boot
- Spring Boot 核心功能
- Spring Boot優缺點
- 優點
- 缺點
- 創建一個簡單的Spring Boot專案
- @SpringBootApplication注解
- @Configuration
- @EnableAutoConfiguration注解
- SpringApplication.run()執行流程
- 一個好玩的擴展
- SpringApplication完整執行流程
- SpringApplicationRunListener
- ApplicationListener
- ApplicationContextInitializer
- CommandLineRunner
- Spring Boot自動配置
- 基于條件的自動配置
- 調整自動配置的順序
- Spring-Boot-Starter常用依賴
- 應用日志spring-boot-starter-logging
- web應用開發spring-boot-starter-web
- 資料訪問spring-boot-starter-jdbc
- 其他的依賴
- SpringBoot微服務的注冊與發現
Spring Boot
Spring Boot
是由 Pivotal
團隊提供用來簡化 Spring
的搭建和開發程序的全新框架,隨著近些年來微服務技術的流行,Spring Boot
也成了時下炙手可熱的熱點技術,
Spring Boot
去除了大量的 xml
組態檔,簡化了復雜的依賴管理,配合各種 starter
使用,基本上可以做到自動化配置,Spring
可以做的事情,現在用 Spring boot
都可以做,
過去使用Spring
創建一個可運行的專案需要進行大量的配置作業,很是繁瑣,SpringBoot
使用習慣優于配置
的理念,內置一個默認配置,無需手動,可以讓專案快速運行起來,
Spring Boot 核心功能
- 獨立運行的Spring專案
Spring Boot
可以以jar包的形式獨立運行,運行一個Spring Boot
專案只需要通過java -jar xx.jar
即可, - 內嵌Servlet容器
Spring Boot
可以選擇內嵌Tomcat
,Jetty
或者Undertow
,這樣就可以無需使用war
包形式部署專案, - 提供starter,簡化Maven配置
Spring Boot
提供一系列的starter pom
來簡化Maven依賴添加, - 自動配置Spring
Spring Boot
可以根據類路徑中的jar包,類,自動配置Bean,減少了配置作業量, - 準生產的應用監控
Spring Boot
提供http
,ssh
,telnet
對專案進行實時監控, - 無代碼生成和xml配置
Spring Boot
通過注解實作自動配置
,可以無需任何xml就能完成所有配置,
Spring Boot優缺點
優點
- 快速構件專案
- 無配置快速繼承主流框架
- 可獨立運行
- 提供運行時監控
- 提高開發部署效率
- 與云計算天然集成
缺點
- 迭代速度快,某些模塊改動較大
- 因為不用手動配置,報錯難以定位
創建一個簡單的Spring Boot專案
打開http://start.spring.io/
,選擇Java語言開發,填寫專案資訊,然后下載代碼,如下圖:
解壓后可以得到一個Spring Boot
的啟動類,代碼如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
直接選擇當前啟動類選擇運行,一個簡單的Spring Boot
專案就啟動成功了,
@SpringBootApplication注解
@SpringBootApplication
是一個復合的注解,他是如下幾個注解組合而成:
- @Configuration
- @EnableAutoConfiguration
- @ComponentScan
在啟動類上加上如上三個注解可以達到與@SpringBootApplication
一樣的效果,顯然后者更加方便些,
@Configuration
這里的就是Spring IOC
中使用的那個配置,既然Spring Boot
本質上就是一個Spring
應用,那么自然也需要加載某個IOC
容器配置,所以加上@Configuration
,本質上也是IOC
容器的配置類,
所以上面的啟動類也可以拆分為如下兩個類:
//配置類
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoConfiguration {
@Bean
public Controller controller() {
return new Controller();
}
}
//啟動類
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConfiguration.class, args);
}
}
在如上兩個類中,DemoApplication
其實就是一個普通的啟動類,而DemoConfiguration
就是一個普通的配置類而已,
@EnableAutoConfiguration注解
@EnableAutoConfiguration
也是一個復合的注解,主要包含如下兩個:
- @AutoConfigurationPackage
- @Import(EnableAutoConfigurationImportSelector.class)
其中最關鍵的是@Import(EnableAutoConfigurationImportSelector.class)
,他借助EnableAutoConfigurationImportSelector
這個類,將當前應用所有符合條件的@Configuration
配置都加載到當前Spring Boot
應用的IOC
容器中去,
SpringApplication.run()執行流程
SpringApplication
在沒有特殊要求的情況下,默認使用模板化的情動流程,但是SpringApplication
也在合適的流程節點開放了不用型別的擴展,我們可以對這些擴展點對SpringBoot
的啟動和關閉流程進行修改擴展,
一個好玩的擴展
在之前的啟動類的main
方法中只有這么簡單的依據話:
SpringApplication.run(DemoApplication.class,args);
正常情況下,一個SpringBoot
專案啟動后會在列印臺或者日志中列印一個字符畫,
但是我們可以在SpringApplication
中來修改列印的內容,對啟動流程進行擴展:
public class DemoApplication {
public static void main(String[] args) { //SpringApplication.run(DemoConfiguration.class, args);
SpringApplication bootstrap = new SpringApplication(Demo - Configuration.class);
bootstrap.setBanner(new Banner() {
@Override
public void printBanner(Environment environment, Class<?> aClass, PrintStream printStream) {
// 比如列印一個我們喜歡的ASCII Arts字符畫
}
});
bootstrap.setBannerMode(Banner.Mode.CONSOLE);
// 其他定制設定...
bootstrap.run(args);
}
}
修改banner
還有一個簡單的方式,就是把需要列印的字符放到一個資源檔案中,然后通過ResourceBanner
加載:
bootstrap.setBanner(new ResourceBanner(new ClassPathResource("banner.txt")));
正常情況下我們不需要對這個設定進行定制,因為真正的啟動邏輯才是我們需要關注的,這只是為了好玩,
SpringApplication完整執行流程
SpringApplication
中的run()
方法主要的流程大體可以概括為如下幾個步驟:
- 如果我們直接使用
SpringApplication
中的靜態run()
,那么,在這個方法中會自動創建一個SpringApplication
的實體物件,然后呼叫這個實體物件的run()
,
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fsJsNZkq-1604679639272)(Boot.assets/螢屏快照 2020-11-03 13.22.30.png)]
在實體化
SpringApplication
的時候,會提前做好如下幾件事情
- 根據
classpath
中是否存在ConfigurableWebApplicationContext
來決定創建的ApplicationContext
型別SpringFactoriesLoader
在classpath
中查找并加載所有可用ApplicationContextInitializer
SpringFactoriesLoader
在classpath
中查找并加載所有可用ApplicationListener
- 推斷并設定
main
方法的定義
- 在
SpringApplication
初始化并完成設定后就開始執行run
方法的邏輯了,在執行之前,需要通過SpringFactoriesLoader
加載所有的SpringApplicationRunListener
,呼叫他們的started()
,通知這些類開始執行當前應用, - 創建并設定當前
SpringBoot
應用需要使用的Environment
,包括配種的PropertySource
和Profile
, - 呼叫所有
SpringApplicationRunListener
的environmentPrepared()
方法 - 根據用戶設定,創建對應型別的
ApplicationContext
,并將之前準備好的Environment
設定給創建號的ApplicationContext
使用, - 借助
SpringFactoriesLoader
,加載之前的ApplicationContextInitializer
,然后呼叫initialize(applocationContext)
方法對Application
進一步處理, - 呼叫所有
SpringApplicationRunListener
的contextPrepared()
方法 - 將通過
@EnableAutoConfiguration
獲取的所有配置以及其他形式的IOC
容器配置加載到已經準備完畢的ApplicationContext
中, - 遍歷呼叫所有
SpringApplicationRunListener
的contextLoaded()
方法,告訴所有的SpringApplicationRunListener
,ApplicationContext
準備完畢, - 呼叫
ApplicationContext
的refresh()
方法, - 執行
ApplicationContext
中注冊的CommandLineRunner
, - 遍歷執行
SpringApplicationRunListener
的finish()
方法,
至此,一個完整的SpringBoot
應用啟動完畢,啟動的程序很多都是一些通知事件的擴展點,如果忽略這些程序,可以將啟動的邏輯精簡到如下幾步:
對比可以發現,SpringApplication
提供的擴展點占了啟動邏輯的很大一部分,除了初始化并準備好ApplicationContext
之外,剩下的大部分作業都是通過擴展點完成的,下面對這些擴展點進行詳細的講解,
SpringApplicationRunListener
SpringApplicationRunListener
是一個在SpringBoot
的main
方法執行程序中接收事件通知的監聽者,主要方法如下:
public interface SpringApplicationRunListener {
void started();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void finished(ConfigurableApplicationContext context, Throwable exception);
}
正常情況下,我們并不需要自己實作一個SpringApplicationRunListener
,SpringBoot
也只是實作了一個EventPublishingRunListener
,用于處理SpringBoot
啟動時不同的ApplicationEvent
,
假如我們需要自定義一個SpringApplicationRunListener
,在實作類DemoSpringApplicationRunListener
的構造方法中需要兩個引數SpringApplication
和args
,然后可以通過SpringFactoriesLoader
的規定,在classpath
下的META-INF/spring.factories
中添加如下配置:
org.springframework.boot.SpringApplicationRunListener=\com.keevol.springboot.demo.DemoSpringApplicationRunListener
隨后SpringApplication
就會在運行的時候呼叫他了,
ApplicationListener
SpringApplication
是java
中監聽者模式的一種實作方式,如果需要添加自定的SpringListener
,可以有如下兩種方式:
- 通過
SpringApplication.addListeners(...)
或者SpringApplication.setListeners(...)
添加一個或多個自定義的listener
, - 借助
SpringFactoriesLoader
,在META-INF/spring.factories
中添加如下配置:
org.springframework.context.ApplicationListener=
\org.springframework.boot.builder.ParentContextCloserApplicationListener,
\org.springframework.boot.cloudfoundry.VcapApplicationListener,
\org.springframework.boot.context.FileEncodingApplicationListener
ApplicationContextInitializer
ApplicationContextInitializer
的目的就是在ConfigurableApplicationContext
的ApplicationContext
執行refresh()
之前,對ConfigurableApplicationContext
的實體做一些設定或處理,
實作一個自定義的ApplicationContextInitializer
有如下兩種方法:
- Spri
ngApplication.addInitializers(...)
- 通過添加
SpringFactoriesLoader
配置
org.springframework.context.ApplicationContextInitializer=
\org.springframework.boot.context.ConfigurationWarningsApplication-ContextInitializer,
\org.springframework.boot.context.ContextIdApplicationContextInitia-lizer,
CommandLineRunner
CommandLineRunner
的原始碼很簡單,如下:
public interface CommandLineRunner{
void run(String... args) throws Exception;
}
需要注意的兩點:
- 所有的
CommandLineRunner
需要在ApplicationContext
完全初始化之后執行, - 只要存在于
ApplicationContext
中的CommandLineRunner
都會被執行,無需手動添加,
以上幾個擴展點都建議使用@org.springframework.core.annotation.Order
進行注解或者實作org.springframework.core.Ordered
介面,便于對他們的執行順序進行調整,避免阻塞,
Spring Boot自動配置
之前在將@EnableAutoConfiguration
的時候說了,這個配置可以借助SpringFactoriesLoader
的幫助,將注解了@Configuration
的Java類匯總并加載到ApplicationContext
中去,
實際上,@EnableAutoConfiguration
還能夠對自動配置進行正價細化的配置和控制,
基于條件的自動配置
在Spring框架中,可以使用@Conditional
這個注解配合@Configuration
或者@Bean
來設定一個配置或者實體是否生效,生成一個類似于if-else
條件的生成邏輯,
關注公眾號回復“Conditional”獲取注解相關詳解
如果要基于條件配置,只需要在@Conditional
中指定自己的Condition
實作類就好了,如下:
@Conditional({DemoConditional1.class,DemoConditional2.class...})
@Conditional
除了可以注解在類和方法上之外,還可以注解在其他Annotation
實作類上,組成一個符合的注解,SpringBoot
中已經實作了一批,如下:
@ConditionalOnBean
:當容器里有指定的 Bean 的條件下,@ConditionalOnClass
:當類路徑下有指定的類的條件下,@ConditionalOnExpression
:基于 SpEL 運算式作為判斷條件,@ConditionalOnJava
:基于 JVM 版本作為判斷條件,@ConditionalOnJndi
:在 JNDI 存在的條件下查找指定的位置,@ConditionalOnMissingBean
:當容器里沒有指定 Bean 的情況下,@ConditionalOnMissingClass
:當類路徑下沒有指定的類的條件下,@ConditionalOnNotWebApplication
:當前專案不是 Web 專案的條件下,- @ConditionalOnProperty:指定的屬性是否有指定的值,
@ConditionalOnResource
:類路徑是否有指定的值,@ConditionalOnSingleCandidate
:當指定 Bean 在容器中只有一個,或者雖然有多個但是指定首選的 Bean,@ConditionalOnWebApplication
:當前專案是 Web 專案的條件下,
調整自動配置的順序
除了可以設定基于條件的配置,我們還可以對當前配置或者組件的加載順序進行調整,以便于在創建加載程序中解決依賴分析和組裝的問題,
@AutoConfigureBefore
或者@AutoConfigureAfter
可以配置當前組件或者配置的加載在其他的之前或者之后進行,比如需要某個配置的加載在另外一個之后,可以進行如下配置:
@Configuration
@AutoConfigureAfter(JmxAutoConfiguration.class)
public class AfterMBeanServerReadyConfiguration {
@AutoWired
MBeanServer mBeanServer;
//通過 @Bean 添加必要的 bean 定義
}
Spring-Boot-Starter常用依賴
之前說過,SpringBoot對開發者的影響主要有以下兩點:
- 基于Spring的配置理念,約定優先于配置
- 提供了各種自動配置依賴的模塊,使開發更加高效和快速
SpringBoot提供了很多以Spring-Boot-Starter開頭的依賴模塊,這些模塊有著默認的配置,正常情況下開箱即用,下面對常用的幾個模塊做一下介紹:
應用日志spring-boot-starter-logging
Java中有很多日志工具,比如log4j,log4j2,sel4j等等,在SpringBoot中,我們可以直接參考現成的依賴包,即可達到開箱即用的效果,比如添加如下Maven依賴:
<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-logging </artifactId>
</dependency>
那么SpringBoot就會自動使用logback作為應用的日志框架,在應用啟動的時候,初始化LoggingApplicationListener并使用,
如果我們要對日志系統做回應的設定,可以通過如下幾種方式進行配置:
- 在classpath下使用自己定制的logback.xml組態檔
- 在系統中任意位置添加logback.xml組態檔,然后通過application.yml指定檔案位置,
logging:
config: xml_path
初次之外,還有其他的日志框架,可自行選擇,比如: spring-boot-starter-log4j和 spring-boot-starter-log4j2等等,在實際專案中只需要參考一個即可,
web應用開發spring-boot-starter-web
通常情況下,我們開發的專案都是一個web專案,需要使用相應的容器來部署,在SpringBoot的maven依賴中添加下面的配置,就可以得到一個可直接運行的web應用,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在引入這個依賴之后,啟動當前專案,會自動嵌入一個默認的tomcat容器,當前服務就運行在這個容器之中,
spring-boot-starter-web默認將當前專案打包成jar包,在運行的時候可以直接使用java -jar xxx.jar來運行,然后訪問回應的請求地址就可以得到回應的response,
資料訪問spring-boot-starter-jdbc
如果專案中需要使用到資料庫,那么添加如下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
正常情況下我們在一個服務中只需要使用一個資料庫,那么這種情況下,只需要在application.yml中添加如下配置即可:
spring:
datasource:
url: jdbc:mysql://host:port/databaseName
username: username
password: password
某些特殊情況下,如果一個服務中需要使用到多個DataSource,那么只需要配置如下實體就好:
@Bean
public DataSource dataSource1() throws Throwable {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(...);
dataSource.setUsername(...);
dataSource.setPassword(...);
// TODO other settings if necessary in the future.
return dataSource;
}
@Bean
public DataSource dataSource2() throws Throwable {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(...);
dataSource.setUsername(...);
dataSource.setPassword(...);
// TODO other settings if necessary in the future.
return dataSource;
}
但是在添加完上面的代碼之后,直接啟動會報錯,我們需要在啟動類上排除SpringBoot在啟動的時候對默認的DataSource的加載,
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
或者在上面配置多個的DataSource上加上@Primary,可同時達到默認的DataSource和定制化的多個DataSource同時加載的兩全其美的效果,
除此之外,還有很多適配不同資料庫的依賴,spring-boot-starter-data-jpa、spring-boot-starter-data-mongodb 等,在實際專案中可以根據不同的資料庫自行選擇,
其他的依賴
SpringBoot還有很多其他的maven依賴,比如:
- spring-boot-starter-aop
- spring-boot-starter-security
- spring-boot-starter-actuator
......
具體的包可以去Maven官網查找,可以根據當前業務查找到我們需要使用的包以及選擇對應的版本,
SpringBoot微服務的注冊與發現
SpringBoot微服務部署到回應的環境之后需要對外提供服務,通常情況下,微服務很少單兵作戰,而是同時部署多個節點集群部署,
在這種情況下,如果訪問者發出一個請求,這個請求具體訪問哪一個節點,如何才能找到對應的節點,這個程序就是服務的發現,而一個服務需要作為一個主題對外提供服務,這個構件主體的程序就成為服務的注冊程序,
服務的注冊和發現在結構上可以簡單的展現為下圖的三角關系:
在這整個三角關系中,提供服務的注冊者Service Registry是整個關系的核心,他負責登記和保存哪些服務是可以對外提供服務的,當服務的訪問者Service Accessor發出請求訪問某個服務節點的時候,需要先訪問服務注冊者,獲取可以訪問的服務節點資訊,這樣服務訪問者就可以根據回傳的資訊訪問回應的服務,
SpringBoot的微服務注冊與發現是有SpringBoot微服務提供服務方式來決定的,如果是基于Dubbo框架的微服務發現方式 ,則很可能是基于Redis或者Zookeeper的注冊和發現機制,
上面這種方式,服務的訪問者需要了解服務注冊機制,獲取到服務節點之后再去訪問對應的微服務,但是對于用戶而言,服務的訪問者就是使用者,不應該過多的去了解服務端有多少節點,而且需要多次訪問才能獲取回應的請求結果,
一個更好的方案是在服務訪問者和注冊者之后添加一個服務訪問代理,訪問者直接對代理發出請求,獲取可用節點,對可用節點再次發出請求的作業都交給服務代理去做,優化之后的結構如下:
經過這樣的調整之后,服務的訪問者只需要與服務代理打交道,具體服務代理如何發現服務并訪問的,對于訪問者來說都只是一個黑盒,并不需要做過多的關心,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/205066.html
標籤:其他