Spring АйО
7.67K subscribers
262 photos
152 videos
338 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
🎉 Встречайте нашу дебютную статью на Habr!

👩‍💻 Блеск и нищета нового Scrolling API в Spring Data

В статье мы разобрали новое Scrolling API, которое предназначено для эффективной пагинации. В частности, Scrolling API приносит KeySet пагинацию в Spring Data, которая в теории может быть сильно быстрее стандратной и всем известной offset пагинации.

Однако, в процессе исследования выяснилось, что с PostgreSQL новое API работает не совсем так, как ожидается. А ведь это одна из самых популярных СУБД в мире!

Заинтриговали? Переходите по ссылке, оставляйте комментарии, и, конечно, ждем ваших лайков)

🔗 https://habr.com/ru/companies/spring_aio/articles/819193/

#SpringBoot #SpringData

Подписывайтесь:
😌@spring_aio
Please open Telegram to view this post
VIEW IN TELEGRAM
🌟 Статическая и динамическая конфигурация в Spring Boot: что выбрать?

В мире облачных сервисов правильная настройка конфигурации играет ключевую роль. В этой статье рассматриваются два подхода: статическая и динамическая конфигурация.

🔧 Статическая конфигурация удобна предсказуемостью и простотой развертывания. Пример на Spring Boot:


@Value("${myapp.staticValue}")
private String staticValue;

public void printStaticValue() {
System.out.println(staticValue);
}


🔄 Динамическая конфигурация обеспечивает гибкость и адаптивность. Например, для изменения конфигураций во время выполнения приложения можно использовать Spring Cloud:


@RefreshScope
@RestController
public class MessageRestController {

@Value("${message:Hello default}")
private String message;

@GetMapping("/message")
public String getMessage() {
return this.message;
}
}


Spring Cloud предоставляет возможность создания config сервера, который может подгружать новые конфигурации из Git. Ознакомьтесь с полной статьей для более детального погружения и примеров кода!

📚 Читать далее

#SpringBoot #SpringCloud
EqualsVerifier отмечает 15-летие 🥳

Переопределение методов equals() и hashCode() – непростая задача. Они должны соответствовать не только требованиям Java, но и используемому стеку технологий (например, JPA).

Библиотека EqualsVerifier помогает разработчикам проверить корректность переопределенных методов уже 15 лет.

Jan Ouwens, создатель библиотеки, делится своим опытом и планами в новой статье.

Узнайте, какие проблемы решались разработчиком по мере развития Java, что было популярно до GitHub, и какие планы у Jan на будущее: https://jqno.nl/post/2024/06/01/looking-back-on-15-years-of-equalsverifier/

Подписывайтесь:
😌@spring_aio
Please open Telegram to view this post
VIEW IN TELEGRAM
👩‍💻 Java-рантаймы с точки зрения Spring Boot 👩‍💻

На первый взгляд, выбор правильного Java-рантайма для вашего проекта на Spring Boot может показаться тривиальным. В конце концов, все популярные рантаймы основываются на коде OpenJDK и предлагают одинаковые программные интерфейсы.

Но не все рантаймы реализованы одинаково. В этой статье мы обсудим различные показатели, которые могут повлиять на ваше решение выбрать определенный дистрибутив Java для Spring Boot приложения.

🔗 https://habr.com/ru/companies/spring_aio/articles/819899/

#JVM #Java #SpringBoot
Please open Telegram to view this post
VIEW IN TELEGRAM
🐢 Неожиданное падение производительности при переходе на Spring Boot 3.3.0 👩‍💻

Hibernate подложил небольшую свинью, конвертируя JPQL в SQL. Внезапно, запрос поиска записей по списку id с передачей пустого списка деградирует в table full scan.

Однако, Hibernate пофиксил баг в течении 10 часов после поста в запрещенную в РФ соцсеть. Осталось дождаться новой версии Spring Boot, которая включит себе этот фикс.

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

#SpringBoot #Hibernate #BreakingNews
Please open Telegram to view this post
VIEW IN TELEGRAM
🎙 Spring АйО Чат!

Друзья, напоминаем, что у нас есть чат (@spring_aio_chat), в котором вы можете:

💬 Делиться фидбеком о публикуемых материалах;
Задавать вопросы, связанные со Spring и сопутствующими технологиями;
😼 Отвечать на вопросы, если Вы знаете на них ответ.
Please open Telegram to view this post
VIEW IN TELEGRAM
Неблокирующие сервисы вчера: WebFlux, Coroutines и Loom.
"Неблокирующие сервисы" сегодня: DockerHub, IntelliJ IDEA Ultimate, Slack и другие.
#программисты_шутят
Dynamic Projection в Spring Data JPA

Используя Spring Data, довольно часто могут возникать накладные расходы из-за получения из базы слишком большого количества полей. Чтобы решить эту проблему, мы можем объявлять методы с нативными запросами, DTO или проекциями для случаев, когда необходимо ограничить количество выбираемых полей. Но такой подход приводит к появлению множества очень похожих методов в репозитории. Например:


public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name); // выбираем из базы сущность со всеми её полями

List<ProductProjection> findPrjsByName(String name); //выбираем из базы ограниченный набор полей, указанный в некоторой проекции

List<ProductDto> findDtosByName(String name); //выбираем из базы ограниченный набор полей, указанный в некоторой DTO
}


Чтобы решить эту проблему можно прибегнуть к использованию Dynamic Projection:


public interface ProductRepository extends JpaRepository<Product, Long> {
<T> List<T> findByName(String name, Class<T> type);
}


Подробнее о сценариях использования и компромиссах, на которые придется пойти используя Dynamic Projection, читайте в следующей статье: https://maciejwalkowiak.com/blog/spring-data-jpa-dynamic-projections/
Мы рады сообщить, что наше сообщество начинает обрастать экспертами, и мы будем знакомить вас с их мнением. Встречайте, Михаил Поливаха, коммитер Spring Data JDBC (Relational), не удержался от комментария по вопросу поддержки проекций в разных модулях Spring Data. Ниже прямая речь Михаила.

Надо сказать, что projection-ы, как функциональность, должна быть доступна во всех модулях spring-data. Вопрос в том, что еще не все модули ее поддержку реализовали до конца.
Наивный читатель мог бы предположить, что поскольку в spring-data-jdbc есть поддержка как interface based projection-ов, так и dynamic projection-ов, то вот это заработает:


public interface MyEntityRepository extends CrudRepository<MyEntity, Long> {

<T> Optional<T> findProjectionByStatus(String status, Class<T> clazz);
}

@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Accessors(chain = true)
@Table
public class MyEntity {

@Id
@EqualsAndHashCode.Include
private Long id;

private String status;

@CreatedDate
private Instant createdAt;
}

interface MyEntityInterfaceProjection {
String status();

Long id();
}

@Test
void whenDynamicProjectsAreInUseViaInterfaces_thenBlast() {
saveInitialEntity();
Optional<MyEntityInterfaceProjection> active = myEntityRepository.findProjectionByStatus("active", MyEntityInterfaceProjection.class);

Assertions.assertThat(active)
.isPresent()
.hasValueSatisfying(myEntityProjection -> {
Assertions.assertThat(myEntityProjection.id() != null && myEntityProjection.status().equalsIgnoreCase("active")).isTrue();
});
}

@NotNull
private MyEntity saveInitialEntity() {
MyEntity myEntity = new MyEntity();
myEntity.setStatus("active");
return myEntityRepository.save(myEntity);
}


Но данный код сгенерит ошибку глубоко в недрах JdbcQueryCreator-a:


java.lang.IllegalStateException: SELECT does not declare a select list
at org.springframework.data.relational.core.sql.SelectValidator.doValidate(SelectValidator.java:57)
at org.springframework.data.relational.core.sql.SelectValidator.validate(SelectValidator.java:49)
at org.springframework.data.relational.core.sql.DefaultSelectBuilder.build(DefaultSelectBuilder.java:207)
at org.springframework.data.jdbc.repository.query.JdbcQueryCreator.complete(JdbcQueryCreator.java:173)
at org.springframework.data.jdbc.repository.query.JdbcQueryCreator.complete(JdbcQueryCreator.java:66)


Связано это с тем, что на данный момент spring-data-jdbc просто не умеет переваривать динамические проджекшены для инфтерфейсов 🙂
Про это мы знаем, бага на это дело пока нет, если он кому-либо важен - можем завести. Хочу также напомнить, что если есть какие-либо инициативы для нововведений в spring-data-jdbc - можно оставлять в комментариях или писать мне в ЛС.
⚠️ Уязвимость в плагине JetBrains GitHub

Если вы используете плагин GitHub в IntelliJ IDEA или других продуктах JetBrains, советуем обновиться до последней версии и отозвать токены созданные IDEA в своем GitHub аккаунте.

Подробности в статье.

🔗 https://habr.com/ru/companies/spring_aio/articles/820819/
🔧 Spring Data findAll антипаттерн

Spring Data Repository отличная концепция, позволяющая нам абстрагироваться от CRUD операций над domain entity. Достаточно объявить пустой интерфейс и унаследовать его, например, от ListCrudRepository или JpaRepository, если мы работем с JPA.


public interface OwnerRepository extends JpaRepository<Owner, Long> {
}


После этого нам сразу будут доступны основные методы работы с entity - save, update, findById, findAllById, findAll, и т.д. Но некоторые из этих методов могут привести к серъезным проблемам с производительностью и памятью, например метод findAll(). Давайте представим, что нам нужно найти всех Owner у которых есть животные c определенным именем и отсортировать по имени владельца. Поскольку мы находимся всего в одном шаге от вызова findAll() метода для «решения» этой проблемы, не пройдет много времени, пока кто-нибудь не предложит следующее решение:



public List<Owner> findOwnerByPetName(Collection<String> petNames) {
return ownerRepository.findAll()
.stream()
.filter(owner -> owner.getPets()
.stream()
.map(Pet::getName)
.anyMatch(petNames::contains)
)
.sorted(Comparator.comparing(Owner::getFirstName))
.toList();
}


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


//derived method
List<Owner> findByPets_NameInOrderByFirstNameAsc(Collection<String> petNames);

//JPA query method
@Query("select o from Owner o left join o.pets pets where pets.name in ?1 order by o.firstName")
List<Owner> findOwnerByPetName(Collection<String> petNames);



Если у нас в репозитории есть метод findAll(), мы должны понимать что рано или поздно, по мере роста команды, им может кто-то воспользоваться. Возможно следует определять базовый интерфейс репозитория вашем проекте самостоятельно и наследовать его от org.springframework.data.repository.Repository и подконтрольно наполнять его методами.

#SpringData #SpringTips
🕓 Hibernate и спецификация JPA: приключение на 20 минут 24 часа

На прошлой неделе у нас был пост про внезапное падение производительности в Hibernate 6.5 на достаточно простом запросе. А сегодня вы можете прочитать историю этой проблемы от лица Гевина Кинга, создателя Hibernate.

Гевин Кинг рассказал, как возник этот баг, и как он повлиял на спецификацию JPA 3.2.

📚 Подробней читайте на Хабре
This media is not supported in your browser
VIEW IN TELEGRAM
По умолчанию в IntelliJ IDEA работают следующие комбинации клавиш:

1) ⌥ + ← (CTRL + ←) – передвинуть каретку к началу слова
2) ⌥ + → (CTRL + →) – передвинуть каретку к концу слова
3) ⇧ + ⌥ + ← (⇧ + CTRL + ←) – выделить слово до его начала
4) ⇧ + ⌥ + → (⇧ + CTRL + →) – выделить слово до его конца
5) ⌥ + ⌫ (CTRL + ⌫) – удалить слово с текущей позиции каретки и до его начала

Но мало кто знает, что эти шорткаты можно сделать еще удобнее!

Настройте их же для режима CamelHumps и IntelliJ IDEA начнёт понимать слова написанные в camelCase!

#IntelliJIDEA #Tooling #HotKeys
Разработчики Каркаса Весеннего Ботинка утверждают, что эти фразы имеют смысл:

- "У меня не применяется совет контроллера"
- "Тебе нужно выстрелить событием"
- "Я сделал этот боб главным, чтобы мои анализы не провалились"

My controller advice did not apply
You need to fire an event
I made this bean primary in order to not to fail my tests


Они держат нас за дураков?
Please open Telegram to view this post
VIEW IN TELEGRAM
👩‍💻 Spring Boot 3.2: замените свой RestTemplate на RestClient

В мире Spring Boot отправка HTTP запросов к внешним сервисам является весьма распространенной задачей. Традиционно при достижении этой цели разработчики полагались на RestTemplate. Однако, по мере развития Spring Framework, на свет появился новый и более мощный способ обработки HTTP запросов: так называемый WebClient. Spring Boot 3.2 представил нам надстройку над WebClient, которая получила название RestClient.

RestClient предлагает нам более современные и интуитивно понятные способы взаимодействия с RESTful сервисами.

📚 Подробности в статье
Please open Telegram to view this post
VIEW IN TELEGRAM
🌿Spring Framework – история проекта и его названия

Часто мы принимаем многие вещи на веру, не углубляясь в причину их происхождения.

Что же заставило Рода Джонсона (создателя Spring Framework), дать название «Spring» своему фреймворку? Если вы никогда об этом не думали, то эта статья из 2006 года именно для вас!

TL;DR: Название «Spring» было предложено в конце 2002 года и символизировало начало нового периода после «зимы» с традиционным J2EE.

🔗 https://spring.io/blog/2006/11/09/spring-framework-the-origins-of-a-project-and-a-name
Please open Telegram to view this post
VIEW IN TELEGRAM
🧭 Spring Boot Developer Roadmap

Roadmap для изучения Spring Boot: https://roadmap.sh/spring-boot. Сохраняйте, чтобы не потерять!

Как думаете, насколько важными являются перечисленные технологии в современных реалиях? И какими из них вы пользуетесь на своих проектах?

Будем рады обсуждению в комментариях!

😌 Подписывайтесь на канал: @spring_aio
💬 Вступайте в чат: @spring_aio_chat
Please open Telegram to view this post
VIEW IN TELEGRAM
Новый компилятор K2 в Kotlin. Часть 1

В новой статье эксперт сообщества Spring АйОМихаил Поливаха рассмотрит новый компилятор К2 для Kotlin. Сначала он расскажет о том, какие проблемы K2 призван решить, а затем о других минорных улучшениях, которые были сделаны. Гайд по обновлению на новую версию будет опубликован в следующей части этой статьи.

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