🎛 Конфигурация Spring Boot: YAML, Профили и Секреты
Хардкодить настройки (порты, пароли, URL-ы) в Java-коде - это моветон. Если вам нужно поменять порт сервера, вы не должны перекомпилировать приложение.
Spring Boot следует принципу: "Код отдельно, настройки отдельно".
1️⃣ Properties vs YAML
По умолчанию Spring создает
Весь мир переходит на YAML (
Было (
Стало (
Меньше дублирования, глазам приятнее.
2️⃣ Как достать настройки в коде?
Способ А: Простой (
Подходит для точечных настроек.
Способ Б: Профессиональный (
Если настроек много (например, настройки почты или API), лучше собрать их в отдельный класс. Это дает типизацию и проверку данных!
Теперь вы просто внедряете
3️⃣ Профили (Profiles) - Киллер-фича
На локальной машине у вас H2 база данных, а на продакшене - PostgreSQL. Как не менять конфиги вручную?
Используйте Профили.
Вы создаете несколько файлов рядом с основным
🔴
🔴
В основном файле вы указываете, какой профиль активен по умолчанию:
А при запуске на сервере вы просто передаете флаг, и Spring подхватит нужный файл, перетерев дефолтные настройки:
4️⃣ Секреты (Никаких паролей в Git!)
Самая страшная ошибка - закоммитить
Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).
Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.
🔴 В файле:
🔴 В переменной ОС:
Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.
🔥 Итог
1. Используйте YAML вместо properties.
2. Группируйте настройки через
3. Разделяйте среды через Профили (
4. Никогда не храните боевые пароли в файлах. Используйте ENV vars.
#SpringBoot #Configuration #YAML #DevOps #BestPractices
📲 Мы в MAX
👉@BookJava
Хардкодить настройки (порты, пароли, URL-ы) в Java-коде - это моветон. Если вам нужно поменять порт сервера, вы не должны перекомпилировать приложение.
Spring Boot следует принципу: "Код отдельно, настройки отдельно".
1️⃣ Properties vs YAML
По умолчанию Spring создает
application.properties. Это старый формат (ключ=значение).Весь мир переходит на YAML (
.yaml или .yml). Он читабельнее и поддерживает иерархию.Было (
.properties):
spring.datasource.url=jdbc:postgresql://localhost/db
spring.datasource.username=admin
server.port=8080
Стало (
.yaml):
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost/db
username: admin
Меньше дублирования, глазам приятнее.
2️⃣ Как достать настройки в коде?
Способ А: Простой (
@Value)Подходит для точечных настроек.
@Value("${server.port}")
private int port;
Способ Б: Профессиональный (
@ConfigurationProperties)Если настроек много (например, настройки почты или API), лучше собрать их в отдельный класс. Это дает типизацию и проверку данных!
@ConfigurationProperties(prefix = "mail")
public record MailConfig(String host, int port, String username) {}
Теперь вы просто внедряете
MailConfig в свои сервисы, как обычный бин.3️⃣ Профили (Profiles) - Киллер-фича
На локальной машине у вас H2 база данных, а на продакшене - PostgreSQL. Как не менять конфиги вручную?
Используйте Профили.
Вы создаете несколько файлов рядом с основным
application.yaml:application-dev.yaml (для разработки)application-prod.yaml (для боевого сервера)В основном файле вы указываете, какой профиль активен по умолчанию:
spring:
profiles:
active: dev # По умолчанию грузим dev-настройки
А при запуске на сервере вы просто передаете флаг, и Spring подхватит нужный файл, перетерев дефолтные настройки:
java -jar app.jar -Dspring.profiles.active=prod4️⃣ Секреты (Никаких паролей в Git!)
Самая страшная ошибка - закоммитить
application-prod.yaml с паролем от боевой БД в репозиторий. ☠️Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).
Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.
spring.datasource.password=secretSPRING_DATASOURCE_PASSWORD=SuperSecurePass123Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.
🔥 Итог
1. Используйте YAML вместо properties.
2. Группируйте настройки через
@ConfigurationProperties.3. Разделяйте среды через Профили (
dev, test, prod).4. Никогда не храните боевые пароли в файлах. Используйте ENV vars.
#SpringBoot #Configuration #YAML #DevOps #BestPractices
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍1🤔1
🎥 Открытый урок «Apache Camel: масштабируемые интеграции для Highload».
🗓 28 января в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Advanced».
Что будет на вебинаре:
✔️ Архитектурные паттерны отказоустойчивости для распределённых систем.
✔️ Тонкая настройка производительности: пулы потоков, back-pressure, мониторинг.
✔️ Стратегии масштабирования: горизонталь, шардинг, разделение нагрузки.
✔️ Разбор реальных проблем и решений в highload-сценариях.
✔️ Live-сессия: ответы на вопросы по архитектуре.
В результате вебинара вы:
- Получите готовые архитектурные подходы, чек-листы и настройки, чтобы ваши Camel-интеграции масштабировались вместе с бизнесом и выдерживали пиковые нагрузки
Кому будет интересно:
Архитекторы интеграций и backend-разработчики, техлиды и DevOps, которым нужно держать высокую нагрузку без деградации сервисов.
🔗 Ссылка на регистрацию: https://vk.cc/cTLgty
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🗓 28 января в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Advanced».
Как сделать так, чтобы ваши интеграции на Camel не стали узким местом при росте нагрузки?
Что будет на вебинаре:
В результате вебинара вы:
- Получите готовые архитектурные подходы, чек-листы и настройки, чтобы ваши Camel-интеграции масштабировались вместе с бизнесом и выдерживали пиковые нагрузки
Кому будет интересно:
Архитекторы интеграций и backend-разработчики, техлиды и DevOps, которым нужно держать высокую нагрузку без деградации сервисов.
🔗 Ссылка на регистрацию: https://vk.cc/cTLgty
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
🧪 Тестирование в Spring Boot: Спите спокойно
Глобально тесты делятся на два лагеря:
1. Unit-тесты (Модульные): Быстрые, изолированные. Проверяем только логику одного класса (обычно Service). Никаких баз данных и поднятия Spring Context.
2. Integration-тесты (Интеграционные): Проверяем, как компоненты работают вместе (Controller + Service + DB). Здесь поднимается Spring Context.
⚡ 1. Unit-тесты: Изоляция и Скорость
Когда вы тестируете
Для этого мы используем Mockito - библиотеку, которая создает "фейковые" объекты (моки).
Ключевые аннотации:
🔴
🔴
🔴
💻 Пример Unit-теста:
🐢 2. Integration-тесты: Тяжелая артиллерия
Иногда нужно проверить, правильно ли мапится JSON в контроллере или работает ли SQL-запрос. Тут нам нужен Spring Context.
Ключевые аннотации:
🔴
🔴
🔴
💻 Пример теста Контроллера (
⚔️
Это самый частый вопрос.
1.
2.
🔥 Итог
🔴 Пишите много Unit-тестов (они быстрые). Используйте
🔴 Пишите немного Integration-тестов (они проверяют связки). Используйте
🔴 Никогда не тестируйте внешней API или боевую БД - мокайте их!
#SpringBoot #Testing #JUnit5 #Mockito #QualityAssurance
📲 Мы в MAX
👉@BookJava
Глобально тесты делятся на два лагеря:
1. Unit-тесты (Модульные): Быстрые, изолированные. Проверяем только логику одного класса (обычно Service). Никаких баз данных и поднятия Spring Context.
2. Integration-тесты (Интеграционные): Проверяем, как компоненты работают вместе (Controller + Service + DB). Здесь поднимается Spring Context.
⚡ 1. Unit-тесты: Изоляция и Скорость
Когда вы тестируете
UserService, вам не нужно, чтобы он реально лез в базу данных. Вам нужно проверить: "Если репозиторий вернет null, выбросит ли сервис ошибку?"Для этого мы используем Mockito - библиотеку, которая создает "фейковые" объекты (моки).
Ключевые аннотации:
@ExtendWith(MockitoExtension.class) - включаем Mockito.@Mock - "Создай фейковый объект" (например, UserRepository).@InjectMocks - "Создай тестируемый объект (UserService) и вставь в него моки".💻 Пример Unit-теста:
@ExtendWith(MockitoExtension.class) // 1. Включаем Mockito
class UserServiceTest {
@Mock
private UserRepository userRepository; // Фейк
@InjectMocks
private UserService userService; // Реальный сервис с фейком внутри
@Test
void shouldReturnUser_WhenExists() {
// GIVEN (Дано) - Настраиваем поведение мока
User mockUser = new User("Alex");
// "Если кто-то вызовет findById(1), верни mockUser"
Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));
// WHEN (Когда) - Вызываем метод сервиса
User result = userService.findById(1L);
// THEN (Тогда) - Проверяем результат
Assertions.assertEquals("Alex", result.getName());
// Проверяем, что метод репозитория действительно вызывался 1 раз
Mockito.verify(userRepository, times(1)).findById(1L);
}
}
🐢 2. Integration-тесты: Тяжелая артиллерия
Иногда нужно проверить, правильно ли мапится JSON в контроллере или работает ли SQL-запрос. Тут нам нужен Spring Context.
Ключевые аннотации:
@SpringBootTest - Поднимает весь контекст приложения (тяжело и медленно, но честно).@WebMvcTest - Поднимает только веб-слой (Контроллеры). Сервисы и БД не грузятся.@MockBean - Главная магия Spring Test. Это как @Mock, только этот мок кладется прямо в Spring Context, заменяя собой настоящий бин.💻 Пример теста Контроллера (
@WebMvcTest):
@WebMvcTest(UserController.class) // Грузим только контроллер
class UserControllerTest {
@Autowired
private MockMvc mockMvc; // Инструмент для имитации HTTP-запросов
@MockBean // Заменяем настоящий сервис заглушкой в контексте Spring
private UserService userService;
@Test
void shouldReturnStatus200() throws Exception {
Mockito.when(userService.findById(1L)).thenReturn(new User("Alex"));
mockMvc.perform(get("/users/1")) // Делаем GET запрос
.andExpect(status().isOk()) // Ждем 200 OK
.andExpect(jsonPath("$.name").value("Alex")); // Проверяем JSON
}
}
⚔️
@Mock vs @MockBean - Не путать!Это самый частый вопрос.
1.
@Mock (из org.mockito): Используется в Unit-тестах. Быстро. Spring про него ничего не знает.2.
@MockBean (из spring-boot-test): Используется в Integration-тестах. Spring находит этот бин в контексте и подменяет его на мок. Медленнее.🔥 Итог
Mockito.when(...).MockMvc.#SpringBoot #Testing #JUnit5 #Mockito #QualityAssurance
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
📦 От Кода к Продакшену: JAR и Docker
В старые времена (Java EE) процесс деплоя был адом: нужно было установить на сервер Tomcat, настроить его, скомпилировать
Spring Boot принес концепцию Fat JAR (Жирный JAR).
🍔 1. Fat JAR - "Всё своё ношу с собой"
Spring Boot упаковывает ваше приложение, все библиотеки (зависимости) и даже сам веб-сервер (Tomcat) в один единственный файл
Этот файл работает как
Как собрать?
В терминале (в папке проекта):
В папке
Как запустить?
Где угодно (на сервере, на ноутбуке друга), где есть Java:
Всё! Сервер стартует.
🐳 2. Docker - "Работает везде"
JAR это хорошо. Но что, если на сервере стоит Java 11, а у вас Java 17? Или другая ОС? Начинается проблема "На моем компьютере работало!".
Docker решает это, упаковывая ваше приложение вместе с Java и операционной системой в Контейнер.
Пишем
Создайте файл без расширения с именем
Вариант для новичков (Простой):
Как запустить:
🏗 3. Multi-stage Build (Уровень Pro)
В варианте выше вам нужно сначала собрать JAR руками. Это неудобно для CI/CD.
В профессиональном Dockerfile мы делаем сборку внутри Docker.
Почему это круто? В финальном образе нет исходного кода и тяжелого Maven. Только Java и ваш JAR. Образ весит минимум, а собрать его можно одной командой
🔥 Итог
1. Maven/Gradle собирают код в один Fat JAR.
2. Dockerfile описывает среду для запуска.
3. Multi-stage build позволяет собирать и запускать приложение в изолированной среде, не засоряя систему.
#SpringBoot #Docker #DevOps #Deployment #Java
📲 Мы в MAX
👉@BookJava
В старые времена (Java EE) процесс деплоя был адом: нужно было установить на сервер Tomcat, настроить его, скомпилировать
.war файл, закинуть его в папку... 🤯Spring Boot принес концепцию Fat JAR (Жирный JAR).
🍔 1. Fat JAR - "Всё своё ношу с собой"
Spring Boot упаковывает ваше приложение, все библиотеки (зависимости) и даже сам веб-сервер (Tomcat) в один единственный файл
.jar.Этот файл работает как
.exe в Windows. Ему ничего не нужно, кроме установленной Java.Как собрать?
В терминале (в папке проекта):
# Для Maven
./mvnw clean package
# Для Gradle
./gradlew build
В папке
target (или build/libs) появится файл myapp-0.0.1-SNAPSHOT.jar.Как запустить?
Где угодно (на сервере, на ноутбуке друга), где есть Java:
java -jar myapp.0.0.1-SNAPSHOT.jar
Всё! Сервер стартует.
🐳 2. Docker - "Работает везде"
JAR это хорошо. Но что, если на сервере стоит Java 11, а у вас Java 17? Или другая ОС? Начинается проблема "На моем компьютере работало!".
Docker решает это, упаковывая ваше приложение вместе с Java и операционной системой в Контейнер.
Пишем
DockerfileСоздайте файл без расширения с именем
Dockerfile в корне проекта.Вариант для новичков (Простой):
# 1. Берем базовый образ с Java 17 (легковесный Alpine Linux)
FROM eclipse-temurin:17-jre-alpine
# 2. Копируем наш JAR внутрь образа
# (Предварительно нужно сделать mvn package руками!)
COPY target/*.jar app.jar
# 3. Говорим, какую команду запустить при старте контейнера
ENTRYPOINT ["java", "-jar", "/app.jar"]
Как запустить:
# 1. Собираем образ (Image)
docker build -t my-spring-app .
# 2. Запускаем контейнер
# -p 8080:8080 пробрасывает порт наружу
docker run -p 8080:8080 my-spring-app
🏗 3. Multi-stage Build (Уровень Pro)
В варианте выше вам нужно сначала собрать JAR руками. Это неудобно для CI/CD.
В профессиональном Dockerfile мы делаем сборку внутри Docker.
# --- Этап 1: Сборка (Build) ---
FROM maven:3.8.5-openjdk-17 AS builder
WORKDIR /app
COPY . .
# Собираем JAR, пропуская тесты (для скорости)
RUN mvn clean package -DskipTests
# --- Этап 2: Запуск (Run) ---
# Берем чистый, маленький образ для запуска
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# Копируем ТОЛЬКО готовый jar из первого этапа
COPY --from=builder /app/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
Почему это круто? В финальном образе нет исходного кода и тяжелого Maven. Только Java и ваш JAR. Образ весит минимум, а собрать его можно одной командой
docker build, даже если на компьютере вообще не установлена Java!🔥 Итог
1. Maven/Gradle собирают код в один Fat JAR.
2. Dockerfile описывает среду для запуска.
3. Multi-stage build позволяет собирать и запускать приложение в изолированной среде, не засоряя систему.
#SpringBoot #Docker #DevOps #Deployment #Java
📲 Мы в MAX
👉@BookJava
👍6❤2👎1
🧩 Микросервисы: Укрощение хаоса (Spring Cloud)
Когда у вас один сервис, всё просто. Но когда их становится 10, 20 или 50, возникают вопросы:
1. Как сервису А узнать IP-адрес сервиса Б? (А если он меняется динамически?)
2. Как не писать тонны кода для HTTP-запросов?
3. Как клиенту (фронтенду) обращаться ко всей этой куче сервисов?
Для этого есть три главных инструмента.
1️⃣ Eureka: Телефонная книга (Service Discovery)
В облаке сервисы постоянно перезапускаются, меняют IP-адреса и порты. Хардкодить
Eureka Server - это реестр.
🔴 Когда сервис (например,
🔴 Когда
В коде:
Вам нужно просто добавить аннотацию
2️⃣ OpenFeign: Магия общения
Окей, адрес мы нашли. Теперь нужно отправить запрос.
Раньше мы использовали
Feign позволяет вызывать удаленный REST-сервис так, будто это обычный метод интерфейса в вашем коде.
Было (
Стало (
Вы просто пишете интерфейс, а реализацию Spring сгенерирует сам!
Это называется Декларативный REST-клиент. Чисто, красиво, типизировано.
3️⃣ API Gateway: Единая точка входа
Представьте, что у вас 50 микросервисов. Фронтенд не должен знать адреса каждого из них (
Spring Cloud Gateway - это вахтер на входе.
Весь внешний мир стучится только в него (например, на порт 8080), а он уже сам разруливает, куда отправить запрос.
Что он делает:
1. Маршрутизация:
2. Безопасность: Проверяет JWT токен один раз на входе.
3. Rate Limiting: "Не больше 10 запросов в секунду от этого юзера".
Пример конфига (
⚡ Итог: Как это работает вместе?
1. Сервисы просыпаются и регистрируются в Eureka.
2. Фронтенд шлет запрос на Gateway.
3. Gateway спрашивает у Eureka адрес нужного сервиса и пересылает запрос.
4. Если сервисам нужно пообщаться между собой, они используют Feign.
#Java #Microservices #SpringCloud #Eureka #Feign
📲 Мы в MAX
👉@BookJava
Когда у вас один сервис, всё просто. Но когда их становится 10, 20 или 50, возникают вопросы:
1. Как сервису А узнать IP-адрес сервиса Б? (А если он меняется динамически?)
2. Как не писать тонны кода для HTTP-запросов?
3. Как клиенту (фронтенду) обращаться ко всей этой куче сервисов?
Для этого есть три главных инструмента.
1️⃣ Eureka: Телефонная книга (Service Discovery)
В облаке сервисы постоянно перезапускаются, меняют IP-адреса и порты. Хардкодить
http://localhost:8081 в коде - самоубийство.Eureka Server - это реестр.
OrderService) запускается, он звонит в Eureka: "Привет, я OrderService, мой IP такой-то".UserService хочет найти заказы, он спрашивает Eureka: "Где сейчас живет OrderService?".В коде:
Вам нужно просто добавить аннотацию
@EnableDiscoveryClient, и магия произойдет сама. Сервисы будут находить друг друга по имени, а не по IP.2️⃣ OpenFeign: Магия общения
Окей, адрес мы нашли. Теперь нужно отправить запрос.
Раньше мы использовали
RestTemplate - это было громоздко и некрасиво.Feign позволяет вызывать удаленный REST-сервис так, будто это обычный метод интерфейса в вашем коде.
Было (
RestTemplate):
String url = "http://order-service/orders/" + userId;
List<Order> orders = restTemplate.getForObject(url, List.class); // Фу, нетипизированно
Стало (
FeignClient):Вы просто пишете интерфейс, а реализацию Spring сгенерирует сам!
@FeignClient(name = "order-service") // Имя сервиса в Eureka
public interface OrderClient {
@GetMapping("/orders/{userId}")
List<Order> getUserOrders(@PathVariable Long userId);
}
// Использование в сервисе:
// List<Order> orders = orderClient.getUserOrders(123L);
Это называется Декларативный REST-клиент. Чисто, красиво, типизировано.
3️⃣ API Gateway: Единая точка входа
Представьте, что у вас 50 микросервисов. Фронтенд не должен знать адреса каждого из них (
api.com:8081, api.com:8082...). Это небезопасно и сложно (CORS error, привет 👋).Spring Cloud Gateway - это вахтер на входе.
Весь внешний мир стучится только в него (например, на порт 8080), а он уже сам разруливает, куда отправить запрос.
Что он делает:
1. Маршрутизация:
/users/** -> лети в UserService, /orders/** -> лети в OrderService.2. Безопасность: Проверяет JWT токен один раз на входе.
3. Rate Limiting: "Не больше 10 запросов в секунду от этого юзера".
Пример конфига (
application.yaml):
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE # lb = Load Balancer (через Eureka)
predicates:
- Path=/users/**
⚡ Итог: Как это работает вместе?
1. Сервисы просыпаются и регистрируются в Eureka.
2. Фронтенд шлет запрос на Gateway.
3. Gateway спрашивает у Eureka адрес нужного сервиса и пересылает запрос.
4. Если сервисам нужно пообщаться между собой, они используют Feign.
#Java #Microservices #SpringCloud #Eureka #Feign
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝6👍5
📨 Apache Kafka: Нервная система микросервисов
Представьте, что вы заказали пиццу.
🔴 REST подход: Вы стоите у прилавка и смотрите на повара, пока он не закончит. Вы не можете отойти. Если повар уснул - вы застряли.
🔴 Kafka подход: Вы бросаете чек в коробку "Заказы" и уходите по своим делам. Повар возьмет заказ, когда освободится. Когда пицца будет готова, он положит её на стол выдачи, и вы получите уведомление.
Kafka - это распределенный лог событий. Это не просто очередь, это история всего, что произошло в системе.
🧩 Основные понятия
1. Topic (Топик) - Это "папка" или канал, куда падают сообщения. Например:
2. Producer (Продюсер) - Тот, кто пишет сообщения в топик (например, сервис Заказов).
3. Consumer (Консьюмер) - Тот, кто читает сообщения (например, сервис Уведомлений или Склад).
4. Broker (Брокер) - Сервер Kafka, который хранит эти данные.
🚀 Главная фишка: Fire and Forget
Когда
Он просто кидает событие
Сервисы-подписчики (Consumers) разгребут эти сообщения в своем темпе. Если сервис SMS упал, он поднимется через час, прочитает топик с того места, где остановился, и дошлет все смски. Данные не пропадут.
💻 Spring Kafka: Как писать код?
В Spring Boot работа с Kafka максимально упрощена.
1. Настройка (
2. Продюсер (Отправляем сообщение)
Нам нужен бин
3. Консьюмер (Слушаем эфир)
Просто вешаем аннотацию
⚡ Kafka vs RabbitMQ (Коротко)
Частый холивар.
🔴 RabbitMQ - это классическая Очередь. Сообщение прочитали -> оно удалилось. Это "умный брокер, глупые потребители".
🔴 Kafka - это Лог. Сообщения хранятся на диске днями (или вечно). Их можно перечитывать заново (Replay). Это идеально для аналитики и восстановления данных.
🔥 Итог
Kafka позволяет микросервисам быть слабосвязанными (decoupled).
🔴 Сервис А не знает о существовании Сервиса Б.
🔴 Система выдерживает пиковые нагрузки (Kafka просто буферизирует сообщения, пока консьюмеры не разгребут их).
#Java #Kafka #Microservices #SpringCloud #Architecture
📲 Мы в MAX
👉@BookJava
Представьте, что вы заказали пиццу.
Kafka - это распределенный лог событий. Это не просто очередь, это история всего, что произошло в системе.
🧩 Основные понятия
1. Topic (Топик) - Это "папка" или канал, куда падают сообщения. Например:
orders-topic, email-topic.2. Producer (Продюсер) - Тот, кто пишет сообщения в топик (например, сервис Заказов).
3. Consumer (Консьюмер) - Тот, кто читает сообщения (например, сервис Уведомлений или Склад).
4. Broker (Брокер) - Сервер Kafka, который хранит эти данные.
🚀 Главная фишка: Fire and Forget
Когда
OrderService создает заказ, ему плевать, работает ли сейчас сервис отправки SMS или сервис начисления бонусов.Он просто кидает событие
OrderCreated в Kafka и мгновенно возвращает ответ пользователю "Заказ принят".Сервисы-подписчики (Consumers) разгребут эти сообщения в своем темпе. Если сервис SMS упал, он поднимется через час, прочитает топик с того места, где остановился, и дошлет все смски. Данные не пропадут.
💻 Spring Kafka: Как писать код?
В Spring Boot работа с Kafka максимально упрощена.
1. Настройка (
application.yaml)
spring:
kafka:
bootstrap-servers: localhost:9092 # Адрес брокера
consumer:
group-id: my-group # Важно для масштабирования
2. Продюсер (Отправляем сообщение)
Нам нужен бин
KafkaTemplate.
@Service
@RequiredArgsConstructor
public class OrderProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public void sendOrderEvent(String orderId) {
// Отправляем в топик "orders"
kafkaTemplate.send("orders", orderId);
System.out.println("Сообщение отправлено: " + orderId);
}
}
3. Консьюмер (Слушаем эфир)
Просто вешаем аннотацию
@KafkaListener.
@Service
public class NotificationConsumer {
@KafkaListener(topics = "orders", groupId = "notification_group")
public void listen(String orderId) {
System.out.println("Получено событие для заказа: " + orderId);
// Тут логика отправки email/sms
sendEmail(orderId);
}
}
⚡ Kafka vs RabbitMQ (Коротко)
Частый холивар.
🔥 Итог
Kafka позволяет микросервисам быть слабосвязанными (decoupled).
#Java #Kafka #Microservices #SpringCloud #Architecture
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🔥2
🎥 Открытый урок «Eclipse Memory Analyzer (MAT): помощь в работе с heap».
🗓 04 февраля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Advanced».
Что будет на вебинаре:
✔️ Ключевые концепции работы с MAT и навигация по heap dump.
✔️ Экспресс-анализ дампа памяти: где искать утечки и рост объектов.
✔️ Разбор реального дампа в онлайне на предмет memory leak.
В результате вебинара:
Вы сможете самостоятельно проводить анализ дампов памяти. Будете знать возможности MAT и какие задачи решаются с его помощью.
Кому будет интересно:
Подойдёт Java-разработчикам, инженерам сопровождения и SRE, кто сталкивается с OutOfMemoryError и падениями по памяти.
🔗 Ссылка на регистрацию: https://vk.cc/cU0oou
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🗓 04 февраля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Advanced».
Без MAT сложно найти причины OutOfMemoryError и утечек. Разберём базу и полезные приёмы анализа heap dump.
Что будет на вебинаре:
В результате вебинара:
Вы сможете самостоятельно проводить анализ дампов памяти. Будете знать возможности MAT и какие задачи решаются с его помощью.
Кому будет интересно:
Подойдёт Java-разработчикам, инженерам сопровождения и SRE, кто сталкивается с OutOfMemoryError и падениями по памяти.
🔗 Ссылка на регистрацию: https://vk.cc/cU0oou
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
🚀 Redis + Spring Cache: Турбо-наддув для бэкенда
Самая медленная часть любого приложения это ввод-вывод (I/O). Поход в базу данных (Postgres/MySQL) это "долго" (миллисекунды). Поход в оперативную память это "мгновенно" (наносекунды).
Redis - это база данных, которая хранит всё в оперативной памяти (In-Memory). Она идеально подходит на роль кэша.
🧠 Как работает Spring Cache?
Spring предоставляет крутую абстракцию. Вам не нужно писать код для подключения к Redis в каждом методе. Вы просто вешаете аннотации, а Spring сам перехватывает вызов метода.
Алгоритм
1. Вызывается метод
2. Spring лезет в кэш (Redis) по ключу
3. Если данные есть (Cache Hit): Spring НЕ выполняет код метода, а сразу возвращает данные из кэша.
4. Если данных нет (Cache Miss): Spring выполняет метод (идет в БД), берет результат, кладет его в кэш и отдает вам.
🛠 Настройка (2 шага)
1. Зависимости
В
2. Включаем рубильник
Над главным классом вешаем
💻 Магия аннотаций
У нас есть 3 главные аннотации, которые вы обязаны знать:
1.
Вешаем над методами поиска (
Результат: Первый вызов займет 3 секунды. Второй, третий и тысячный вызов с тем же ID займут 0.001 секунды.
2.
Самая большая проблема кэширования - инвалидация. Если мы обновили данные юзера в БД, а в кэше осталась старая версия — это баг.
При обновлении или удалении мы должны очистить кэш.
Теперь при следующем вызове
3.
Используется реже. Метод выполняется всегда, а его результат кладется в кэш, обновляя старое значение.
🆚 Redis vs HashMap
"Зачем мне Redis, если я могу создать
1. Память: Если данных много,
2. Микросервисы: Если у вас запущено 3 экземпляра сервиса, у каждого будет свой
3. Живучесть: При перезагрузке приложения
⚠️ Важный нюанс: Serializable
Чтобы положить Java-объект в Redis, его нужно превратить в байты (сериализовать).
Ваши DTO и Entity должны реализовывать интерфейс
🔥 Итог: кэширование - это самый простой способ масштабирования.
🔴 Часто читаете, редко меняете? ->
🔴 Удалили/Обновили? ->
#Java #Spring #Redis #Caching #Performance
📲 Мы в MAX
👉@BookJava
Самая медленная часть любого приложения это ввод-вывод (I/O). Поход в базу данных (Postgres/MySQL) это "долго" (миллисекунды). Поход в оперативную память это "мгновенно" (наносекунды).
Redis - это база данных, которая хранит всё в оперативной памяти (In-Memory). Она идеально подходит на роль кэша.
🧠 Как работает Spring Cache?
Spring предоставляет крутую абстракцию. Вам не нужно писать код для подключения к Redis в каждом методе. Вы просто вешаете аннотации, а Spring сам перехватывает вызов метода.
Алгоритм
@Cacheable:1. Вызывается метод
getUser(1).2. Spring лезет в кэш (Redis) по ключу
user::1.3. Если данные есть (Cache Hit): Spring НЕ выполняет код метода, а сразу возвращает данные из кэша.
4. Если данных нет (Cache Miss): Spring выполняет метод (идет в БД), берет результат, кладет его в кэш и отдает вам.
🛠 Настройка (2 шага)
1. Зависимости
В
pom.xml добавляем стартер для кэша и драйвер Redis:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. Включаем рубильник
Над главным классом вешаем
@EnableCaching.💻 Магия аннотаций
У нас есть 3 главные аннотации, которые вы обязаны знать:
1.
@Cacheable — "Запомни меня"Вешаем над методами поиска (
get, find).
@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
// Имитация долгого запроса в БД (3 секунды)
simulateSlowService();
return userRepository.findById(id).orElseThrow();
}
}
Результат: Первый вызов займет 3 секунды. Второй, третий и тысячный вызов с тем же ID займут 0.001 секунды.
2.
@CacheEvict - "Забудь меня"Самая большая проблема кэширования - инвалидация. Если мы обновили данные юзера в БД, а в кэше осталась старая версия — это баг.
При обновлении или удалении мы должны очистить кэш.
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
Теперь при следующем вызове
getUserById(id) Spring увидит, что кэш пуст, и снова сходит в БД за свежими данными.3.
@CachePut - "Обнови меня"Используется реже. Метод выполняется всегда, а его результат кладется в кэш, обновляя старое значение.
🆚 Redis vs HashMap
"Зачем мне Redis, если я могу создать
ConcurrentHashMap прямо в Java?"1. Память: Если данных много,
HashMap съест всю память JVM, и приложение упадет (OutOfMemory). Redis живет отдельно.2. Микросервисы: Если у вас запущено 3 экземпляра сервиса, у каждого будет свой
HashMap. Кэш будет рассинхронизирован. Redis это общий кэш для всех инстансов.3. Живучесть: При перезагрузке приложения
HashMap очищается. Redis (обычно) работает на отдельном сервере и хранит данные даже при рестарте вашего кода.⚠️ Важный нюанс: Serializable
Чтобы положить Java-объект в Redis, его нужно превратить в байты (сериализовать).
Ваши DTO и Entity должны реализовывать интерфейс
Serializable, либо (что правильнее) нужно настроить Jackson Serializer, чтобы хранить данные в Redis в читаемом JSON-формате.🔥 Итог: кэширование - это самый простой способ масштабирования.
@Cacheable.@CacheEvict.#Java #Spring #Redis #Caching #Performance
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
👮♂️ Spring Security: Фейсконтроль для вашего API
Spring Security - это не просто библиотека, это мощный фреймворк, который встает стеной между интернетом и вашим контроллером.
Его работа строится на концепции Filter Chain (Цепочка фильтров). Каждый запрос проходит через серию проверок: "Есть ли токен?", "Валиден ли он?", "Есть ли права?".
🔑 Authentication vs Authorization
Два слова, которые путают все джуниоры.
1. Authentication (Аутентификация): "Кто ты?"
🔴 Ввод логина/пароля.
🔴 Проверка отпечатка пальца.
🔴 Ответ: 401 Unauthorized (если не знаем, кто это).
2. Authorization (Авторизация): "А что тебе можно?"
🔴 Ты Вася (мы тебя узнали), но ты хочешь удалить базу данных. Тебе нельзя.
🔴 Ответ: 403 Forbidden (знаем кто ты, но не пустим).
🎫 JWT (JSON Web Token) - Паспорт туриста
В микросервисах мы не храним состояние пользователя на сервере (Stateless). Вместо этого, при логине мы выдаем пользователю Токен.
JWT - это строка из трех частей, разделенных точками:
🔴 Payload: Полезные данные (User ID, Role, Email).
🔴 Signature: Цифровая подпись сервера. Гарантирует, что хитрый хакер не поменял в токене роль
Как это работает:
1. Клиент шлет Логин/Пароль -> Сервер проверяет и отдает JWT.
2. Клиент сохраняет JWT (обычно в LocalStorage браузера).
3. При каждом запросе клиент прикрепляет JWT в заголовок:
4. Сервер видит токен, проверяет подпись и пускает (не ходя в базу данных!).
🛡 Настройка (Spring Boot 3.x)
Раньше мы наследовались от
Сейчас мы просто объявляем бин
🔓 Что такое OAuth2?
JWT - это когда вы сами выдаете токены.
OAuth2 - это когда токены выдает кто-то большой и доверенный (Google, Facebook, GitHub).
Кнопка "Войти через Google" - это OAuth2.
1. Вы перенаправляете юзера на Google.
2. Google спрашивает: "Разрешить приложению MyShop узнать ваш email?".
3. Google возвращает вам токен.
4. Вы верите этому токену, потому что доверяете Google.
В Spring Boot это настраивается буквально в 5 строк в
🔥 Итог: безопасность для бэкенда это:
1. Spring Security как движок.
2. JWT как пропуск.
3. Stateless режим (без сессий).
4. HTTPS (обязательно, иначе токен украдут).
#SpringSecurity #JWT #OAuth2 #Java #CyberSecurity
📲 Мы в MAX
👉@BookJava
Spring Security - это не просто библиотека, это мощный фреймворк, который встает стеной между интернетом и вашим контроллером.
Его работа строится на концепции Filter Chain (Цепочка фильтров). Каждый запрос проходит через серию проверок: "Есть ли токен?", "Валиден ли он?", "Есть ли права?".
🔑 Authentication vs Authorization
Два слова, которые путают все джуниоры.
1. Authentication (Аутентификация): "Кто ты?"
2. Authorization (Авторизация): "А что тебе можно?"
🎫 JWT (JSON Web Token) - Паспорт туриста
В микросервисах мы не храним состояние пользователя на сервере (Stateless). Вместо этого, при логине мы выдаем пользователю Токен.
JWT - это строка из трех частей, разделенных точками:
Header.Payload.Signature.USER на ADMIN.Как это работает:
1. Клиент шлет Логин/Пароль -> Сервер проверяет и отдает JWT.
2. Клиент сохраняет JWT (обычно в LocalStorage браузера).
3. При каждом запросе клиент прикрепляет JWT в заголовок:
Authorization: Bearer <token>4. Сервер видит токен, проверяет подпись и пускает (не ходя в базу данных!).
🛡 Настройка (Spring Boot 3.x)
Раньше мы наследовались от
WebSecurityConfigurerAdapter. Забудьте, этот класс Deprecated.Сейчас мы просто объявляем бин
SecurityFilterChain.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable) // Для REST API отключаем
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // Никаких сессий!
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll() // Логин доступен всем
.requestMatchers("/admin/**").hasRole("ADMIN") // Админка только админам
.anyRequest().authenticated() // Всё остальное - только с токеном
)
// Добавляем наш кастомный фильтр для проверки JWT
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
🔓 Что такое OAuth2?
JWT - это когда вы сами выдаете токены.
OAuth2 - это когда токены выдает кто-то большой и доверенный (Google, Facebook, GitHub).
Кнопка "Войти через Google" - это OAuth2.
1. Вы перенаправляете юзера на Google.
2. Google спрашивает: "Разрешить приложению MyShop узнать ваш email?".
3. Google возвращает вам токен.
4. Вы верите этому токену, потому что доверяете Google.
В Spring Boot это настраивается буквально в 5 строк в
application.yaml, но под капотом там огромная машина стандартов.🔥 Итог: безопасность для бэкенда это:
1. Spring Security как движок.
2. JWT как пропуск.
3. Stateless режим (без сессий).
4. HTTPS (обязательно, иначе токен украдут).
#SpringSecurity #JWT #OAuth2 #Java #CyberSecurity
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2
А вы справитесь с тестом по HighLoad?
Как пройти путь от разработчика до архитектора высоконагруженных систем для работы с крупными проектами?
Пройдите тест, проверьте свои знания для обучения на курсе «Highload Architect» от OTUS. А так же и получите скидку🎁 до 15.02.2026 - подробности у менеджера.
➡️ Пройти Тест https://vk.cc/cU6fLb
На курсе вы освоите проектирование масштабируемых и отказоустойчивых систем, оптимизацию производительности, работу с современными инструментами для создания высоконагруженных решений и лучшие практики разработки серверных приложений.
❗️ Практическое обучение проводится в прямом эфире — вебинары не являются предзаписанными.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Как пройти путь от разработчика до архитектора высоконагруженных систем для работы с крупными проектами?
Пройдите тест, проверьте свои знания для обучения на курсе «Highload Architect» от OTUS. А так же и получите скидку
На курсе вы освоите проектирование масштабируемых и отказоустойчивых систем, оптимизацию производительности, работу с современными инструментами для создания высоконагруженных решений и лучшие практики разработки серверных приложений.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
🏗 SOLID - Пять заповедей программиста
Почему один проект живет 10 лет и его легко дорабатывать, а другой через полгода превращается в "Legacy", к которому страшно подходить?
Разница в соблюдении принципов SOLID.
Это аббревиатура из 5 правил, сформулированных Робертом Мартином (Дядя Боб). Если вы нарушаете их - ваш код "гниет".
Давайте разберем каждую букву.
1️⃣ S - Single Responsibility Principle (Единственная ответственность)
⛔ Как делают новички (God Object):
Класс
1. Считает сумму заказа.
2. Сохраняет заказ в БД.
3. Отправляет email клиенту.
4. Генерирует PDF-чек.
Если бизнес попросит изменить формат чека — мы лезем в этот класс. Если поменяется логика БД - опять в него. Риск сломать отправку писем при правке базы данных огромен!
✅ Как надо:
Разбиваем на маленькие классы:
•
•
•
•
2️⃣ O - Open-Closed Principle (Открытость/Закрытость)
Это значит: Не меняйте старый рабочий код, чтобы добавить новую фичу.
⛔ Плохо:
У нас есть метод расчета доставки.
✅ Хорошо:
Используем полиморфизм.
3️⃣ L - Liskov Substitution Principle (Принцип подстановки Барбары Лисков)
Если у вас есть класс
Суть: Если код работает с базовым классом, он должен работать и с любым его наследником, не зная об этом и не ломаясь.
4️⃣ I - Interface Segregation Principle (Разделение интерфейсов)
⛔ Плохо:
Интерфейс
Мы создаем класс
Нам придется реализовать метод
✅ Хорошо:
Разбейте на
Человек имплементирует оба. Робот - только
5️⃣ D - Dependency Inversion Principle (Инверсия зависимостей)
Это то, что мы учили в Spring (DI).
Ваш
Тогда вы сможете легко подменить Postgres на MySQL или Mock-объект для тестов, не меняя ни строчки в Сервисе.
SOLID - это фильтр. Прежде чем закоммитить код, спросите себя:
1. Не делает ли мой класс слишком много? (S)
2. Придется ли мне переписывать этот класс, если добавятся новые условия? (O)
3. Не ломаю ли я поведение родителя? (L)
4. Не заставляю ли я других реализовывать ненужные методы? (I)
5. Завишу ли я от интерфейсов или от конкретных классов? (D)
#Architecture #SOLID #CleanCode #OODesign
📲 Мы в MAX
👉@BookJava
Почему один проект живет 10 лет и его легко дорабатывать, а другой через полгода превращается в "Legacy", к которому страшно подходить?
Разница в соблюдении принципов SOLID.
Это аббревиатура из 5 правил, сформулированных Робертом Мартином (Дядя Боб). Если вы нарушаете их - ваш код "гниет".
Давайте разберем каждую букву.
1️⃣ S - Single Responsibility Principle (Единственная ответственность)
"У класса должна быть только одна причина для изменения."
⛔ Как делают новички (God Object):
Класс
OrderService делает всё:1. Считает сумму заказа.
2. Сохраняет заказ в БД.
3. Отправляет email клиенту.
4. Генерирует PDF-чек.
Если бизнес попросит изменить формат чека — мы лезем в этот класс. Если поменяется логика БД - опять в него. Риск сломать отправку писем при правке базы данных огромен!
✅ Как надо:
Разбиваем на маленькие классы:
•
OrderCalculator (считает).•
OrderRepository (сохраняет).•
EmailNotificationService (шлет письма).•
PdfGenerator (печатает).OrderService теперь просто дирижер, который вызывает эти компоненты.2️⃣ O - Open-Closed Principle (Открытость/Закрытость)
"Программные сущности должны быть открыты для расширения, но закрыты для модификации."
Это значит: Не меняйте старый рабочий код, чтобы добавить новую фичу.
⛔ Плохо:
У нас есть метод расчета доставки.
if (deliveryType == "DHL") { ... }
else if (deliveryType == "Post") { ... }
// Пришла задача добавить FedEx? Придется лезть сюда и добавлять else if!
✅ Хорошо:
Используем полиморфизм.
interface DeliveryStrategy { void deliver(); }
class DhlDelivery implements DeliveryStrategy { ... }
class PostDelivery implements DeliveryStrategy { ... }
// Нужен FedEx? Просто создаем НОВЫЙ класс, не трогая старые!
class FedExDelivery implements DeliveryStrategy { ... }
3️⃣ L - Liskov Substitution Principle (Принцип подстановки Барбары Лисков)
"Наследники должны без проблем заменять родителей."
Если у вас есть класс
Bird с методом fly(), а вы создали наследника Penguin (Пингвин), который при вызове fly() бросает ошибку (потому что пингвины не летают) - вы нарушили LSP.Суть: Если код работает с базовым классом, он должен работать и с любым его наследником, не зная об этом и не ломаясь.
4️⃣ I - Interface Segregation Principle (Разделение интерфейсов)
"Много маленьких интерфейсов лучше, чем один огромный."
⛔ Плохо:
Интерфейс
Worker имеет методы work() и eat().Мы создаем класс
Robot. Роботы работают, но не едят.Нам придется реализовать метод
eat() и оставить его пустым или кинуть ошибку. Это мусор.✅ Хорошо:
Разбейте на
Workable и Eatable.Человек имплементирует оба. Робот - только
Workable.5️⃣ D - Dependency Inversion Principle (Инверсия зависимостей)
"Зависьте от абстракций, а не от конкретики."
Это то, что мы учили в Spring (DI).
Ваш
Service не должен зависеть от PostgresRepository. Он должен зависеть от интерфейса Repository.Тогда вы сможете легко подменить Postgres на MySQL или Mock-объект для тестов, не меняя ни строчки в Сервисе.
SOLID - это фильтр. Прежде чем закоммитить код, спросите себя:
1. Не делает ли мой класс слишком много? (S)
2. Придется ли мне переписывать этот класс, если добавятся новые условия? (O)
3. Не ломаю ли я поведение родителя? (L)
4. Не заставляю ли я других реализовывать ненужные методы? (I)
5. Завишу ли я от интерфейсов или от конкретных классов? (D)
#Architecture #SOLID #CleanCode #OODesign
📲 Мы в MAX
👉@BookJava
👍11❤2🔥2