Для тех, кто был слишком занят на неделе или просто пропустил некоторые посты, публикуем дайджест!
- Внедряем Jakarta Data в Spring приложение. Обсуждение в комментариях получилось горячим!
- Spring Boot 3.2: замените RestTemplate на RestClient. Кратко объяснили, что такое RestClient и зачем он нужен.
- Spring Framework – история проекта и его названия. Нашли ответ на важный вопрос: "Почему же Spring?" в статье от 2006 года.
- Spring Boot Developer Roadmap. Обсудили, какие технологии должен знать современный Spring Boot разработчик.
- Новый компилятор K2 в Kotlin. Часть 1. Разобрали, чем может похвастаться обновленный компилятор в Kotlin.
И главное, нас уже больше 1000! Спасибо, что вы с нами
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥33👍13❤5👏1
Spring предлагает различные инструменты для тестирования контроллеров:
MockMvc, WebTestClient и TestRestTemplate. И пусть все они служат одной цели (вызову HTTP-эндпоинтов и проверке ответа), между ними есть некоторые различия. Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤4🔥3
Несмотря на то, что данная статья была опубликована более полугода назад, команда Spring АйО по-прежнему считает ее актуальной, важной и интересной.
Себастьян Делюз, контрибьютор Spring Framework, делится обзором усилий команды Spring по оптимизации эффективности приложений во время выполнения. Он рассматривает Virtual Threads, GraalVM Native Image, Project CRaC, Project Leyden и всё это в контексте Spring!
P.S. Будем благодарны за лайки. Конечно же, если перевод статьи вам понравится 💚
Please open Telegram to view this post
VIEW IN TELEGRAM
👍30🔥6 3❤2👏1
Одной из главных причин популярности Spring Boot является его способность автоматически конфигурировать (auto-configuration) множество компонентов, существенно упрощая жизнь разработчикам. Однако иногда возникает необходимость слегка подправить настройки этих компонентов без отказа от всех преимуществ автоматической конфигурации.
Предположим, вам нужно кастомизировать настройки кэша в вашем приложении. Вместо того чтобы полностью переопределять CacheManager, вы можете использовать Customizer интерфейс, чтобы внести необходимые изменения:
@Bean
CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return cacheManager -> cacheManager.setAllowNullValues(false);
}
Аналогичным образом можно настроить и любые другие компоненты:
//Кастомизация свойств Hibernate
@Bean
HibernatePropertiesCustomizer hibernatePropertiesCustomizer() {
return properties -> properties.put("hibernate.integrator_provider",
(IntegratorProvider) () -> List.of(new BeanValidationIntegrator()));
}
//Кастомизация Jackson2ObjectMapperBuilderCustomizer
@Bean
Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
builder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
builder.featuresToEnable(
SerializationFeature.WRITE_ENUMS_USING_TO_STRING,
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
};
}
Но бывает и такое, что подходящего Customizer интерфейса просто нет. В таком случае, можно использовать BeanPostProcessor для кастомизации уже инициализированных бинов:
//Кастомизация springLiquibase бина
@Bean
BeanPostProcessor liquibaseBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof SpringLiquibase springLiquibase) {
springLiquibase.setContexts("my-context");
}
return bean;
}
};
}
#SpringBoot #SpringTips
Please open Telegram to view this post
VIEW IN TELEGRAM
👍38🔥9 9
В новом переводе от команды Spring АйО, Siva Katamreddy, девелопер адвокат в AtomicJar (Testcontainers), поделился своими мыслями о популярных в наши дни TDD, Clean, Hexagonal, Onion и Ports & Adapters. Он также постарался ответить на вопрос, который, возможно, волнует не только его: "Действительно ли мы, разработчики, так любим всё усложнять?".
Если сложных задач нет, что нам в таком случае делать? Мы делаем простые вещи сложными и затем решаем сложные проблемы. Не так ли? Мы, разработчики, любим сложность, по крайней мере в начале своей карьеры.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥6 5🤔2🤯1
Более миллиона раз разработчики обращались к вопросу на StackOverflow о том, как получить значение из
application.properties. Возможно, вы удивитесь @Value – это не единственный способ. И далеко не всегда самый удобный.Способ №1: @Value
Аннотация
@Value используется для инъекции отдельных значений из файла конфигурации. Например:
@Value("${property.name}")
private String propertyName;
Пожалуй, самый простой, но не самый поддерживаемый вариант, из-за отсутствия группировки и большого количества дублирующего кода, когда значений, с которыми надо работать, становится довольного много.
Способ №2: @ConfigurationProperties
Аннотация
@ConfigurationProperties используется для группировки связанных свойств в объект класса. Свойства могут настраиваться через .properties и .yaml файлы, переменные окружения и т.д.Типичное использование
@ConfigurationProperties может выглядеть следующим образом:
@ConfigurationProperties(prefix = "app")
@Component
@Getter
@Setter
public class ApplicationProperties {
private String name;
}
@SpringBootTest(properties = "app.name=my-app")
class ApplicationPropertiesTest {
@Autowired
private ApplicationProperties applicationProperties;
@Test
void appName() {
var appName = applicationProperties.getName();
assertEquals("my-app", appName);
}
}
Да, нужно будет создать отдельный класс, зато преимуществ у этого подхода относительно
@Value довольно много. Перечислим некоторые из них:– Группировка по префиксу
– Возможность иерархического представления свойств
– Это бин и этим всё сказано :)
–
@ConfigurationPropertiesBindingОтдельно отметим
@ConfigurationPropertiesBinding. Допустим, нам нужно добавить новое свойство version, которое будет представлять класс Version для обработки семантического версионирования (major.minor.patch).
@ConfigurationProperties(prefix = "app")
@Component
@Getter
@Setter
public class ApplicationProperties {
private String name;
private Version version;
}
Для преобразования строкового значения из конфигурации в объект класса
Version нам потребуется конвертор, который как раз будет отмечен аннотацией @ConfigurationPropertiesBinding:
@ConfigurationPropertiesBinding
@Component
class SemVerPropertyConverter implements Converter<String, Version> {
@Override
public Version convert(String source) {
return StringUtils.hasLength(source) ? Version.parse(source) : null;
}
}
Пример использования:
@SpringBootTest(properties = {
"app.name=my-app",
"app.version=1.1.0"
})
class ApplicationPropertiesTest {
@Autowired
private ApplicationProperties applicationProperties;
@Test
void appVersion() {
Version version = applicationProperties.getVersion();
assertEquals(1, version.getMajorVersion());
assertEquals(1, version.getMinorVersion());
assertEquals(0, version.getPatchVersion());
}
}
Подробнее про
@ConfigurationProperties и @ConfigurationPropertiesBinding вы можете прочитать в документации.Способ №3: Environment
А если вы хотите обойтись без специальных аннотаций, можно использовать
Environment:
@Autowired
private Environment env;
public void someMethod() {
String property = env.getProperty("property.name");
}
#SpringBoot #SpringTips
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥9 7🤔1🤯1
Для тех, кто был слишком занят на неделе или просто пропустил некоторые посты, публикуем дайджест!
– Тестирование HTTP-эндпоинтов: MockMvc vs. WebTestClient vs. TestRestTemplate. Похолеварили в комментариях на тему постоянных изменений в Spring Framework.
– Эффективность Spring-приложений в рантайме. Текущее состояние дел и планы на будущее. Узнали, как обстоят дела с развитием Virtual Threads, GraalVM Native Image, Project CRaC, Project Leyden в контексте Spring.
– Spring Boot Tip: Customizer интерфейсы для кастомизации бинов. Рассказали, как можно безболезнено "подкрутить" автоконфигурацию в Spring Boot.
– Разработка ПО действительно так сложна? Или это мы делаем ее такой? Таких жарких споров в комментариях на Хабр мы давно не видели.
– Spring Boot Tips: работаем со свойствами. Освежили в памяти способы работы со свойствами, их преимущества и недостатки.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥6 4
Docker Compose предлагает несколько способов управления запуском сервисов. Один из вариантов — создать множество
compose.yaml файлов. Главный файл будет содержать все возможные сервисы приложения и его окружения, а другие файлы — импортировать сервисы из основного.Однако у такого подхода есть недостатки. Во-первых, сложно получить целостное представление о приложении. Во-вторых, создание и поддержка большого количества
compose.yaml файлов может быть трудоемкой задачей, особенно если ваша IDE не поддерживает их удобное редактирование.Решением этой проблемы в Docker Compose являются профили. Этот подход знаком многим разработчикам, работающим со Spring. Профили позволяют гибко управлять запуском сервисов в зависимости от окружения.
Подробнее о Docker Compose профилях можно прочитать в статье (en): https://event-driven.io/en/docker_compose_profiles/
#Docker #DockerCompose
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥5❤1⚡1
Неожиданный поворот в поддержке String Templates в JDK 23. Команда Java решила отказаться от функциональности, которая есть в большинстве современных языках программирования. Почему так произошло? Кажется, из-за слишком большой гибкости, которую заложили на ранних этапах разработки, а также, нежелания просто сделать “синтаксический сахар” для строковой интерполяции. А чего же хотели разработчики на самом деле? Нам кажется, что все-таки - последнего.
Мы представляем вам перевод почтовой переписки Гэвина Бирмана и Брайана Гоеца, в которой решилась судьба String Templates.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤5🔥4
На прошлой неделе Сбер (а точнее СберТех) представил линейку своих IDE - GigaIDE, которая включает две версии - Cloud и Desktop.
Cloud версия сделана поверх VS Code, по всей видимости, интегрирована с их относительно новым продуктом GitVerse.
Desktop версия является сборкой IntelliJ IDEA Community, благо последняя является open source продуктом, в которую было добавлено большое количество плагинов, включая AI ассистент от Сбера - GigaCode.
Но выход линейки IDE был сопряжен небольшим скандалом и перебранкой между сотрудниками Сбер и JetBrains.
Пока нет официальных комментариев с обеих сторон, читайте подробности в нашем блоге на Хабре: https://habr.com/ru/companies/spring_aio/news/826164/
#breaking_news #ide #jetbrains #sber
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
GigaIDE — новая IDE от Сбера
На прошлой неделе Сбер (а точнее СберТех) представил линейку своих IDE - GigaIDE, которая включает две версии - Cloud и Desktop. Cloud версия сделана поверх VS Code, по всей видимости, интегрирована с...
👎17👍15❤6😁5🔥3🤔2
Автоматизированное тестирование Spring-приложений стало неотъемлимой частью разработки. Единственный выбор, с котором сегодня сталкиваются разработчики: сначала писать тесты или функциональность?
А в ситуации, когда тесты становятся обязательными, возникает вопрос: насколько они хороши?
Филип Рикс собрал лучшие практики тестирования в одной статье, объясняя их важность и рассказывая почему стоит им следовать (en): https://rieckpil.de/spring-boot-testing-best-practices/
Please open Telegram to view this post
VIEW IN TELEGRAM
rieckpil
Spring Boot Testing Best Practices - rieckpil
Learn about the top five Spring Boot testing best practices to build and maintain Spring Boot applications more confidently.
👍11❤7🔥3
Встречайте вторую часть статьи "Новый компилятор K2 в Kotlin" от эксперта сообщества Spring АйО – Михаила Поливахи!
В первой части Михаил рассказал про компилятор К2 в общем, а во второй части сфокусировался только на процедуре миграции.
📚 Подробней читайте на Хабре
P.S. Будем благодарны за лайки на статье на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤3🔥3
Spring разработчики часто используют Markdown для написания документации к своим приложениям. В IntelliJ IDEA есть удобный плагин для работы с Markdown файлами, который предоставляет специальный редактор с подсветкой, автокомплитом и форматированием. Он также позволяет просматривать документацию в реальном времени.
Кроме стандартной функциональности в IntelliJ IDEA есть пара уникальных фич, которые редакция Spring АйО хотела бы выделить особенно.
📚 Интересно? Читайте продолжение на Хабре
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥3😁2❤1
Джеймс Гослинг — канадский программист и инженер, создавший Java в начале 90-х годов. Его цель была ясна: создать язык, позволяющий писать программы, независимые от платформы. Так появился лозунг "Write Once, Run Anywhere", который революционизировал разработку ПО, позволяя Java-приложениям работать на любых устройствах с поддержкой JVM.
Недавно Джеймс сообщил, что уходит на заслуженный отдых:
Я наконец-то вышел на пенсию. После долгих лет работы программистом, пришло время просто наслаждаться жизнью. Последние 7 лет в Amazon были отличными, несмотря на COVID-19 и производственные проблемы. У меня есть длинный список сайд-проектов, которые нужно завершить. Будет весело.
Мы, как Spring-разработчики, благодарим Джеймса. Без его новаторских идей и разработки Java, возможно, у нас не было бы нашего любимого фреймворка 💚
Please open Telegram to view this post
VIEW IN TELEGRAM
❤58👍13🔥8
Для тех, кто был слишком занят на неделе или просто пропустил некоторые посты, публикуем дайджест!
– Как управлять запуском различных сервисов в Docker Compose? Узнали, что профили есть не только в Spring!
– Почему String Templates не будет в Java 23? Получили хоть и не всеобъемлющий, но ответ на вопрос, почему String Templates были удалены из Java после нескольких итераций preview.
– GigaIDE — новая IDE от Сбера. Что тут говорить. Самая громкая новость последних дней. 200+ комментариев под постом на Хабре не дадут соврать.
– Тестирование Spring Boot приложений. Лучшие практики. Судя по комментариям, некоторые из перечисленных практик могли показаться очевидными, но услышать их хотя бы раз точно стоит.
– Новый компилятор K2 в Kotlin. Часть 2. Продолжили изучать новые возможности K2 в Kotlin вместе с Михаилом Поливахой.
– Markdown в IntelliJ IDEA как отдельный вид искусства. Рисуем диаграммы и вызываем bash команды. Рассказали, как можно использовать Markdown файлы в IntelliJ IDEA по максимуму.
– Знакомьтесь, James Gosling: Отец Java. А завершили неделю с одной стороны замечательной, с другой стороны немного грустной новостью про уход на пенсию Джеймса Гослинга.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥7❤5
Валидация данных – ключевой аспект любого приложения. В Spring она часто используется в параметрах методов
@RestController, например:
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping("/search")
public ResponseEntity<List<Product>> searchProducts(@RequestParam @NotNull @Size(min = 3, max = 50) String name,
@RequestParam @NotNull @Min(0) @Max(10000) Double price) {
// Логика поиска продуктов
List<Product> products = productService.search(name, price);
return new ResponseEntity<>(products, HttpStatus.OK);
}
}
Валидация в сервисном слое
Валидация помогает гарантировать, что данные, поступающие в приложение, соответствуют требованиям. Для валидации в сервисном слое нужно добавить аннотацию
@Validated над сервисом:
@Service
@Validated
public class EmailService {
public void send(@Email String email,
@Length(max = 10) String subject,
@NotBlank String body) {
// бизнес-логика
}
}
Теперь метод send вызовет ошибку, если данные не проходят валидацию:
emailService.send(
"i am not email",
"I am too loooooooooong",
""
);
jakarta.validation.ConstraintViolationException: send.body: must not be blank, send.email: must be a well-formed email address, send.subject: length must be between 0 and 10
...
Валидация DTO в методах сервиса
Чтобы не дублировать поля в разных методах, разработчики часто используют DTO. Аннотации валидации применимы и здесь:
public record EmailRequest(
@Email String email,
@Length(max = 10) String subject,
@NotBlank String body
) {
}
Но в этом случае помимо
@Validated над классом, нужно также не забыть добавить @Valid перед типом параметра в методе:
@Service
@Validated
public class EmailService {
public void sendBatch(
@Valid List<EmailRequest> requests
) {
// do work
}
}
Следующий код вызовет ошибку:
emailService.sendBatch(
List.of(
new EmailRequest("not email", "test", "Hello"),
new EmailRequest("alex@spring.aio", "I am too loooooooooong", "")
)
);
jakarta.validation.ConstraintViolationException: sendBatch.requests[1].subject: length must be between 0 and 10, sendBatch.requests[1].body: must not be blank, sendBatch.requests[0].email: must be a well-formed email address
Валидация элементов коллекций
Кстати, точно также можно валидировать и элементы коллекций, а также ключи и значения в Map:
@Service
@Validated
public class EmailService {
public void search(
Map<@NotBlank String, @NotBlank String> searchParams
) {
// do work
}
}
Следующий код вызовет ошибку:
searchService.search(Map.of("", ""));
jakarta.validation.ConstraintViolationException: search.searchParams<K>[].<map key>: must not be blank, search.searchParams[].<map value>: must not be blank
#SpringBoot #SpringTips #Validation
Please open Telegram to view this post
VIEW IN TELEGRAM
👍44🔥13❤2👌1
Forwarded from Java Developer
Благодаря этой статье вы узнаете, как подключить и настроить Liquibase в Spring Boot приложении, сгенерировать скрипты инициализации и миграции схемы БД, а также дополнить уже существующие changelog файлы новыми скриптами миграции.
Ссылка на статью — КЛИК
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍6👌4
В новом переводе от команды Spring АйО вы узнаете, как аннотация
@Transactional помогла решить проблему с утечкой соединений и обеспечила стабильность системы. Недавно мы обнаружили критическую проблему внутри слоя репозиториев в нашем микросервисном Spring приложении: неправильная обработка исключения приводила к неожиданным сбоям и нарушению работы сервиса во время тестирования производительности.
📚Подробнее читайте на Хабр: https://habr.com/ru/companies/spring_aio/articles/827642/
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍7❤2
Spring Data упрощает создание запросов, но стандартные методы не всегда подходят под конкретные задачи. В таких случаях мы можем создать собственные реализации методов репозиториев. Например, если мы хотим, чтобы запрос формировался динамически на основе фильтра и возвращал DTO с меньшим количеством полей, нам понадобится создать fragment interface и кастомный метод с собственной реализацией.
//Кастомный интерфейс
public interface CustomizedUserRepository {
List<UserDto> findAllUsers(UserFilter filter);
}
//Реализация нашего интерфейса, которая будет использоваться Spring'ом
public class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
private final EntityManager em;
public CustomizedUserRepositoryImpl(JpaContext jpaContext) {
em = jpaContext.getEntityManagerByManagedType(User.class);
}
//Реализация нашего метода
@Override
public List<UserDto> findAllUsers(UserFilter filter) {
var cb = em.getCriteriaBuilder();
var query = cb.createQuery(UserDto.class);
var root = query.from(User.class);
var emailPath = root.<String>get(User_.EMAIL);
var usernamePath = root.<String>get(User_.USERNAME);
query.multiselect(root.get(User_.ID), emailPath, usernamePath);
var predicates = new ArrayList<Predicate>();
var email = filter.email();
if (StringUtils.hasLength(email)) {
predicates.add(cb.like(cb.lower(emailPath), "%" + email.toLowerCase() + "%"));
}
var username = filter.username();
if (StringUtils.hasLength(username)) {
predicates.add(cb.like(cb.lower(usernamePath), "%" + username.toLowerCase() + "%"));
}
query.where(predicates.toArray(new Predicate[]{}));
return em.createQuery(query).getResultList();
}
}
//Использование кастомного интерфейса
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {}
Теперь при инжекции
UserRepository, кастомный метод будет доступен для вызова:
List<UserDto> users = userRepository.findAllUsers(new UserFilter("Maksim", null));
Важные замечания
1.
CustomizedUserRepositoryImpl — полноценный Spring-бин, поддерживающий инжекцию других бинов и специфическую функциональность (AOT, Lifecycle Callbacks и т.д.).2. Инжекция
UserRepository может привести к циклической зависимости. Чтобы избежать этого, его можно получить через ApplicationContext.getBean().3. Spring пытается автоматически обнаружить пользовательские fragment интерфейсы, если классы следуют соглашению об именовании с постфиксом
Impl. Модифицировать значение по умолчанию можно через атрибут аннотации @EnableJpaRepositories:
@EnableJpaRepositories(repositoryImplementationPostfix = "MyPostfix")
4. Репозитории могут включать несколько пользовательских реализаций, которые имеют более высокий приоритет, чем базовая реализация, что позволяет переопределять базовые методы. Например, создадим кастомный интерфейс и переопределим метод
save:
public interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
@Override
public <S extends T> S save(S entity) {
// наша кастомная реализация
}
}
Теперь, если мы объявим следующий репозиторий:
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {}
то при вызове метода
userRepository.save(user) будет использован метод из нашей реализации CustomizedSaveImpl. 5. В примерах выше мы рассматривали Spring Data JPA, но эта концепция поддерживается для всех модулей Spring Data (MongoDB, Redis, JDBC и т.д.).
Подробнее про реализацию кастомных репозиториев читайте в документации.
#SpringBoot #SpringTips #CustomRepository
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🔥8👌3
Пожалуй, почти каждый Spring разработчик сталкивается в своей практике с версионированием баз данных. На эту тему есть отличный доклад на Joker 2023 от Александра Шустанова, в котором спикер сравнивает 2 самых популярных инструмента для миграций БД: Flyway и Liquibase. Редакция Spring АйО приводит транскрипт доклада, для тех, у кого нет 45 минут для просмотра видео.
В статье вас ожидает обзор ключевых особенностей Liquibase и Flyway, а также сравнение их возможностей. Расскажем, когда нужно создавать миграции, как облегчить этот процесс и уменьшить количество ошибок. Осветим некоторые малоизвестные возможности этих инструментов и развеем мифы о других.
📚 Подробнее читайте на Хабре
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥8❤5👎1