Привет, друзья, сегодня я поделюсь с вами статьей о технологическом росте Amway. Я верю, что если вы прочитаете ее внимательно, вы обязательно что-то приобретете!
🔗【Ссылка на статью】:«Исследование в 2024 году»
💖 Причина рекомендации: Эту статью написал Одноклассник Сяо Ху Написанный, он рассказывает историю собственного роста, тщательно записывает этот рост, а также практикует и делится техниками.
Операция инициализации системы является очень распространенным требованием. Обычно после запуска приложению необходимо выполнить некоторые важные задачи инициализации, такие как загрузка глобальной конфигурации, инициализация таблиц базы данных, предварительный разогрев кэша, запуск фоновых задач и т. д. Как выбрать подходящее техническое решение для обеспечения эффективного выполнения задач инициализации в различных сценариях, особенно в распределенном развертывании с несколькими экземплярами, как обеспечить выполнение задач только один раз, стало ключом к нашему глубокому обдумыванию и оптимизации в реальном проекте. операции. вопрос.
В этой статье будет объединена среда Spring Boot, от базового механизма запуска, основных технических принципов до сложных сценариев в распределенной среде, чтобы привести вас к постепенному и глубокому пониманию того, как выполнять задачи инициализации после запуска различными способами. Наконец, мы будем использовать практический пример проекта, чтобы продемонстрировать, как обеспечить, чтобы задача инициализации выполнялась только один раз в распределенной среде развертывания, и решить проблему повторного выполнения задачи в нескольких экземплярах.
У этих задач есть одна общая черта: обычно их нужно выполнить только один раз, при запуске приложения. Поэтому крайне важно выбрать подходящий механизм для выполнения этих операций инициализации и гарантировать, что задачи не будут выполняться повторно в распределенной среде. Включая, но не ограничиваясь:
Spring Boot предоставляет несколько механизмов для выполнения задач инициализации после запуска приложения. Эти механизмы удовлетворяют потребности автономного и распределенного развертывания и имеют разные сроки выполнения и применимые сценарии.
@PostConstruct
это очень краткий и часто используемый способ отметить Spring управление Bean Метод автоматически вызывается после завершения внедрения зависимостей. Этот метод особенно подходит для одного Bean операция инициализации. Весна После завершения внедрения зависимостей автоматически вызовите с помощью @PostConstruct
Аннотированные методы гарантируют, что логика инициализации находится в рабочем состоянии. Bean Выполняется после завершения инициализации.
подходит для использования в конкретном Bean Задачи, которые необходимо выполнить после завершения инициализации. Например, определенная Категория услугинуждатьсясуществовать Читать во время загрузки Конфигурациядокументили Выполнение определенных операций инициализации。
@Component
public class MyService {
@PostConstruct
public void init() {
// Инициализируйте задачу и выполните ее только один раз
System.out.println("Bean Выполнить после инициализации");
}
}
@PostConstruct
Аннотации,Весна будет внутри Bean После инициализации Автоматический вызов Долженметод。@PostConstruct
Метод аннотации может действовать только на конкретный Bean,существоватьэтот Bean Выполняется после завершения инициализации. Если есть несколько Bean нуждатьсяинициализация Задача,@PostConstruct
Не могу пересечь Bean Логика выполнения управления.CommandLineRunner и ApplicationRunner — это интерфейсы Spring Boot, используемые для выполнения задач инициализации после запуска приложения. Разница между ними заключается в форме передаваемых параметров. CommandLineRunner предоставляет исходные параметры String[], а ApplicationRunner инкапсулирует контекстную информацию параметров запуска.
CommandLineRunner:этот Предоставляемый интерфейсиздаоригинальный String[]
Параметры запуска. Эти параметры обычно передаются при запуске приложения. Java Аргументы командной строки программы. Если вас интересуют параметры командной строки только при запуске приложения и вам необходимо напрямую манипулировать ими, вы можете использовать CommandLineRunner
。
ApplicationRunner:этот Интерфейс инкапсулирует запускчасизпараметр,проходить ApplicationArguments
Класс обеспечивает доступ более высокого уровня к параметрам командной строки. Если вам нужна дополнительная функциональность (например, получение аргументов командной строки в нестандартных форматах, обработка аргументов с флагами и т. д.), вы можете использовать ApplicationRunner
。
CommandLineRunner
все еще ApplicationRunner
,Все могутсуществоватьвсе Bean Выполняется после завершения инициализации, чтобы гарантировать, что логика запуска приложения является глобальной.run()
метод,Выполнение задачиавтоматическое,Не обязательно звонить напрямую.CommandLineRunner
или ApplicationRunner
выбирать классы, по умолчанию порядок их выполнения не определен. Чтобы обеспечить порядок выполнения, вы можете использовать @Order
Аннотации явно указывают приоритет выполнения.CommandLineRunner
@Component
public class MyStartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// Задачи, которые необходимо выполнить после запуска этого приложения
System.out.println("Выполнять задачи инициализации после запуска приложения");
}
}
ApplicationRunner
@Component
public class MyAppStartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// Получить параметры командной строки
System.out.println("Выполнить задачи инициализации после запуска приложения и получить параметры запуска:" + args.getOptionNames());
}
}
После запуска мы найдем,@Component
Порядок выполнения действительно раньше, чем ApplicationRunner
и CommandLineRunner
。
@Component с аннотацией Bean:Все, что отмечено как @Компонент (или @Service、@Repository、@Controller и т. д.) занятия будут проходить в Spring Boot Он автоматически сканируется и создается при запуске приложения. Эти Bean будет внутри Spring Контейнер создается и инициализируется на ранних этапах запуска, а загружается и выполняется самое раннее в процессе запуска приложения.
ApplicationRunner и CommandLineRunner: Классы реализации этих двух интерфейсов: Spring Boot Уникальные хуки запуска, они присутствуют во всех @Component Bean создается и выполняется после инициализации, но существует Spring Boot Полный запуск приложения(То есть контекст приложения готов)После выполнения。ApplicationRunner буду сравнивать CommandLineRunner выполняется раньше, поскольку он инкапсулирует больше информации о контексте параметра запуска, поэтому их run() методбудет внутри Spring Boot Полное обновление контекста Bean Выполняется после инициализации.
Если в вашем проекте есть несколько классов отбора,И все они должны выполняться при запуске приложения,использовать @Order
Аннотации могут явно контролировать порядок выполнения. Например:
@Component
@Order(1) // Установите приоритет. Чем меньше число, тем выше приоритет.
public class FirstStartupTask implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Первая задача запуска");
}
}
@Component
@Order(2)
public class SecondStartupTask implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Вторая задача запуска");
}
}
Таким образом, FirstStartupTask будет внутри SecondStartupTask выполнен раньше.
Spring Boot Модель программирования, управляемая событиями, может помочь разработчикам существовать в выполнении конкретных задач на разных этапах жизненного цикла приложения. Автор: Слушайте события жизненного цикла С помощью Spring разработчики могут выполнять задачи инициализации в точное время. Этот метод подходит для сценариев, где необходимо обеспечить время выполнения задач. Например, некоторые задачи не могут быть выполнены до полного запуска приложения, установления соединения с базой данных и готовности сервиса. Весна Boot В , существует множество событий жизненного цикла, таких как:
ApplicationReadyEvent:Запускается, когда приложение полностью запущено и готово обрабатывать запросы.。этотсобытиевыражать Spring Контекст приложения полностью инициализирован, и приложение готово принимать внешние запросы. Подходит для задач инициализации, выполняемых сразу после запуска приложения, таких как запуск фоновых служб, инициализация кэша и т. д.
ContextRefreshedEvent:когда Spring Запускается, когда контекст инициализируется или обновляется. Обычно это происходит, когда Spring Boot Во время запуска используется для обозначения Spring Контейнеры готовы и все Bean Инициализация завершена. - При запуске приложения удобно выполнять некоторые операции предварительного разогрева, например загрузку информации о конфигурации, инициализацию пула подключений к базе данных и т. д.
ApplicationStartedEvent:существовать Spring Boot Срабатывает при запуске приложения, происходит в Spring Может использоваться для выполнения некоторых задач ранней инициализации до загрузки контекста.
ApplicationEnvironmentPreparedEvent:существовать Spring Boot Во время запуска, когда приложение Environment
Срабатывает, когда настройка завершена. Еще не инициализирован Spring Контейнеры подходят для некоторой инициализации на основе конфигурации среды.
ApplicationFailedEvent:если Spring Boot Если запуск не удался, это событие будет вызвано. Может использоваться для очистки или ведения журнала после сбоя при запуске приложения.
Spring Boot предоставил ApplicationListener
Интерфейс @EventListener
аннотация приходите мониторить эти события жизненного цикла. Мы можем использовать эти два метода для выполнения задач инициализации в определенное время.
ApplicationListener
монитор ApplicationReadyEvent
путем реализации ApplicationListener Интерфейс, может быть указан как мониторсобытия, например монитор. ApplicationReadyEvent чтобы гарантировать выполнение задачи после полного запуска приложения.
@Component
public class ApplicationListenerExample implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// Задачи, выполняемые после завершения запуска приложения
System.out.println("Выполнять задачи после завершения запуска приложения");
}
}
ApplicationReadyEvent
да Spring Boot событие, возникающее после завершения запуска приложения.ApplicationReadyEvent
будет срабатывать.@EventListener
аннотациямониторсобытиеSpring 5 представил @EventListener
аннотация, это более краткий способ отслеживания событий, нет необходимости явно калибровать ApplicationListener интерфейс.
@Component
public class EventListenerExample {
@EventListener(ApplicationReadyEvent.class)
public void handleApplicationReady() {
// Задачи, выполняемые после завершения запуска приложения
System.out.println("использовать @EventListener существуют Выполнение задач после запуска приложения");
}
}
@EventListener(ApplicationReadyEvent.class)
выражатьмонитор ApplicationReadyEvent
событие。@EventListener
аннотацияизметодбудет внутри ApplicationReadyEvent
Выполнять при срабатывании, подходит для задач после полного запуска приложения.ApplicationReadyEvent
Событие гарантирует, что задачи будут выполняться только после полного запуска приложения.ContextRefreshedEvent
Может гарантировать существование некоторых задач инициализации Spring Выполняется после завершения инициализации контекста.@Bean(initMethod)
Определить собственный метод инициализациисуществовать Spring середина,@Bean(initMethod) предоставил Что-то вроде Настроить Bean Способ инициализации метода. С помощью этого механизма разработчики могут предоставлять конкретные Bean Укажите метод инициализации, который будет использоваться внутри Spring Контейнер завершает Bean Внедрение зависимостей и постэкземплярное создание Автоматическое исполнение。в целом,Этот метод используется для обработки некоторых сложных операций инициализации.,Например Инициализировать соединение с базой данных、Загрузить внешнюю конфигурацию、Запуск фоновых задач и т. д.
Подходит для тех, кому требуется сложная инициализация Bean:когда Bean Инициализация требует выполнения сложных операций (например, вызова внешнего API, загрузка исполняемого файла, инициализация подключения к базе данных и т. д.), вы можете передать initMethod Укажите метод инициализации без существования Bean добрыйсерединаиспользовать @Аннотация PostConstructили CommandLineRunner и т. д.
Внешняя конфигурация управляет логикой инициализации:@Bean(initMethod = "init") разрешено Bean Метод инициализации привязан к внешней конфигурации, что позволяет разработчикам более гибко управлять 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)
Позволяет разработчикам гибко указывать имя метода инициализации, подходящее для тех, кому необходимо существование. Bean Сценарии, в которых определенные задачи выполняются во время инициализации. и @PostConstruct
или CommandLineRunner
ждатьметодпо сравнению с,@Bean(initMethod)
Больше возможностей управления, особенно в сложных приложениях.initMethod
метод определяет конкретную логику инициализации.@Configuration
Конфигурация в классе Bean час,initMethod
вид, который не зависит от Bean Способ инициализации самого класса. это помогает Bean из Конфигурацияивыполнитьразделение。@PostConstruct
или CommandLineRunner
ждатьаннотацияиз Способ,@Bean(initMethod)
Нужен разработчик в конфигурации явно указывается имя метода инициализатора, что может привести к коду Немного менее читабельно, тем более в дасуществовать несколько Классов При настройке нескольких методов инициализации разработчикам может потребоваться более тщательно управлять этими методами.@Bean(initMethod)
Может показаться слишком излишним. В это время используйте @PostConstruct
или CommandLineRunner
Другие методы более краткие и прямые.@Bean(initMethod)
Инициализация, указанная в методе, должна быть выполнена Spring контейнеруправление Бобы. существуют в некоторых случаях (например, в некоторых чистых Java Объект или создан вручную Bean), не может быть инициализирован напрямую.Предположим, у нас есть приложение, которое требует существования для выполнения следующих задач инициализации при запуске:
мы будемиспользовать Spring Boot Различные методы инициализации в сочетании с Распределенной блокировка, гарантирующая, что задача будет выполнена только один раз. В частности, используйте следующие технологии:
@PostConstruct
:для простогозадачи инициализации。CommandLineRunner
:для глобальных задач,существование выполняется после запуска приложения.@Bean(initMethod)
:длянуждатьсяособенныйинициализациялогикаиз Bean Указывает метод инициализации.src
└── main
├── java
│ └── com
│ └── example
│ ├── Application.java
│ ├── config
│ │ └── AppConfig.java
│ ├── initializer
│ │ ├── AppStartupRunner.java
│ │ ├── CacheInitializer.java
│ │ └── DistributedLockInitializer.java
│ └── service
│ └── MyService.java
└── resources
└── application.properties
application.properties
# Redis Конфигурация
spring.redis.host=localhost
spring.redis.port=6379
# Конфигурация базы данных (если используется MySQL)
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=root
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);
}
}
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();
}
}
MyService.java
package com.example.service;
public class MyService {
public void init() {
// Здесь можно выполнять сложные операции инициализации, такие как вызовы внешних API и т. д.
System.out.println("Выполнить MyService из Настроитьинициализацияметод"); }
}
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 {
// Выполнить задачу после запуска приложения инициализации
System.out.println("Выполнить Запуск приложениячасизобщая ситуацияинициализация Задача");
}
}
CacheInitializer.java
package com.example.initializer;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class CacheInitializer {
@PostConstruct
public void init() {
// Предварительный разогрев логики кэша, например загрузка часто используемых данных в кэш.
System.out.println("Выполнить Прогрев кэшазадач");
}
}
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) {
// получать Распределенная блокировка, убедитесь, что задача инициализации выполняется только один раз
Boolean success = redisTemplate.opsForValue().setIfAbsent("init_lock", "locked");
if (Boolean.TRUE.equals(success)) {
// 模拟осуществлятьинициализация Задача(нравитьсяинициализациятехническая спецификация、нагрузка Конфигурацияждать)
System.out.println("Выполнитьинициализация Задача:инициализациябаза данныхилинагрузка Основные данные");
// Здесь вы можете выполнять такие задачи, как инициализация таблиц базы данных и загрузка данных по умолчанию.
} else {
System.out.println("Задача выполнялась в других экземплярах, текущий экземпляр пропустил задачу");
}
}
}
Используя эти технологии иметод,Разработчики могут гарантировать, что задачи реализации будут выполняться эффективно и безопасно при запуске приложения.,Избегайте повторного выполнения в среде с несколькими экземплярами. финальный,Эти решения могут помочь разработчикам обеспечить стабильность и производительность системы, обеспечивая при этом стабильность и производительность системы.,Улучшите ремонтопригодность и масштабируемость системы.