Spring Boot: для отправки писем можно использовать spring-boot-starter-mail.
✅ Он включает всю необходимую конфигурацию и зависимости, благодаря чему отправка почты становится простой и понятной.
Добавь зависимость:
Настрой почтовые параметры в application.properties (или application.yml):
Используй JavaMailSender в коде:
👉 Java Portal
Добавь зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
Настрой почтовые параметры в application.properties (или application.yml):
spring.mail.host=smtp.gmail.com
spring.mail.port=587
[email protected]
spring.mail.password=my_password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
Используй JavaMailSender в коде:
@Autowired
private JavaMailSender mailSender;
public void sendEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
message.setFrom("[email protected]");
mailSender.send(message);
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Java-совет: используй
Значение создаётся лениво (только при первом обращении).
👉 Java Portal
ThreadLocal.withInitial(...), чтобы каждому потоку задавать своё безопасное значение по умолчанию.Значение создаётся лениво (только при первом обращении).
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍1
Тонкие Docker-образы для Java: в этой статье вы узнаете, как собирать тонкие Docker-образы для ваших Java-приложений с использованием Alpine Linux и инструмента jlink.
Мы будем опираться на свежие базовые образы Java 21 от Eclipse Temurin и BellSoft Liberica. Также мы сравним этих провайдеров с Alpaquita Linux, который тоже поставляется BellSoft. В сравнение также войдет оценка безопасности на основе количества уязвимостей. В качестве примера мы возьмем простое Spring Boot-приложение, которое поднимает несколько REST-эндпоинтов.
Если вам интересна Java в контексте контейнеризации, на моем блоге вы можете найти несколько похожих статей. Например, можно почитать, как ускорить старт Java на Kubernetes с помощью CRaC в том посте. Еще есть статья, где сравниваются разные провайдеры JDK, которые используются для запуска Java-приложений в Paketo Buildpacks.
👉 Java Portal
Мы будем опираться на свежие базовые образы Java 21 от Eclipse Temurin и BellSoft Liberica. Также мы сравним этих провайдеров с Alpaquita Linux, который тоже поставляется BellSoft. В сравнение также войдет оценка безопасности на основе количества уязвимостей. В качестве примера мы возьмем простое Spring Boot-приложение, которое поднимает несколько REST-эндпоинтов.
Если вам интересна Java в контексте контейнеризации, на моем блоге вы можете найти несколько похожих статей. Например, можно почитать, как ускорить старт Java на Kubernetes с помощью CRaC в том посте. Еще есть статья, где сравниваются разные провайдеры JDK, которые используются для запуска Java-приложений в Paketo Buildpacks.
Please open Telegram to view this post
VIEW IN TELEGRAM
Piotr's TechBlog
Slim Docker Images for Java - Piotr's TechBlog
In this article, you will learn how to build slim Docker images for your Java apps using Alpine Linux and the jlink tool.
👍2
Совет: в REST-сервисах ты часто получаешь только ID сущностей. И не всегда нужно тащить их из БД.
Чтобы проставить связь (по сути, foreign key в базе), можно “создать” ссылку на сущность через
👉 Java Portal
Чтобы проставить связь (по сути, foreign key в базе), можно “создать” ссылку на сущность через
getReferenceById(id) без SELECT и использовать её, чтобы задать relation.@Service
public SomeService {
@Autowired
private ProductRepository productRepository;
@Autowired
private CategoryRepository featureRepository;
public void setCategory(long productId, long categoryId) {
Product product = productRepository.findById(productId).orElseThrow(); // executes SELECT
Category category = categoryRepository.getReferenceById(categoryId); // does not execute a SELECT
product.setCategory(category);
productRepository.save(product);
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍5
Spring Boot: можно реализовать оптимистическую блокировку через аннотацию
✅ Идеально подходит, когда:
- чтения происходят часто
- записи сравнительно редкие
- конфликты случаются нечасто
❌ Не лучший вариант, когда:
- конфликты происходят часто
- нужна строгая сериализация
Когда читаем, Entity загружается с текущей версией. Допустим, version = 2.
Когда делаем update, учитывается запись с version = 2.
Если за это время другая транзакция уже успела её обновить, version уже не 2, апдейт не затронет ни одной строки, и Hibernate кинет OptimisticLockException.
То есть конфликт ловится без блокировки строки.
👉 Java Portal
@Version.- чтения происходят часто
- записи сравнительно редкие
- конфликты случаются нечасто
- конфликты происходят часто
- нужна строгая сериализация
public class Account {
@Id
private Long id;
private BigDecimal balance;
@Version
private Long version;
}Когда читаем, Entity загружается с текущей версией. Допустим, version = 2.
Когда делаем update, учитывается запись с version = 2.
Если за это время другая транзакция уже успела её обновить, version уже не 2, апдейт не затронет ни одной строки, и Hibernate кинет OptimisticLockException.
То есть конфликт ловится без блокировки строки.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Реальный event-driven проект на Core Java 21, Apache Kafka (KRaft mode) и PostgreSQL (в Docker).
Проект показывает, как современные распределенные системы обрабатывают заказы асинхронно через Kafka, без блокировок и ожидания между сервисами.
https://github.com/FlexiDriod/kafka-order-processing-system
👉 Java Portal
Проект показывает, как современные распределенные системы обрабатывают заказы асинхронно через Kafka, без блокировок и ожидания между сервисами.
https://github.com/FlexiDriod/kafka-order-processing-system
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - FlexiDriod/kafka-order-processing-system
Contribute to FlexiDriod/kafka-order-processing-system development by creating an account on GitHub.
🤣2😁1
Spring Boot: отдавай предпочтение статическим utility-классам вместо Spring-бинов только если они не хранят состояние, у них нет зависимостей и их не нужно мокать или оборачивать в AOP.
👉 Java Portal
public class CacheUtils {
private static Map<String, String> cache = new HashMap<>();
...
}
// Кэш как выше разделяется между всеми потоками и может случайно изменяться
@Component
@Scope("request")
public class CacheService {
private Map<String, String> cache = new HashMap<>();
...
}
// Если оформить это как бин, можно задать ему конкретный scope.
// Spring лучше управляет объектами с состоянием.Please open Telegram to view this post
VIEW IN TELEGRAM
👍3👀3💊3❤1
Большинство разработчиков в Spring знают, как доставать query-параметры и path variables.
Но часто забывают, что HTTP-хедеры можно вытаскивать так же просто. В Spring для этого есть аккуратный
Можно в одну строку получить
Пример:
▪️ Добавляешь в метод контроллера
▪️ Spring сам подхватывает значение из заголовка
▪️ Ты получаешь его сразу параметром метода
Нужно сделать опциональным?
Просто добавь
Нужен дефолт?
▪️ Используй
▪️ Очень полезно для логирования, аналитики, A/B тестов или фичефлагов, завязанных на заголовки.
▪️ Выручает при работе с API-клиентами, которые шлют кастомные заголовки.
▪️ Чище, короче и легче тестируется.
▪️ Чем меньше зависимостей от servlet API, тем лучше.
👉 Java Portal
Но часто забывают, что HTTP-хедеры можно вытаскивать так же просто. В Spring для этого есть аккуратный
@RequestHeader.Можно в одну строку получить
User-Agent, Authorization или любой кастомный хедер. И не нужно лезть в HttpServletRequest.Пример:
@RequestHeader("User-Agent") String userAgentНужно сделать опциональным?
Просто добавь
required = false.Нужен дефолт?
defaultValue = "unknown".Please open Telegram to view this post
VIEW IN TELEGRAM
👍20
Java-совет: чтобы не ловить оверхед на boxing/unboxing, используй стримы примитивов (IntStream/LongStream/DoubleStream) вместо Stream<Integer>/Stream<Long>/Stream<Double>.
❌ Создаём объекты Integer для каждого значения:
✅ Работаем напрямую с int:
✅ Другие примитивные стримы:
👉 Java Portal
Stream<Integer> boxed = Stream.of(1, 2, 3, 4, 5);
int sumBoxed = boxed.reduce(0, Integer::sum);
int sumPrimitive = IntStream.of(1, 2, 3, 4, 5).sum();
LongStream, DoubleStreamPlease open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3
Как прогревать кэши в Spring Boot?
И вообще, как делать что-то на старте приложения?
Обычно такие операции делают в
Если “прогрев” лежит в
Покажу более элегантный способ “прогрева кэшей”. В какой-то момент точно пригодится.
Смотри:
В чём плюс?
В интеграционных тестах с
Когда всё-таки нужно, чтобы “прогрев” выполнялся и в тестах, добавь параметр “использовать main метод”:
И всё. Если код должен выполняться после старта, но мешает тестам, клади его в
👉 Java Portal
И вообще, как делать что-то на старте приложения?
Обычно такие операции делают в
@PostConstruct или ловят событие ApplicationReadyEvent. Но у этих вариантов есть заметный минус.Если “прогрев” лежит в
@PostConstruct, как его отключать в тестах? Можно завести флаг, сделать наследника и подменять бин в тестовой конфигурации, но это не всегда помогает и часто выглядит как костыль.Покажу более элегантный способ “прогрева кэшей”. В какой-то момент точно пригодится.
Смотри:
SpringApplication.run(...) возвращает полностью готовый контекст. Из него можно получить нужный компонент и вызвать метод “прогрева”. Код выглядит так:@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(MainApplication.class, args);
AccountService accService = ctx.getBean(AccountService.class);
accService.loadDictionary();
}
}
В чём плюс?
В интеграционных тестах с
@SpringBootTest метод main не запускается. Значит, код внутри не выполняется. Никаких костылей вокруг @PostConstruct, всё чисто и аккуратно.Когда всё-таки нужно, чтобы “прогрев” выполнялся и в тестах, добавь параметр “использовать main метод”:
@SpringBootTest(useMainMethod = SpringBootTest.UseMainMethod.ALWAYS)
И всё. Если код должен выполняться после старта, но мешает тестам, клади его в
main. Очень полезный приём.Please open Telegram to view this post
VIEW IN TELEGRAM
❤4