溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

《深入實踐Spring Boot》閱讀筆記之三:核心技術(shù)源代碼分析

發(fā)布時間:2020-07-11 17:09:41 來源:網(wǎng)絡(luò) 閱讀:829 作者:情情說 欄目:開發(fā)技術(shù)

剛關(guān)注的朋友,可以回顧前兩篇文章:

  • 基礎(chǔ)應(yīng)用開發(fā)
  • 分布式應(yīng)用開發(fā)

上篇文章總結(jié)了《深入實踐Spring Boot》的第二部分,本篇文章總結(jié)第三部分,也是最后一部分。這部分主要講解核心技術(shù)的源代碼分析,因為篇幅和能力原因,分析的不會太詳細,后續(xù)深入研究后再專門寫文章。希望大家能從「閱讀筆記」3篇文章中,對Spring Boot提供的功能有所了解,在項目中進行實踐,不斷從繁瑣重復(fù)的開發(fā)中解放出來。

我也是最近剛開始了解Spring Boot,計劃今年在項目中實踐,到時會總結(jié)實踐過程中的一些問題和經(jīng)驗,分享給大家。想一起學(xué)習(xí)、實踐、交流的朋友,可以掃描文章下方的二維碼,關(guān)注我的個人公眾號,感謝大家。

本篇主要從以下幾個方面總結(jié):

  • Spring Boot自動配置實現(xiàn)原理;
  • Spring Boot數(shù)據(jù)訪問實現(xiàn)原理;
  • 微服務(wù)核心技術(shù)實現(xiàn)原理;
題外話

春節(jié)假期很快過去了,明天就要上班了,相信大家還是意猶未盡,沒吃夠、沒玩夠、沒和家人待夠。今年因為個人原因,沒有回家過年,心理最牽掛的還是爺爺奶奶,他們都80多了,希望她們身體健康,開開心心地度過生命最后的旅程。

不管怎樣,大家要切換頻道了,回歸到正常的工作中,好好努力,一起期待明年和家人更好的團聚。

Spring Boot自動配置實現(xiàn)原理

使用Spring Boot創(chuàng)建一個簡單的Web項目很簡潔,不需要太多配置,編寫一個簡單的主程序就行:

@SpringBootApplication
public class ConfigApplication{
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
}
主程序分析

首先分析下run方法(省略不關(guān)鍵的部分代碼):

public ConfigurableApplicationContext run(String... args) {

        ConfigurableApplicationContext context = null;
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.started();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            listeners.finished(context, null);
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }

它首先開啟一個SpringApplicationRunListeners監(jiān)聽器,然后創(chuàng)建一個應(yīng)用上下文ConfigurableApplicationContext,通過這個上下文加載應(yīng)用所需的類和各種環(huán)境配置等。

一個應(yīng)用能夠正常運行起來,需要一些環(huán)境變量、各種資源和一些相關(guān)配置等,下面看下createApplicationContext方法會加載應(yīng)用定義的和需要的類及各種資源。

自動配置

所有的自動配置都是從注解@SpringBootApplication引入的,它其實又包含了@Configuration、@EnableAutoConfiguration和@ComponentScan,其中,@EnableAutoConfiguration就是啟用自動配置的,并將導(dǎo)入一些自動配置的類定義。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

EnableAutoConfiguration最終會導(dǎo)入一個自動配置的類列表,列表中的自動配置類很多,這些配置類中大都將被導(dǎo)入,并處于備用狀態(tài),當(dāng)項目中引入了相關(guān)的包時,相關(guān)的功能將被啟用。

例如在項目的maven配置中配置了Redis的引用,Redis的默認配置項將被啟用,首先會讀取項目中的配置,只有項目中沒有相關(guān)配置才啟用配置的默認值,下面代碼是Redis的自動配置,如果配置文件中沒設(shè)置,會使用下面默認設(shè)置。

@ConfigurationProperties(
    prefix = "spring.redis"
)
public class RedisProperties {
    private int database = 0;
    private String host = "localhost";
    private String password;
    private int port = 6379;
    private int timeout;
    private RedisProperties.Pool pool;
    private RedisProperties.Sentinel sentinel;
    private RedisProperties.Cluster cluster;

    public RedisProperties() {
    }

通過自動配置,就不用重復(fù)定義配置項名稱了,覆蓋約定的配置項即可。可通過查看各個Properties類,查看有哪些配置項。

Spring Boot數(shù)據(jù)訪問實現(xiàn)原理

要使用數(shù)據(jù)庫,首先必須與數(shù)據(jù)庫服務(wù)器建立連接。對于關(guān)系型數(shù)據(jù)庫,Spring Boot 連接數(shù)據(jù)源一般都采用JDBC的方式來實現(xiàn)。其他類型的數(shù)據(jù)庫使用各自獨立的方式來建立連接。

數(shù)據(jù)源類型和驅(qū)動

JDBC連接數(shù)據(jù)源必須指定數(shù)據(jù)源類型和數(shù)據(jù)庫驅(qū)動程序,數(shù)據(jù)源主要有4中:

  • 使用java.sql.DriverManager類;
  • 使用實現(xiàn)了javax.sql.DataSource接口的子類,DataSource接口由驅(qū)動程序供應(yīng)商實現(xiàn),主要有3類實現(xiàn)、基本實現(xiàn)、連接池實現(xiàn),分布式事務(wù)實現(xiàn) ;
  • DBCP連接池,Apache 軟件基金組織下的開源連接池實現(xiàn),Tomcat 的連接池正是采用該連接池來實現(xiàn)的;
  • C3P0連接池;

Spring Boot 默認使用org.apache.tomcat.jdbc.pool.DataSource,它使用第2種方式,實現(xiàn)了javax.sql.DataSource接口。數(shù)據(jù)源的類型可以通過配置更改。

另外,Spring Boot 默認幾乎支持現(xiàn)有的所有數(shù)據(jù)庫。

數(shù)據(jù)存取功能實現(xiàn)

與數(shù)據(jù)庫建立連接后,就可以對數(shù)據(jù)庫執(zhí)行一些存取操作,對數(shù)據(jù)庫實現(xiàn)管理的功能。數(shù)據(jù)存取操作大體上包含兩方面的內(nèi)容,即實體建模和持久化。

不管是關(guān)系型數(shù)據(jù)庫,還是NoSQL數(shù)據(jù)庫,都遵循這一設(shè)計規(guī)范。實體建模即將Java的普通對象和關(guān)系映射為數(shù)據(jù)庫表機器相關(guān)的關(guān)系,在Spring Boot中,主要是通過注解實現(xiàn)。

關(guān)系型數(shù)據(jù)庫都使用了JPA的一套標準,它結(jié)合使用Hibernate實現(xiàn)了實體的持久化。后續(xù)的數(shù)據(jù)庫管理設(shè)計都遵循了JPA這一個標準規(guī)范,提供相同的訪問數(shù)據(jù)庫的API。

微服務(wù)核心技術(shù)實現(xiàn)原理

Spring Cloud是基于對Netfix開源組件進一步封裝的一套云應(yīng)用開發(fā)工具,可以用來開發(fā)各種微服務(wù)應(yīng)用。

配置服務(wù)實現(xiàn)

前一篇文章說到,配置管理的在線更新功能使用事件總線,即spring-cloud-bus來發(fā)布狀態(tài)變化,并使用分布式消息來發(fā)布更新事件,分布式消息最終使用RabbitMQ來實現(xiàn)消息收發(fā)。

再來回顧下在線更新流程:

  • 更新Git倉庫的配置文件;
  • 以POST指令出發(fā)更新請求;
  • 配置管理服務(wù)器從Git倉庫中讀取配置文件,并將配置文件分發(fā)給各個客戶端,同時在RabbitMQ中發(fā)布一個更新消息;
  • 客戶端訂閱RabbitMQ消息,收到消息后執(zhí)行更新;

配置管理服務(wù)器中的消息分發(fā)是從spring-cloud-bus中調(diào)用spring-cloud-stream組件實現(xiàn)的,而spring-cloud-stream使用RabbitMQ實現(xiàn)了分布式消息分發(fā)。具體實現(xiàn)就不說了,使用過RabbitMQ的很好理解。

發(fā)現(xiàn)服務(wù)和負載均衡

客戶端執(zhí)行注冊使用計劃任務(wù)的方式來實現(xiàn),而客戶端從發(fā)現(xiàn)服務(wù)器中更新其他在線的客戶端列表,也使用了一個定時任務(wù)來管理。

當(dāng)一個應(yīng)用啟用發(fā)現(xiàn)服務(wù)的功能之后,會默認啟用Ribbon的負載均衡服務(wù)。Ribbon通過發(fā)現(xiàn)服務(wù)獲取在線的客戶端,為具有多個實例的客戶端建立起負載均衡管理機制。

分布式消息實現(xiàn)

使用spirng-cloud-stream可以非常簡單地使用RabbitMQ的異步消息,Spring Cloud的配置管理中的分布式消息分發(fā)也是通過調(diào)用spring-cloud-stream組件來實現(xiàn)的。

下面以消息生產(chǎn)者和消費者的實現(xiàn)說明分布式消息實現(xiàn)

消息生產(chǎn)者:

@EnableBinding(Source.class)
@RestController 
@SpringBootApplication 
public class SenderApplication { 
    @Autowired 
    @Output(Source.OUTPUT) 
    private MessageChannel channel;

    @RequestMapping(method = RequestMethod.POST, path = "/send") 
    public void write (@RequestBody Map<String, Object> msg){
        channel.send(MessageBuilder.withPayload(msg).build());
    } 

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

消息消費者:

@EnableBinding(Sink.class)
@IntegrationComponentScan
@MessageEndpoint
@SpringBootApplication
public class ReceiverApplication {
    @ServiceActivator(inputChannel=Sink.INPUT)
    public void accept(Map<String, Object> msg){
        System.out.println(msg.get("msg").toString() + ":" + msg.get("name"));
    }

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

從上面的分析可以看到,Spring Boot及其一些相關(guān)組件,已經(jīng)盡量把一些可以實現(xiàn)和做到的功能,都幫我們實現(xiàn)了。 雖然使用Spring Boot及其相關(guān)組件看起來非常簡單,但實際上可以實現(xiàn)無比強大的功能,這就是Spring Boot 及其組件的神奇所在。

《深入實踐Spring Boot》閱讀筆記之三:核心技術(shù)源代碼分析

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI