Spring АйО
8.45K subscribers
304 photos
216 videos
405 links
Русскоязычное сообщество Spring-разработчиков.

Habr: bit.ly/433IK46
YouTube: bit.ly/4h3Ci0x
VK: bit.ly/4hF0OG8
Rutube: bit.ly/4b4UeX6
Яндекс Музыка: bit.ly/3EIizWy

Канал для общения: @spring_aio_chat
Download Telegram
Spring Tips: Переопределение свойств через переменные окружения

Часто в файле application.properties (или application.yml) объявляются свойства, значения которых содержат переменные вида ${ENV_PROPERTY_KEY:defaultValue}:


spring.datasource.url=jdbc:postgresql://${POSTGRES_HOST:localhost}/${POSTGRES_DB_NAME:local_dev_db}
spring.datasource.username=${POSTGRES_USERNAME:root}
spring.datasource.password=${POSTGRES_PASSWORD:root}
spring.datasource.driver-class-name=org.postgresql.Driver


Такой подход позволяет переопределять свойства при запуске приложения в разных средах (local, test, prod и т.д.).

Например, если мы решили запустить наше приложение через Docker Compose, предварительно собрав его в Docker образ, то передача значений для объявленных нами переменных окружения будет выглядеть следующим образом:


spring_test_app:
image: spring_test_app:latest
build:
context: .
dockerfile: docker/Dockerfile
args:
DOCKER_BUILDKIT: 1
restart: "no"

# задаём конкретные значения тем самым переменным окружения
environment:
POSTGRES_HOST: postgres:5432
POSTGRES_DB_NAME: test_stand_db
POSTGRES_USERNAME: admin
POSTGRES_PASSWORD: admin
ports:
- "8080:8080"


В этом примере переменные из application.properties переопределяются через переменные окружения при запуске Docker контейнера.

Переопределение свойств напрямую

Но на самом деле, можно обойтись без дополнительных переменных в application.properties, переопределив Spring-свойства напрямую.

Теперь application.properties выглядит следующим образом:


spring.datasource.url=jdbc:postgresql://localhost:5432/local_dev_db
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=org.postgresql.Driver


А код сервиса нашего приложения в Docker Compose следующим образом:


spring_test_app:
image: spring_test_app:latest
build:
context: .
dockerfile: docker/Dockerfile
args:
DOCKER_BUILDKIT: 1
restart: "no"
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres/test_stand_db
SPRING_DATASOURCE_USERNAME: admin
SPRING_DATASOURCE_PASSWORD: admin
ports:
- "8080:8080"


Для spring.datasource.url, spring.datasource.username и spring.datasource.password будут использованы те значения, которые мы указали в Docker Compose файле.

За счёт чего это становится возможным?

Spring Boot использует определенный порядок загрузки свойств приложения, чтобы обеспечить разумное переопределение значений. Переменные окружения загружаются позже и перезаписывают свойства, заданные в application.properties. Полный порядок загрузки можно найти в документации.

Relaxed Binding в Spring Boot

Кстати, обратите внимание на стиль написания названий свойств. Spring Boot использует концепцию Relaxed Binding, которая позволяет указать название свойства без полного совпадения. Например:


@ConfigurationProperties(prefix = "my.main-project.person")
class MyPersonProperties {
var firstName: String? = null
}


Для этого класса можно использовать следующие стили именования свойств:

- my.main-project.person.first-name — Kebab стиль для .properties/.yaml файлов
- my.main-project.person.firstName — CamelCase стиль
- my.main-project.person.first_name — Underscore стиль
- MY_MAINPROJECT_PERSON_FIRSTNAME — Uppercase + Underscore стиль для переменных окружения. При использовании Uppercase + Underscore стиля следует учитывать, что многие операционные системы ограничивают имена переменных окружения. Например, в Linux переменные могут содержать только буквы (a-z, A-Z), цифры (0-9) и символ подчеркивания (_). Подробнее читайте в документации.

В приведённом выше примере с Docker Compose файлом мы как раз воспользовались Uppercase + Underscore стилем, чтобы указать значения для нужных нам свойств. Именно такой вариант именования переменных окружения является негласным для Linux.

Ставь 🔥 если знал про это и 🤔 если слышишь впервые)

#SpringBoot #SpringTips
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥37🤔24👍121
👩‍💻 Генерация HTTP клиентов для Spring Boot приложения по OpenAPI спецификации

В новом переводе от команды Spring АйО вы узнаете, как можно сгенерировать код HTTP клиентов для Spring Boot приложения по OpenAPI спецификации, используя плагин openapi-generator для Gradle.

В статье вы найдете:

💡 Пошаговую инструкцию по использованию openapi-generator для Gradle
⚙️ Настройки для генератора, которые помогут оставить только нужный код
🍃 Пример конфигурации сгенерированных Spring-бинов

📚 Подробнее читайте на Хабре
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍104🤔1
😲 Awesome System Design

Нашли интересный репозиторий (больше 10к звезд на GitHub!) с материалами по системному проектированию:

– 18 статей по ключевым концепциям проектирования систем
– 26 статей по основным блокам проектирования систем
– Разбор 50 задач по проектированию на YouTube, разбитых по уровню сложности
– Ответы на вопросы по проектированию системы на интервью
– Ссылки на статьи, книги и каналы YouTube

🔗 https://github.com/ashishps1/awesome-system-design-resources

Сохраняйте, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥35👍144
🗓 Еженедельный дайджест №7

Для тех, кто был слишком занят на неделе или просто пропустил некоторые посты, публикуем дайджест!

Кастомные валидаторы в Spring Boot: Как сделать валидацию под себявспомнили основные нюансы реализации собственных аннотаций и валидаторов

Soft Assertions в AssertJ – Михаил Поливаха (эксперт сообщества Spring АйО) объяснил, как и в каких ситуации стоит использовать soft assertions

Spring Boot Tips: Переопределение свойств через переменные окруженияузнали, как переопределять свойства через переменные окружения без их явного указания в application.properties

Генерация HTTP клиентов для Spring Boot приложения по OpenAPI спецификациивыяснили, как можно сгенерировать код HTTP-клиентов и доработать его при необходимости

Awesome System Designнашли отличный репозиторий с материалами по системному дизайну на GitHub

😌@spring_aio
Please open Telegram to view this post
VIEW IN TELEGRAM
👍95🔥5
⚡️ Вышел Hibernate 7.0.0.Beta1!

Основное, на что стоит обратить внимание:

* Переход на Jakarta Persistence версии 3.2
* Более строгая проверка доменной модели
* Новая схема mapping.xsd c расширенными возможностями маппинга
* Переход на Hibernate Models с Hibernate Commons Annotations (HCANN)

📚 Подробнее читайте на Хабре

#spring_news #hibernate
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍7🤯2
🔥 Состояние Spring в 2024 году

Команда Spring АйО перевела важнейший документ для Spring-разработчиков!

В начале июня компания VMWare, владеющая Spring, опубликовала результаты исследования, в котором приняло учатие более 1,500 разработчиков по всему миру. Отчёт получился действительно интересным и всеобъемлющим. Были рассмотрены как базовые темы, такие как выбор архитектурных подходов и типов API, так и продвинутые, такие как компиляция в Native Image и использование Spring вместе с Kubernetes.

Обязательно к прочтению: https://habr.com/ru/companies/spring_aio/articles/834050/

Сохраняй, делись с друзьями и оставляй своё мнение касаемо результатов этого исследования в комментариях!

😌@spring_aio
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥94🤯31
Spring Tips: Рекурсивные запросы в Hibernate

Рекурсивные запросы в SQL очень полезны при работе с иерархическими или графовыми структурами данных. Конструкция WITH, введенная в SQL:1999, позволяет задавать Common Table Expressions (CTE), которые представляют собой именованные подзапросы. CTE упрощают сложные запросы, улучшают их читаемость и, что самое важное, позволяют нам реализовать рекурсию.

Рассмотрим таблицу, которая хранит информацию о сотрудниках и их менеджерах:


CREATE TABLE employees (
employee_id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
employee_name VARCHAR(255),
manager_id INTEGER,
CONSTRAINT pk_employees PRIMARY KEY (employee_id)
);

ALTER TABLE employees ADD CONSTRAINT
FK_EMPLOYEES_ON_MANAGER FOREIGN KEY (manager_id)
REFERENCES employees (employee_id);


Эта таблица представляет собой список сотрудников, где у каждого сотрудника есть уникальный идентификатор (employee_id), имя (employee_name) и ссылка на менеджера (manager_id). Поле manager_id является внешним ключом, ссылающимся на employee_id в той же таблице, что позволяет создать иерархическую структуру, где один сотрудник может быть менеджером для других.

Предположим, что нам нужно выбрать всех подчиненных определенного менеджера. Для решения этой задачи мы можем использовать рекурсивный SQL запрос:


WITH RECURSIVE EmployeeHierarchy AS (
-- Базовый случай: начнем с верхнего уровня менеджера
SELECT employee_id, employee_name, manager_id
FROM employees
WHERE manager_id = :id

UNION ALL

-- Рекурсивный случай: найдем всех сотрудников, подчиненных найденным ранее сотрудникам
SELECT e.employee_id, e.employee_name, e.manager_id
FROM employees e
INNER JOIN EmployeeHierarchy eh ON e.manager_id = eh.employee_id
)

SELECT *
FROM EmployeeHierarchy;


До выхода версии Hibernate 6.2, для выполнения подобных запросов приходилось использовать nativeQuery. Пример с использованием entityManager выглядит следующим образом:


var sql = {SQL-запрос, представленный выше};

var employees = entityManager.createNativeQuery(sql, Employee.class)
.setParameter("id", 1)
.getResultList();


Либо так, если используется Spring Data JPA:


public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query(value = "{SQL-запрос, представленный выше}", nativeQuery = true)
List<Employee> findAllEmployeesByManagerIdSQL(@Param("id") Integer id);
}

List<Employee> employees = employeeRepository.findAllEmployeesByManagerIdSQL(1);


С выходом Hibernate 6.2, появилась возможность писать рекурсивные запросы, используя HQL. Запрос, представленный выше, теперь можно написать так:


String jpql = """
WITH EmployeeHierarchy AS (
SELECT e.employeeId AS id, e.employeeName AS name, e.manager AS mgr
FROM Employee e
WHERE e.manager.id = :id

UNION ALL

SELECT e.employeeId, e.employeeName, e.manager.id
FROM Employee e
JOIN EmployeeHierarchy eh ON e.manager.id = eh.id
)
SELECT new Employee(
eh.id,
eh.name,
eh.mgr
)
FROM EmployeeHierarchy eh
""";

var employees = entityManager.createQuery(jpql, Employee.class)
.setParameter("id", 1)
.getResultList();


А также со Spring Data JPA:


public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query(value = "{JPQL-запрос, представленный выше}")
List<Employee> findAllEmployeesByManagerIdJPQL(@Param("id") Integer id);
}

List<Employee> employees = employeeRepository.findAllEmployeesByManagerIdJPQL(1);


Как можно заметить, синтаксис HQL и SQL запросов довольно сильно похож. Но есть некоторые различия:

* В отличие от стандартного SQL, в Hibernate нет необходимости использовать ключевое слово RECURSIVE
* В Hibernate имена атрибутов CTE задаются через псевдонимы в выражении SELECT. Другими словами, в заголовке CTE имена не указываются.

#SpringTips #Hiberante #CTE
Please open Telegram to view this post
VIEW IN TELEGRAM
👍285🔥4
👸 The Mother Of All Demo Apps

Когда вы изучаете новую технологию, наличие хорошего примера может значительно облегчить процесс. Представляем полезный ресурс под названием RealWorld или, как, говорят сами его разработчики, - The Mother Of All Demo Apps.

RealWorld - это сервис, на котором собраны проекты с различным стеком, которые, благодаря спеке, должны предоствлять один и тот же API.

Команда Spring АйО выбрала из всего списка самые свежие проекты на Spring Boot с актуальным стеком:

- Spring Boot
- Spring Boot + GraalVM + Spring Data JPA + Spring Security
- Spring Boot + MyBatis
- Spring Boot + Spring Data JPA
- Spring Boot + Spring Data JPA + openapi-generator
- Spring Boot + Spring Data JPA + PostgreSQL
- Spring Boot + Spring Data JPA + Spring Security
- Spring Boot + Spring Security + jOOQ
- Spring Boot + WebFlux + MongoDB
- Spring Boot + WebFlux + RouterFunction + Spock
- Spring Data Couchbase + Spring Boot + Couchbase

Сохраняйте, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥34👍115👎1