📦 От Кода к Продакшену: 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
🚀 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
🏗 Порождающие паттерны: Как рождаются объекты?
Создать объект просто:
А если у объекта 20 полей? А если нам нужен только один экземпляр на всё приложение? А если мы не знаем заранее, какой именно класс нам нужен?
Тут на сцену выходят паттерны.
1️⃣ Singleton (Одиночка)
Суть: Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Где нужен: Логгеры, Конфигурация, Пул соединений с БД.
Как реализовать:
1. Скрываем конструктор (
2. Создаем статическое поле с экземпляром.
3. Возвращаем его через статический метод.
⚠️ Важно: В Spring Boot все бины по умолчанию - синглтоны. Вам не нужно писать этот код руками, контейнер Spring сам следит, чтобы сервис был создан один раз.
2️⃣ Builder (Строитель)
Суть: Позволяет создавать сложные объекты пошагово. Спасает от «Телескопического конструктора» (когда у вас конструктор с 10 аргументами, и вы не помните, где там
Было (Ужас):
Стало (Builder):
🛠 Лайфхак:
В Java не нужно писать Билдер руками (это 50 строк кода). Просто поставьте аннотацию Lombok
3️⃣ Factory Method (Фабричный метод)
Суть: Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.
Это реализация принципа Open-Closed. Мы добавляем новые типы продуктов, не ломая существующий код.
Пример: У нас есть "Уведомления". Сегодня это Email, завтра SMS, послезавтра Push.
🔥 Итог
1. Singleton - когда нужен один объект на всю систему.
2. Builder - когда объект сложный и у него много параметров.
3. Factory - когда мы не знаем заранее, какой конкретно объект понадобится, или хотим скрыть логику выбора.
#DesignPatterns #GoF #Singleton #Builder #Factory #Java
📲 Мы в MAX
👉@BookJava
Создать объект просто:
User u = new User().А если у объекта 20 полей? А если нам нужен только один экземпляр на всё приложение? А если мы не знаем заранее, какой именно класс нам нужен?
Тут на сцену выходят паттерны.
1️⃣ Singleton (Одиночка)
Суть: Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Где нужен: Логгеры, Конфигурация, Пул соединений с БД.
Как реализовать:
1. Скрываем конструктор (
private).2. Создаем статическое поле с экземпляром.
3. Возвращаем его через статический метод.
public class Database {
// Единственный экземпляр
private static Database instance;
private Database() {} // Никто не создаст объект извне
public static synchronized Database getInstance() {
if (instance == null) {
instance = new Database();
}
return instance;
}
}
⚠️ Важно: В Spring Boot все бины по умолчанию - синглтоны. Вам не нужно писать этот код руками, контейнер Spring сам следит, чтобы сервис был создан один раз.
2️⃣ Builder (Строитель)
Суть: Позволяет создавать сложные объекты пошагово. Спасает от «Телескопического конструктора» (когда у вас конструктор с 10 аргументами, и вы не помните, где там
age, а где height).Было (Ужас):
new User("Alex", null, true, "admin", 25, null);Стало (Builder):
User user = User.builder()
.name("Alex")
.age(25)
.role("ADMIN")
.active(true)
.build();
🛠 Лайфхак:
В Java не нужно писать Билдер руками (это 50 строк кода). Просто поставьте аннотацию Lombok
@Builder над классом.3️⃣ Factory Method (Фабричный метод)
Суть: Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.
Это реализация принципа Open-Closed. Мы добавляем новые типы продуктов, не ломая существующий код.
Пример: У нас есть "Уведомления". Сегодня это Email, завтра SMS, послезавтра Push.
// 1. Интерфейс
interface Notification { void send(String msg); }
// 2. Реализации
class EmailNotification implements Notification { ... }
class SmsNotification implements Notification { ... }
// 3. Фабрика (Решает, что создать)
class NotificationFactory {
public static Notification create(String type) {
return switch (type) {
case "EMAIL" -> new EmailNotification();
case "SMS" -> new SmsNotification();
default -> throw new IllegalArgumentException("Unknown type");
};
}
}
// Клиентский код (не знает про классы Email/Sms, знает только интерфейс)
Notification notification = NotificationFactory.create("SMS");
notification.send("Hello!");
🔥 Итог
1. Singleton - когда нужен один объект на всю систему.
2. Builder - когда объект сложный и у него много параметров.
3. Factory - когда мы не знаем заранее, какой конкретно объект понадобится, или хотим скрыть логику выбора.
#DesignPatterns #GoF #Singleton #Builder #Factory #Java
📲 Мы в MAX
👉@BookJava
👍5🔥3
🧅 Архитектура: От Слоев к Луковице
❌ Проблема Слоенки (Database Driven Design)
В классическом Spring-приложении зависимости идут сверху вниз:
1. Контроллер зависит от Сервиса.
2. Сервис зависит от Репозитория (Базы данных).
В чем подвох?
Ваша бизнес-логика (Сервис) намертво привязана к деталям хранения данных (БД).
🔴 Хотите поменять SQL на NoSQL? Переписывайте сервис.
🔴 Хотите протестировать логику? Придется мокать базу данных.
🔴 Главный грех: База данных диктует, как писать бизнес-логику. А должно быть наоборот!
✅ Решение: Clean / Hexagonal / Onion
Дядя Боб, Алистер Кокберн и другие умные дядьки придумали, как перевернуть игру.
Главная идея: Зависимости должны быть направлены ТОЛЬКО внутрь, к центру.
Представьте приложение как Луковицу.
1. Ядро (Core / Domain) - Центр Вселенной
Здесь живет ваша Бизнес-логика.
🔴 Сущности (
🔴 Правила (
🔴 Правило: Здесь НЕТ фреймворков. Никакого Spring, никакого Hibernate, никакого SQL. Только чистая Java.
🔴 Этот слой ничего не знает о внешнем мире.
2. Порты (Ports / Use Cases) - Граница
Ядро определяет интерфейсы (Порты), которые ему нужны для работы.
🔴 Например:
🔴 Заметьте: интерфейс лежит внутри домена!
3. Адаптеры (Adapters / Infrastructure) - Внешний мир
Здесь живут детали реализации.
🔴
🔴
🔴 Здесь подключается Spring, Hibernate, Kafka и всё остальное.
🔄 Инверсия Зависимостей (DIP)
Следите за руками:
1. В слоеной архитектуре:
2. В чистой архитектуре:
Оба зависят от абстракции. БД стала просто плагином. Вы можете выкинуть Postgres и поставить заглушку (In-Memory Map) - и бизнес-логика даже не заметит подмены!
⚖️ Когда что использовать?
1. Layered (Controller-Service-Repo)
• ✅ Простые CRUD-приложения.
• ✅ Админки, прототипы.
• ✅ Когда логики почти нет, просто перекладываем данные.
2. Hexagonal (Ports & Adapters)
• ✅ Сложная бизнес-логика (Банкинг, Финтех, Логистика).
• ✅ Приложение живет долго (5+ лет).
• ✅ Нужно писать много Unit-тестов для ядра, не поднимая контекст Spring.
🔥 Итог
🔴 Layered: Быстро писать, сложно поддерживать. БД - главная.
🔴 Clean: Дольше писать (много маппингов DTO <-> Entity), легко поддерживать. Логика - главная.
#Architecture #CleanArchitecture #Hexagonal #Spring #Java
📲 Мы в MAX
👉@BookJava
❌ Проблема Слоенки (Database Driven Design)
В классическом Spring-приложении зависимости идут сверху вниз:
1. Контроллер зависит от Сервиса.
2. Сервис зависит от Репозитория (Базы данных).
В чем подвох?
Ваша бизнес-логика (Сервис) намертво привязана к деталям хранения данных (БД).
✅ Решение: Clean / Hexagonal / Onion
Дядя Боб, Алистер Кокберн и другие умные дядьки придумали, как перевернуть игру.
Главная идея: Зависимости должны быть направлены ТОЛЬКО внутрь, к центру.
Представьте приложение как Луковицу.
1. Ядро (Core / Domain) - Центр Вселенной
Здесь живет ваша Бизнес-логика.
User, Order).User не может быть моложе 18 лет).2. Порты (Ports / Use Cases) - Граница
Ядро определяет интерфейсы (Порты), которые ему нужны для работы.
interface UserRepository (найти пользователя, сохранить пользователя).3. Адаптеры (Adapters / Infrastructure) - Внешний мир
Здесь живут детали реализации.
PostgresUserRepository реализует интерфейс UserRepository.RestController вызывает методы Ядра.🔄 Инверсия Зависимостей (DIP)
Следите за руками:
1. В слоеной архитектуре:
Service зависит от PostgresDao.2. В чистой архитектуре:
Service зависит от Интерфейса. А PostgresDao зависит от Интерфейса.Оба зависят от абстракции. БД стала просто плагином. Вы можете выкинуть Postgres и поставить заглушку (In-Memory Map) - и бизнес-логика даже не заметит подмены!
⚖️ Когда что использовать?
1. Layered (Controller-Service-Repo)
• ✅ Простые CRUD-приложения.
• ✅ Админки, прототипы.
• ✅ Когда логики почти нет, просто перекладываем данные.
2. Hexagonal (Ports & Adapters)
• ✅ Сложная бизнес-логика (Банкинг, Финтех, Логистика).
• ✅ Приложение живет долго (5+ лет).
• ✅ Нужно писать много Unit-тестов для ядра, не поднимая контекст Spring.
🔥 Итог
#Architecture #CleanArchitecture #Hexagonal #Spring #Java
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2