欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot啟動后的初始化數(shù)據(jù)加載原理解析與實戰(zhàn)

 更新時間:2024年11月22日 10:22:02   作者:不惑_  
本文主要圍繞?Spring?Boot?啟動后的初始化數(shù)據(jù)加載展開,介紹了初始化任務(wù)的基本需求,包括全局配置加載、數(shù)據(jù)庫表初始化等,闡述了多種初始化加載方式,分析了它們的優(yōu)缺點,需要的朋友可以參考下

系統(tǒng)初始化操作是一個非常常見的需求。通常,應(yīng)用在啟動后需要執(zhí)行一些重要的初始化任務(wù),例如加載全局配置、初始化數(shù)據(jù)庫表、預(yù)熱緩存、啟動后臺任務(wù)等。而如何選擇合適的技術(shù)方案,在不同的場景下保證初始化任務(wù)的高效執(zhí)行,尤其在多實例的分布式部署中,如何確保任務(wù)只執(zhí)行一次,成為我們在項目實戰(zhàn)中需要深入思考和優(yōu)化的關(guān)鍵問題。

本文將結(jié)合 Spring Boot 框架,從基礎(chǔ)的啟動機制、核心技術(shù)原理到分布式環(huán)境下的復(fù)雜場景,帶領(lǐng)大家逐步深入理解如何通過不同方式進行啟動后的初始化任務(wù)執(zhí)行。最終,我們會通過一個項目實戰(zhàn)例子,演示如何確保初始化任務(wù)在分布式部署環(huán)境中只執(zhí)行一次,解決多實例下的任務(wù)重復(fù)執(zhí)行問題。

初始化任務(wù)的基本需求

這些任務(wù)有一個共同的特性:它們通常只需要在應(yīng)用啟動時執(zhí)行一次。因此,選擇一個合適的機制來執(zhí)行這些初始化操作,并且在分布式環(huán)境中確保任務(wù)不會被重復(fù)執(zhí)行,是至關(guān)重要的。包括但不限于:

  • 全局配置的加載:如從數(shù)據(jù)庫、配置文件或遠程服務(wù)加載全局的應(yīng)用參數(shù)。
  • 數(shù)據(jù)庫表初始化:例如檢查并創(chuàng)建缺失的數(shù)據(jù)庫表、插入初始數(shù)據(jù)等。
  • 緩存預(yù)熱:應(yīng)用啟動后立即加載部分常用數(shù)據(jù)到緩存中,減少首次訪問的延遲。
  • 后臺任務(wù)啟動:啟動如消息隊列監(jiān)聽、定時任務(wù)調(diào)度等長期運行的后臺服務(wù)。
  • 系統(tǒng)健康檢查:確保關(guān)鍵依賴服務(wù)(如數(shù)據(jù)庫、消息隊列、第三方服務(wù))在啟動時正常工作。

啟動后初始化加載的幾種方式

Spring Boot 提供了多種機制來處理應(yīng)用啟動后的初始化任務(wù)。這些機制涵蓋了單機部署和分布式部署的需求,并且具有不同的執(zhí)行時機和適用場景。

PostConstruct 注解

@PostConstruct 是一種非常簡潔且常用的方式,它用于標注在 Spring 管理的 Bean 完成依賴注入后自動調(diào)用的方法。這種方式特別適合單個 Bean 的初始化操作。Spring 在完成依賴注入后,自動調(diào)用帶有 @PostConstruct 注解的方法,確保初始化邏輯在 Bean 初始化完成時執(zhí)行。

適用于需要在某個特定 Bean 初始化完成后執(zhí)行的任務(wù)。例如,某個服務(wù)類需要在加載時讀取配置文件或執(zhí)行特定的初始化操作。

@Component
public class MyService {
    @PostConstruct
    public void init() {
        // 初始化任務(wù),只執(zhí)行一次
        System.out.println("Bean 初始化后執(zhí)行");
    }
}

優(yōu)點:

  • 簡單直觀:它是 Java EE 標準的一部分,使用非常簡單。只需要在一個方法上加上 @PostConstruct 注解,Spring 會在 Bean 初始化后自動調(diào)用該方法。
  • 自動調(diào)用:可以確保在 Spring 容器完成 Bean 的依賴注入后,自動執(zhí)行初始化操作,不需要顯式調(diào)用。

缺點:

  • 只能處理單個 Bean 的初始化任務(wù)@PostConstruct 注解的方法只能作用于某個具體 Bean,在這個 Bean 完成初始化時執(zhí)行。如果有多個 Bean 需要初始化任務(wù),@PostConstruct 無法跨 Bean 控制執(zhí)行邏輯。

CommandLineRunner / ApplicationRunner

CommandLineRunner 和 ApplicationRunner 是 Spring Boot 中用于在應(yīng)用啟動完成后執(zhí)行初始化任務(wù)的接口。兩者的區(qū)別在于傳遞的參數(shù)形式,CommandLineRunner 提供原始的 String[] 參數(shù),而 ApplicationRunner 封裝了啟動參數(shù)的上下文信息。

CommandLineRunner:這個接口提供的是原始的 String[] 啟動參數(shù),這些參數(shù)通常是應(yīng)用啟動時傳遞給 Java 程序的命令行參數(shù)。如果你只關(guān)心應(yīng)用啟動時的命令行參數(shù)并且需要直接操作它們,可以使用 CommandLineRunner。

ApplicationRunner:這個接口封裝了啟動時的參數(shù),通過 ApplicationArguments 類提供對命令行參數(shù)的更高層次的訪問。如果你需要更多功能(例如獲取非標準格式的命令行參數(shù),處理帶有標志的參數(shù)等),可以使用 ApplicationRunner。

優(yōu)點

  • 適用于全局任務(wù):無論是 CommandLineRunner 還是 ApplicationRunner,都能在所有 Bean 完成初始化之后執(zhí)行,確保應(yīng)用的啟動邏輯是全局性的。
  • 自動執(zhí)行:一旦實現(xiàn)了這些接口的類被注冊為 Spring Bean,Spring 會自動調(diào)用它們的 run() 方法,任務(wù)執(zhí)行是自動的,無需顯式調(diào)用。

缺點

  • 多個實現(xiàn)類的順序控制:如果項目中有多個 CommandLineRunnerApplicationRunner 實現(xiàn)類,默認情況下它們的執(zhí)行順序是不確定的。為了保證執(zhí)行順序,可以使用 @Order 注解明確指定執(zhí)行的優(yōu)先級。
  • 只能執(zhí)行一次:這類方法在 Spring Boot 應(yīng)用啟動時執(zhí)行,并且默認只執(zhí)行一次。如果你需要某些任務(wù)在應(yīng)用的生命周期內(nèi)多次執(zhí)行,這種方式不適用。

使用 CommandLineRunner

@Component
public class MyStartupRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        // 這是應(yīng)用啟動后要執(zhí)行的任務(wù)
        System.out.println("應(yīng)用啟動后執(zhí)行初始化任務(wù)");
    }
}

使用 ApplicationRunner

@Component
public class MyAppStartupRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 獲取命令行參數(shù)
        System.out.println("應(yīng)用啟動后執(zhí)行初始化任務(wù),獲取啟動參數(shù):" + args.getOptionNames());
    }
}

運行后我們會發(fā)現(xiàn),@Component 的執(zhí)行順序確實早于 ApplicationRunner 和 CommandLineRunner。

為什么是這個順序

**@Component注解的 Bean:**任何標注為 @Component(或 @Service、@Repository、@Controller 等)的類會在 Spring Boot 應(yīng)用啟動時被自動掃描并實例化。這些 Bean 會在 Spring 容器啟動的初期階段被創(chuàng)建和初始化,在應(yīng)用啟動過程中最早被加載和執(zhí)行。

ApplicationRunner CommandLineRunner: 這兩個接口的實現(xiàn)類是 Spring Boot 特有的啟動鉤子,它們在所有@Component Bean 被創(chuàng)建和初始化之后執(zhí)行,但在 Spring Boot 完成應(yīng)用啟動(即應(yīng)用的上下文已準備好)后執(zhí)行。ApplicationRunner 會比 CommandLineRunner 早執(zhí)行,因為它封裝了啟動參數(shù)上下文的更多信息,所以它們的 run() 方法會在 Spring Boot 完成上下文刷新和 Bean 初始化之后執(zhí)行。

執(zhí)行順序控制

如果你的項目中有多個實現(xiàn)類,且它們都需要在應(yīng)用啟動時執(zhí)行,使用 @Order 注解可以明確控制執(zhí)行順序。例如:

@Component
@Order(1)  // 設(shè)置優(yōu)先級,數(shù)字越小優(yōu)先級越高
public class FirstStartupTask implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("第一個啟動任務(wù)");
    }
}

@Component
@Order(2)
public class SecondStartupTask implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("第二個啟動任務(wù)");
    }
}

這樣,F(xiàn)irstStartupTask 會在 SecondStartupTask 之前執(zhí)行。

Spring Boot 生命周期事件

Spring Boot 提供了事件驅(qū)動的編程模型,可以幫助開發(fā)者在應(yīng)用生命周期的不同階段執(zhí)行特定的任務(wù)。通過監(jiān)聽 Spring 生命周期事件,開發(fā)者可以在精確的時機執(zhí)行初始化任務(wù)。這種方式適合需要確保任務(wù)執(zhí)行時機的場景,例如,某些任務(wù)必須等到應(yīng)用完全啟動、數(shù)據(jù)庫連接已經(jīng)建立、服務(wù)已經(jīng)準備好之后才能執(zhí)行。Spring Boot 中有很多生命周期事件,例如:

**ApplicationReadyEvent:**當應(yīng)用完全啟動并準備好處理請求時觸發(fā)。此事件表示 Spring 應(yīng)用上下文已經(jīng)完全初始化,應(yīng)用已準備好接收外部請求。適用于在應(yīng)用啟動完成后立即執(zhí)行的初始化任務(wù),例如啟動后臺服務(wù)、初始化緩存等。

ContextRefreshedEvent:當 Spring 上下文被初始化或刷新時觸發(fā)。這通常發(fā)生在 Spring Boot 啟動過程中,用于標志 Spring 容器準備好并且所有 Bean 已初始化完畢。 - 適合在應(yīng)用啟動時進行一些預(yù)熱操作,如加載配置信息、初始化數(shù)據(jù)庫連接池等。

ApplicationStartedEvent:在 Spring Boot 應(yīng)用啟動時觸發(fā),發(fā)生在 Spring 上下文加載之前,可以用于執(zhí)行一些早期的初始化任務(wù)。

ApplicationEnvironmentPreparedEvent:在 Spring Boot 啟動過程中,當應(yīng)用的 Environment 配置完成時觸發(fā)。這時還未初始化 Spring 容器,適用于一些基于環(huán)境配置的初始化。

ApplicationFailedEvent:如果 Spring Boot 啟動失敗,這個事件會被觸發(fā)。可以用來處理應(yīng)用啟動失敗后的清理或日志記錄。

監(jiān)聽 Spring 生命周期事件

Spring Boot 提供了 ApplicationListener 接口和 @EventListener 注解來監(jiān)聽這些生命周期事件。我們可以通過這兩種方式,在特定的時機執(zhí)行初始化任務(wù)。

1:使用 ApplicationListener 監(jiān)聽 ApplicationReadyEvent

通過實現(xiàn) ApplicationListener 接口,可以監(jiān)聽指定的事件,例如監(jiān)聽 ApplicationReadyEvent 來確保在應(yīng)用完全啟動后執(zhí)行任務(wù)。

@Component
public class ApplicationListenerExample implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 應(yīng)用啟動完成后執(zhí)行的任務(wù)
        System.out.println("應(yīng)用啟動完成后執(zhí)行任務(wù)");
    }
}
  • 事件ApplicationReadyEvent 是 Spring Boot 應(yīng)用啟動完成后發(fā)布的事件。
  • 觸發(fā)時機:在所有 Bean 被初始化之后,并且 Spring 上下文已經(jīng)完全加載并準備好時,ApplicationReadyEvent 會被觸發(fā)。

2:使用 @EventListener 注解監(jiān)聽事件

Spring 5 引入了 @EventListener 注解,它提供了更簡潔的方式來監(jiān)聽事件,不需要顯式實現(xiàn) ApplicationListener 接口。

@Component
public class EventListenerExample {
    @EventListener(ApplicationReadyEvent.class)
    public void handleApplicationReady() {
        // 應(yīng)用啟動完成后執(zhí)行的任務(wù)
        System.out.println("使用 @EventListener 在應(yīng)用啟動后執(zhí)行任務(wù)");
    }
}
  • 事件@EventListener(ApplicationReadyEvent.class) 表示監(jiān)聽 ApplicationReadyEvent 事件。
  • 觸發(fā)時機@EventListener 注解的方法會在 ApplicationReadyEvent 觸發(fā)時執(zhí)行,適用于應(yīng)用完全啟動后的任務(wù)。

事件驅(qū)動機制的優(yōu)缺點

優(yōu)點:

  • 精確控制執(zhí)行時機:通過監(jiān)聽特定的生命周期事件,開發(fā)者可以精確地控制初始化任務(wù)的執(zhí)行時機,確保任務(wù)只在應(yīng)用處于某種狀態(tài)時執(zhí)行。例如,ApplicationReadyEvent 事件保證任務(wù)只在應(yīng)用完全啟動后執(zhí)行。
  • 解耦應(yīng)用邏輯:使用事件監(jiān)聽機制,開發(fā)者不需要直接在應(yīng)用啟動過程中顯式調(diào)用初始化任務(wù)。事件驅(qū)動可以幫助將應(yīng)用的啟動邏輯與任務(wù)執(zhí)行邏輯解耦,使得代碼更清晰、更易維護。
  • 處理復(fù)雜的初始化邏輯:如果初始化邏輯比較復(fù)雜,或者有多個任務(wù)需要按特定順序執(zhí)行,事件機制可以提供靈活的控制。例如,ContextRefreshedEvent 可以確保一些初始化任務(wù)在 Spring 上下文初始化完成后執(zhí)行。

缺點:

  • 依賴事件觸發(fā):事件機制的缺點是任務(wù)的執(zhí)行依賴于事件的觸發(fā),這要求開發(fā)者對 Spring 事件機制有所了解。如果應(yīng)用啟動過程中沒有觸發(fā)預(yù)期的事件,初始化任務(wù)可能會錯過執(zhí)行時機。
  • 調(diào)試難度較大:如果任務(wù)執(zhí)行依賴于特定的事件觸發(fā),在調(diào)試時可能需要特別關(guān)注事件的觸發(fā)順序和事件的監(jiān)聽邏輯,否則可能會導(dǎo)致任務(wù)無法按預(yù)期執(zhí)行。
  • 學習成本:對于沒有使用過 Spring 事件機制的開發(fā)者來說,需要花費一些時間學習和理解事件發(fā)布與監(jiān)聽的原理,尤其是在多事件場景下,理解事件的傳播與監(jiān)聽順序。

使用 @Bean(initMethod) 定義自定義初始化方法

在 Spring 中,@Bean(initMethod) 提供了一種自定義 Bean 初始化方法的方式。通過這種機制,開發(fā)者可以為特定的 Bean 指定一個初始化方法,該方法會在 Spring 容器完成該 Bean 的依賴注入和實例化后自動執(zhí)行。通常,這種方法用于處理一些復(fù)雜的初始化操作,例如初始化數(shù)據(jù)庫連接、加載外部配置、啟動后臺任務(wù)等。

適用于需要復(fù)雜初始化的 Bean:當 Bean 的初始化需要執(zhí)行復(fù)雜的操作(例如調(diào)用外部 API、執(zhí)行文件加載、數(shù)據(jù)庫連接初始化等)時,可以通過 initMethod 指定一個初始化方法,而不需要在 Bean 類中使用 @PostConstruct 注解或 CommandLineRunner 等方式。

外部配置控制初始化邏輯:@Bean(initMethod = "init") 允許將 Bean 的初始化方法與外部配置綁定,使得開發(fā)者能夠更靈活地控制 Bean 的初始化過程。

@Configuration
public class AppConfig {
    @Bean(initMethod = "init")
    public MyService myService() {
        return new MyService();
    }
}

public class MyService {
    // 自定義初始化邏輯
    public void init() {
        System.out.println("自定義初始化方法");
    }
}
  • @Bean(initMethod = "init"):這里,@Bean 注解為 MyService 定義了一個初始化方法 init。當 MyService Bean 被創(chuàng)建并且依賴注入完成后,init 方法會被自動調(diào)用。
  • init() 方法:MyService 類中定義了一個名為 init() 的方法,這個方法在 Bean 完成初始化后會被自動調(diào)用。通常,這個方法包含了一些額外的初始化邏輯,比如外部資源的加載或初始化。

優(yōu)缺點分析

優(yōu)點:

  • 靈活性@Bean(initMethod) 允許開發(fā)者靈活指定初始化方法的名稱,適合用于需要在 Bean 初始化時執(zhí)行某些特定任務(wù)的場景。與 @PostConstructCommandLineRunner 等方法相比,@Bean(initMethod) 提供了更多的控制選項,尤其在復(fù)雜的應(yīng)用程序中。
  • 支持復(fù)雜初始化邏輯:當 Bean 的初始化過程比較復(fù)雜(例如需要加載配置、啟動線程、或者處理數(shù)據(jù)庫連接等),可以通過 initMethod 方法指定特定的初始化邏輯。
  • 與 Spring 配置文件解耦:在使用 @Configuration 類中配置 Bean 時,initMethod 提供了一種不依賴于 Bean 類本身的初始化方式。它有助于將 Bean 的配置與實現(xiàn)分離。

缺點:

  • 可讀性略差:相比 @PostConstructCommandLineRunner 等注解的方式,@Bean(initMethod) 需要開發(fā)者在配置類中明確指定初始化方法的名稱,這可能導(dǎo)致代碼的可讀性略差,尤其是在項目中有多個配置類和多個初始化方法時,開發(fā)者可能需要更加小心地管理這些方法。
  • 不適合所有類型的初始化:對于一些簡單的 Bean 初始化任務(wù),例如基本的配置加載或基礎(chǔ)的數(shù)據(jù)預(yù)處理,使用 @Bean(initMethod) 可能顯得過于冗余。此時,使用 @PostConstructCommandLineRunner 等方式更為簡潔和直接。
  • 初始化方法依賴 Spring 容器的管理@Bean(initMethod) 中指定的初始化方法必須是由 Spring 容器管理的 Bean。在某些情況下(例如某些純 Java 對象或手動創(chuàng)建的 Bean),可能無法直接使用該方法進行初始化。

綜合項目實戰(zhàn)

需求說明

假設(shè)我們有一個應(yīng)用,要求在啟動時執(zhí)行以下初始化任務(wù):

  • 從數(shù)據(jù)庫或遠程服務(wù)加載全局配置。
  • 初始化一些數(shù)據(jù)庫表(如果不存在)。
  • 預(yù)熱緩存。
  • 啟動后臺任務(wù)(如定時任務(wù))。
  • 在多實例的分布式環(huán)境中,確保某些初始化任務(wù)只執(zhí)行一次(如初始化某些基礎(chǔ)數(shù)據(jù)、加載配置等)。

方案設(shè)計

我們將使用 Spring Boot 的不同初始化方式結(jié)合分布式鎖來確保任務(wù)只執(zhí)行一次。具體使用以下技術(shù):

  • @PostConstruct:用于簡單的初始化任務(wù)。
  • CommandLineRunner:用于全局任務(wù),在應(yīng)用啟動后執(zhí)行。
  • Spring 事件機制:用于精確控制任務(wù)的執(zhí)行時機。
  • 分布式鎖(基于 Redis):確保在多實例環(huán)境中,任務(wù)只執(zhí)行一次。
  • 自定義 @Bean(initMethod):為需要特殊初始化邏輯的 Bean 指定初始化方法。

1. 項目結(jié)構(gòu)

src
└── main
    ├── java
    │   └── com
    │       └── example
    │           ├── Application.java
    │           ├── config
    │           │   └── AppConfig.java
    │           ├── initializer
    │           │   ├── AppStartupRunner.java
    │           │   ├── CacheInitializer.java
    │           │   └── DistributedLockInitializer.java
    │           └── service
    │               └── MyService.java
    └── resources
        └── application.properties

2. application.properties

# Redis 配置
spring.redis.host=localhost
spring.redis.port=6379

# 數(shù)據(jù)庫配置(假設(shè)使用 MySQL)
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=root

3. 主應(yīng)用入口類 Application.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

4. 配置類 AppConfig.java

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.service.MyService;

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public MyService myService() {
        return new MyService();
    }
}

5. 服務(wù)類 MyService.java

package com.example.service;

public class MyService {

    public void init() {
        // 這里可以執(zhí)行復(fù)雜的初始化操作,如外部API調(diào)用等
        System.out.println("執(zhí)行 MyService 的自定義初始化方法");
    }
}

6. 啟動初始化任務(wù)類 AppStartupRunner.java

package com.example.initializer;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class AppStartupRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        // 應(yīng)用啟動后執(zhí)行的初始化任務(wù)
        System.out.println("執(zhí)行應(yīng)用啟動時的全局初始化任務(wù)");
    }
}

7. 緩存初始化類 CacheInitializer.java

package com.example.initializer;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class CacheInitializer {

    @PostConstruct
    public void init() {
        // 預(yù)熱緩存邏輯,例如加載常用數(shù)據(jù)到緩存
        System.out.println("執(zhí)行緩存預(yù)熱任務(wù)");
    }
}

8. 分布式鎖初始化類 DistributedLockInitializer.java

package com.example.initializer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class DistributedLockInitializer implements ApplicationListener<ApplicationReadyEvent> {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 獲取分布式鎖,確保初始化任務(wù)只執(zhí)行一次
        Boolean success = redisTemplate.opsForValue().setIfAbsent("init_lock", "locked");
        if (Boolean.TRUE.equals(success)) {
            // 模擬執(zhí)行初始化任務(wù)(如初始化數(shù)據(jù)表、加載配置等)
            System.out.println("執(zhí)行初始化任務(wù):初始化數(shù)據(jù)庫或加載基礎(chǔ)數(shù)據(jù)");
            // 這里可以執(zhí)行初始化數(shù)據(jù)庫表、加載默認數(shù)據(jù)等任務(wù)
        } else {
            System.out.println("任務(wù)已經(jīng)在其他實例中執(zhí)行,當前實例跳過任務(wù)");
        }
    }
}

9.關(guān)鍵技術(shù)和設(shè)計

  • @PostConstruct:用于緩存預(yù)熱任務(wù),在 Bean 初始化完成后立即執(zhí)行。
  • CommandLineRunner:全局任務(wù)的執(zhí)行方式,確保應(yīng)用啟動后執(zhí)行某些初始化操作。
  • 事件驅(qū)動機制(ApplicationReadyEvent):精確控制任務(wù)執(zhí)行的時機,確保任務(wù)在應(yīng)用完全啟動并準備好后執(zhí)行。
  • 分布式鎖(基于 Redis):確保初始化任務(wù)在多實例部署的環(huán)境中只執(zhí)行一次。通過 StringRedisTemplate 實現(xiàn) Redis 的分布式鎖,防止在多個實例中重復(fù)執(zhí)行相同任務(wù)。
  • @Bean(initMethod):為特定的 Bean 指定自定義初始化方法,適合需要復(fù)雜初始化的場景。

10.運行效果

  • 當應(yīng)用啟動時,CommandLineRunner 會執(zhí)行全局初始化任務(wù),確保應(yīng)用啟動后的任務(wù)被執(zhí)行。
  • CacheInitializer 會在 Bean 初始化完成后執(zhí)行緩存預(yù)熱。
  • DistributedLockInitializer 會通過 Redis 分布式鎖確保初始化任務(wù)只執(zhí)行一次。若任務(wù)已經(jīng)在其他實例中執(zhí)行,當前實例跳過該任務(wù)。

關(guān)鍵要點

  • 在單機環(huán)境中,@PostConstruct 和 CommandLineRunner 等方式已足夠滿足大多數(shù)初始化需求。
  • 在分布式環(huán)境下,必須確保初始化任務(wù)只執(zhí)行一次,推薦使用基于 Redis 的分布式鎖來避免重復(fù)執(zhí)行。
  • Spring 提供的事件機制和 @Bean(initMethod) 允許開發(fā)者靈活控制任務(wù)的執(zhí)行時機和邏輯,滿足復(fù)雜業(yè)務(wù)場景的需求。

通過靈活運用這些技術(shù)和方法,開發(fā)者可以確保應(yīng)用啟動時的初始化任務(wù)高效、安全地執(zhí)行,避免在多實例環(huán)境中產(chǎn)生重復(fù)執(zhí)行的情況。最終,這些方案能夠幫助開發(fā)者在確保系統(tǒng)穩(wěn)定性和性能的同時,提高系統(tǒng)的可維護性和擴展性。

以上就是SpringBoot啟動后的初始化數(shù)據(jù)加載原理解析與實戰(zhàn)的詳細內(nèi)容,更多關(guān)于SpringBoot初始化數(shù)據(jù)加載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入淺出Java中重試機制的多種方式

    深入淺出Java中重試機制的多種方式

    重試機制在分布式系統(tǒng)中,或者調(diào)用外部接口中,都是十分重要的。重試機制可以保護系統(tǒng)減少因網(wǎng)絡(luò)波動、依賴服務(wù)短暫性不可用帶來的影響,讓系統(tǒng)能更穩(wěn)定的運行的一種保護機制。本文就來和大家聊聊Java中重試機制的多種方式
    2023-03-03
  • Mybatis-plus null值更新不生效問題解決

    Mybatis-plus null值更新不生效問題解決

    在使用Mybatis-plus進行數(shù)據(jù)更新時,默認策略是NOT_NULL,即null值不會被更新到數(shù)據(jù)庫,解決方法包括設(shè)置全局field-strategy、對特定字段設(shè)置field-strategy或使用UpdateWrapper方式更新,下面就來介紹一下
    2024-10-10
  • 詳解Java關(guān)于時間格式化的方法

    詳解Java關(guān)于時間格式化的方法

    這篇文章主要介紹了詳解Java關(guān)于時間格式化的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Java中Cglib代理類重寫邏輯詳解

    Java中Cglib代理類重寫邏輯詳解

    這篇文章主要介紹了Java中Cglib代理類重寫邏輯詳解,代理類中只會維護NoOp這個回調(diào)屬性,并不會生成目標類MyService中的noOp所對應(yīng)的方法,需要的朋友可以參考下
    2023-11-11
  • 學習Java HashMap,看這篇就夠了

    學習Java HashMap,看這篇就夠了

    這篇文章主要介紹了Java HashMap的相關(guān)資料,文中示例代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-07-07
  • JAVA中哈希表HashMap的深入學習

    JAVA中哈希表HashMap的深入學習

    這篇文章主要介紹了哈希表HashMap的深入學習,哈希表是一種非常重要的數(shù)據(jù)結(jié)構(gòu),許多緩存技術(shù)(比如memcached)的核心其實就是在內(nèi)存中維護一張大的哈希表,本文會對java集合框架中HashMap的實現(xiàn)原理進行講解。感興趣的話可以一起來學習
    2020-07-07
  • 基于SpringBoot實現(xiàn)文件秒傳功能

    基于SpringBoot實現(xiàn)文件秒傳功能

    在開發(fā)Web應(yīng)用時,文件上傳是一個常見需求,然而,當用戶需要上傳大文件或相同文件多次時,會造成帶寬浪費和服務(wù)器存儲冗余,此時可以使用文件秒傳技術(shù)通過識別重復(fù)文件,本文就給大家介紹了如何基于SpringBoot實現(xiàn)文件秒傳功能,需要的朋友可以參考下
    2025-04-04
  • SpringBoot啟動時自動執(zhí)行代碼的幾種實現(xiàn)方式

    SpringBoot啟動時自動執(zhí)行代碼的幾種實現(xiàn)方式

    這篇文章主要給大家介紹了關(guān)于SpringBoot啟動時自動執(zhí)行代碼的幾種實現(xiàn)方式,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2022-02-02
  • SpringBoot項目如何打可執(zhí)行war包

    SpringBoot項目如何打可執(zhí)行war包

    最近小編做了一個springboot項目,最后需要打成war包在容器中部署,下面小編給大家分享下SpringBoot項目如何打可執(zhí)行war包,感興趣的朋友一起看看吧
    2020-04-04
  • java求兩個數(shù)中的大數(shù)(實例講解)

    java求兩個數(shù)中的大數(shù)(實例講解)

    下面小編就為大家?guī)硪黄猨ava求兩個數(shù)中的大數(shù)(實例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10

最新評論