Spring АйО
8.45K subscribers
305 photos
216 videos
406 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 Framework центральное место занимает Bean. В своем видео Джош Лонг рассказывает об истории Bean и его жизненном цикле.

#SpringTips #SpringBoot

📱 https://www.youtube.com/watch?v=Z5hxolai4Tk

Подписывайтесь:
😌@spring_aio
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3👏2
🕐 Тонкое управление Scheduled задачами в Spring

Какими способами можно настроить время и условие запуска Scheduled задач в Spring?

Первый способ - через @Profile над сервисом, в котором объявлена задача, чтобы указать профили, в которых она должна (или не должна) запускаться.


java
@Profile("test,!prod")
class Teapot {
@Scheduled(cron = "0 15 10 15 * ?")
void makeTea() {
log.info("I'am a teapot.");
}
}


Но в таком варианте, мы управляем только условием запуска, но не можем настроить переодичность.

Другой вариант, это объявление cron expression в пропертях:


#application-test.properties
teapot.make_tea.cron=0 15 10 15 * ?



@Scheduled(cron = "${teapot.make_tea.cron}")
void makeTea() {
log.info("I'am a teapot.");
}


Но как тогда в таком случае отключить джобу? В качестве cron expression можно использовать дефис(-), что означает, что джобу запускать не нужно вовсе. И тогда мы обходимся без явного перечисления профилей в @Profile.


#application-prod.properties
teapot.make_tea.cron=-


Такой подход особо полезен при использовании spring-cloud-config, тогда нет необходимости делать передеплой приложения, чтобы выключить, или донастроить джобу. Нужно только не забыть повесить @RefreshScope на класс.

#SpringBoot #SpringTips
👍10👌5🔥3
🔧 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
👍235👀3👎2😴2