📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP
⚡️ Квиз на знание Java
Пройти тестирование — сложно! А ты справишься?
21 вопрос, 30 минут
Проверь себя - пройди квиз и оцени свой уровень навыков, а также свою готовность к обучению на курсе — «Разработчик на Spring Framework» от OTUS.
💻 За 5 месяцев обучения ты освоишь современные возможности Spring, научишься быстро проходить путь от идеи до production-grade, создавать Web-приложения на микросервисной архитектуре и решать высокоуровневые задачи по разработке.
👉 ПРОЙТИ ТЕСТ: https://vk.cc/cLshxc
Если успешно пройдешь тест, сможешь забронировать место в группе по выгодной цене! И еще дарим промокод SPRING5
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🧠 Как в Java сломать equals() и потерять данные в HashMap
Сегодня покажу, как неочевидный баг в equals()/hashCode()
может привести к потере данных при работе с HashMap
.
Допустим, у вас есть Entity:
public class User {
private String id;
private String name;
// equals/hashCode только по id
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
HashMap
, а потом... изменим его id:
User user = new User();
user.setId("1");
user.setName("Alice");
Map<User, String> map = new HashMap<>();
map.put(user, "value");
user.setId("2"); // ⚠️ ключ стал "невидимым"
System.out.println(map.get(user)); // null 😱
HashMap
ищет ключ по hashCode()
→ ищет бакет → сравнивает через equals()
. А hashCode()
уже другой, и объект "теряется".equals()
/hashCode()
!final
;record
);record
:
public record User(String id, String name) {}
💡Сегодня покажу крутую фишку для оптимизации чтения больших коллекций из базы через JPA.
📌 Проблема:
Когда загружаем большую коллекцию через @OneToMany
, Hibernate часто делает это лениво (LAZY
), но при первом доступе — забирает всю коллекцию целиком.
Это может привести к OutOfMemoryError или резкому проседанию производительности.
📌 Решение: использовать пагинацию (batch-size
) или запрос коллекции порциями.
Как настроить batch-size
на уровне сущности:
@Entity
public class User {
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
@BatchSize(size = 50)
private List<Order> orders;
}
application.properties
:
spring.jpa.properties.hibernate.default_batch_fetch_size=50
@BatchSize
работает только для LAZY-связей.paged
запросы в репозитории.batch-size
Hibernate может сломать приложение под нагрузкой. Оптимизируйте загрузку коллекций заранее!Как работают instance initializer blocks.
Пример с родительским и дочерним классами:
class Parent {
int a = 5;
{
System.out.println("Parent instance initializer");
a = 10;
}
Parent() {
System.out.println("Parent constructor, a = " + a);
}
}
class Child extends Parent {
int b = 15;
{
System.out.println("Child instance initializer");
b = 25;
}
Child() {
System.out.println("Child constructor, b = " + b);
}
}
public class Test {
public static void main(String[] args) {
Child child = new Child();
}
}
Parent instance initializer
Parent constructor, a = 10
Child instance initializer
Child constructor, b = 25
Parent
.a = 5
),a = 10
),Parent()
).Child
:b = 15
),b = 25
),Child()
).super()
.Есть фича. Есть дедлайн. Есть понимание, что тесты надо писать… но они отъедают время, которого итак впритык.
Один наш знакомый девелопер сказал: «С тех пор как поставил Explyt Test — начал писать меньше тестов… но покрытие стало лучше. Как это вообще возможно?!»
Попробуйте сами. Плагин сам предлагает тесты для вашего кода — прямо в IDE.
👉 explyt.ai — сэкономь себе пару часов уже сегодня.
📌 Ошибка: Вызов метода с @Transactional
внутри того же класса не запускает новую транзакцию.
Почему? Spring оборачивает бин в прокси, а внутренние вызовы проходят мимо прокси, значит, аннотация игнорируется.
Пример проблемы:
@Service
public class OrderService {
@Transactional
public void createOrder() {
saveOrder();
}
@Transactional
public void saveOrder() {
// Новый транзакционный контекст не создастся!
}
}
saveOrder()
в отдельный бин.AopContext
:
@Service
@EnableAspectJAutoProxy(exposeProxy = true) // важно!
public class OrderService {
@Transactional
public void createOrder() {
((OrderService) AopContext.currentProxy()).saveOrder();
}
@Transactional
public void saveOrder() {
// Теперь всё ок ✅
}
}
exposeProxy = true
нужен на уровне конфигурации, иначе AopContext
не заработает.Сегодня покажу вам 🧠 один тонкий момент в работе с Optional
, который часто ловит даже опытных.
Многие пишут так:
Optional<String> optional = getValue();
if (optional.isPresent()) {
doSomething(optional.get());
}
Optional
и рискуете ошибками в многопоточке.
getValue().ifPresent(this::doSomething);
getValue()
.map(this::transform)
.filter(this::isValid)
.ifPresent(this::doSomething);
map
для преобразования значенияfilter
для отсеивания ненужныхorElse
, orElseGet
, orElseThrow
для обработки отсутствияifPresentOrElse
в Java 9+ для двух вариантов действийStream API
)orElseThrow()
вместо .get()
:
String value = getValue().orElseThrow(() -> new IllegalStateException("Value not found"));
.isPresent()
и .get()
связки — используйте силу функционального подхода! 🚀🧠 JPA: подводный камень с @ElementCollection
и fetch = FetchType.EAGER
Сегодня покажу, почему @ElementCollection(fetch = FetchType.EAGER)
— скрытая угроза производительности и неожиданного поведения.
📌 Суть проблемы
При использовании @ElementCollection
с EAGER
Hibernate делает отдельный SELECT на каждую коллекцию, даже при JOIN FETCH
на родительскую сущность.
@Entity
class User {
@Id Long id;
@ElementCollection(fetch = FetchType.EAGER)
List<String> tags;
}
findAll()
приведёт к N+1 проблеме: User
, потом по одному на каждый tags
.JOIN FETCH
на User
, Hibernate не может сделать JOIN
на @ElementCollection
. Это ограничение — Hibernate всегда грузит коллекцию отдельным запросом.Page<User>
— Hibernate сначала грузит User
'ов, а затем делает N запросов на коллекции. В проде это быстро становится проблемой.fetch = FetchType.LAZY
(по умолчанию так и есть).@BatchSize
:
@ElementCollection
@BatchSize(size = 20)
List<String> tags;
SELECT u FROM User u LEFT JOIN FETCH u.tags WHERE u.id IN :ids
@ElementCollection
— он не так прост, как кажется.👩💻 Разработка на Java требует глубокого понимания не только языка, но и принципов работы JVM, многопоточности и современных фреймворков.
Курс «Java Developer. Professional» — это структурированное обучение для разработчиков, которые хотят выйти на новый уровень, освоить актуальный стек технологий и уверенно претендовать на позиции уровня Middle+.
🦾 Вы получите 96 часов практической работы, обучение на живых вебинарах, вы разберете ключевые аспекты работы JVM, научитесь строить эффективные многопоточные приложения, освоите Spring WebFlux, Kafka, реактивный Postgres и Kubernetes.
Программа OTUS постоянно обновляется, соответствуя требованиям рынка, а диплом ценится работодателями.
👉 Пройдите вступительное тестирование и присоединяйтесь к группе: https://vk.cc/cL3cnt
🎁 Начните обучение со скидкой, подробности у менеджеров. ПРОМОКОД: JAVA_04
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🧠 JPA: не забывай про flush()
перед clear()
— иначе словишь баг
Если ты используешь EntityManager вручную, например, при батчевой вставке или обновлении, то, скорее всего, пишешь что-то вроде:
for (int i = 0; i < entities.size(); i++) {
em.persist(entities.get(i));
if (i % 50 == 0) {
em.clear(); // чтобы не росла память
}
}
flush()
перед clear()
ты теряешь все неперсистенные изменения! Hibernate просто забудет про них.
for (int i = 0; i < entities.size(); i++) {
em.persist(entities.get(i));
if (i % 50 == 0) {
em.flush();
em.clear();
}
}
flush()
гарантирует, что все накопленные изменения пойдут в базу, а clear()
уже безопасно очищает контекст.🧠 Spring Boot и медленные autowire — проверь, не зарыта ли у тебя бомба в @Configuration
Есть распространённый анти-паттерн: ты используешь @Configuration
и внутри создаёшь бины с @Bean
, а в этих методах — инжектишь зависимости через параметры. Всё выглядит красиво и «по фэншую»... но только на первый взгляд.
@Configuration
public class MyConfig {
@Bean
public MyService myService(SomeDep dep) {
return new MyService(dep);
}
@Bean
public SomeDep someDep() {
return new SomeDep();
}
}
SomeDep
создаётся долго (например, подтягивает настройки из удалённого конфига, делает init-запрос в БД, или тянет секьюрити-контекст), это тормозит весь старт.@Bean
-методы не видны как "инициализация", и кажется, что контекст тормозит "где-то ещё".@Lazy
в нужных местах, особенно если bean тяжёлый или редко используется.@Configuration
в пользу @Component
+ @Service
, если это упрощает понимание.spring-boot-starter-actuator
+ --debug
могут открыть глаза.🧠 Spring Boot 3.2+: ускоряем стартап с помощью application.metrics.export.observation.enabled=false
Spring Boot 3.2 по умолчанию включает сбор Micrometer Observation метрик — даже если вы не используете Prometheus, Datadog и пр.
Это полезно, но часто избыточно — особенно в микросервисах, где важна скорость старта.
📌 Что это даёт?
- Отключает автоконфигурацию ObservationRegistry
- Убирает связанные Bean
'ы
- Сокращает время старта до 30-60% (в зависимости от контекста)
💡 Как применить?
В application.yml
или application.properties
:
management:
metrics:
export:
observation:
enabled: false
.properties
:
management.metrics.export.observation.enabled=false
Реальные проекты и нетворкинг с профи: Летняя школа бэкенд‑разработки Яндекса открыла набор
Начинающие бэкендеры, есть планы на лето? Если уже умеете писать читаемый код в Python, Java или C++ и разбираетесь в алгоритмах, Летняя школа бэкенда Яндекса — ваш шанс прокачаться в разработке высоконагруженных сервисов. Вы получите уникальный опыт, работая вместе с ведущими специалистами компании.
Как проходит обучение:
— со 2 июня по 27 июля — онлайн-лекции, семинары и практические задания
— с 28 июля по 24 августа — разработка реальных проектов офлайн или онлайн
Вас ждут:
— работа в фулстек-командах в коворкингах Яндекса
— лекции от специалистов компании в летнем лектории
— возможность стать частью команды и получить офер: больше половины выпускников становятся стажерами или сотрудниками компании
Школа бесплатная, но нужно пройти отбор. Отправляй заявку до 27 апреля!
Хотите глубже разобраться в функциональном программировании и писать более качественный код на Scala? Приходите на вебинар в Otus
24 апреля в 20:00 пройдёт открытый вебинар с Алексеем Воронцом — руководителем разработки в Naumen, 14 лет опыта, из них 9 лет на Scala. На практических примерах он покажет:
— почему Scala — функциональный язык
— как работать с ключевыми библиотеками
— как повысить выразительность кода
❗️ Если вы уже знакомы со Scala или только начинаете к нему присматриваться и хотите развивать функциональный подход в своих проектах — этот вебинар для вас.
Каждый участник:
— сможет задать вопросы эксперту
— получит скидку на полный курс по Scala-разработке
👉 Регистрируйтесь и сделайте свой код лучше
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
🧠 Как ускорить загрузку контекста Spring Boot — простой приём
Если у вас тяжёлый Spring Boot-приложение с кучей конфигураций и бинов, время старта может легко вырасти до 20–30 секунд и больше. Сегодня покажу приём, который помогает ускорить cold start за счёт отключения ненужных автоматических конфигураций.
📌 Spring Boot автоконфигурация — это палка о двух концах.
Она упрощает старт, но часто тянет за собой кучу лишнего. Особенно если вы используете @SpringBootApplication
, которая включает в себя @EnableAutoConfiguration
.
💡 Решение — использовать spring.autoconfigure.exclude
, чтобы явно выключить ненужное. Например:
# application.yaml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
--debug
или логгером org.springframework.boot.autoconfigure
уровня DEBUG.exclude
.@ImportAutoConfiguration
с явным списком нужных автоконфигураций. Это тонкая настройка, идеально для библиотек и SDK.Java. Сортировки
Java. Сортировка пузырьком.
Java. О сортировке выбором.
Java. Быстрая сортировка. Объяснение на пальцах)
Java. Оценка сложности алгоритмов сортировки.
Java. Сортировка слиянием.
Java. Сортировка подсчетом.
Java. Сортировка вставками.
Java. Сортировка расческой. От пузырька до расчески.
👉@BookJava
🤖 А ты справишься с тестом по Kotlin?
🏆 Пройди тест из 10 вопросов, проверь свой уровень знаний и получи скидку на онлайн-курс «Kotlin Backend Developer. Professional» от OTUS!
Если успешно пройдешь тест, сможешь забронировать место в группе по выгодной цене! И еще дарим промокод Kotlin5
🎫 Курс можно приобрести в рассрочку
➡️ Пройти тест и забрать скидку: https://vk.cc/cLkRLn
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟
Как меняется ИТ-индустрия с внедрением AI? Узнай 6 июня на ИТ-конференции МТС True Tech Day
True Tech Day 2025 — третья масштабная технологическая конференция МТС для профессионалов ИТ‑индустрии.
В программе:
— Больше 40 докладов от известных ученых и ИТ-компаний.
— Выступления зарубежных спикеров с индексом Хирша более 50.
— Концентрация практических кейсов: как создаются большие проекты с применением AI.
— Доклады по архитектуре, бэкенд-разработке и построению ИТ-платформ.
— AI-интерактивы и технологические квесты.
— Пространство для нетворкинга,
…а еще after-party со звездным лайн-апом.
Когда: 6 июня
Где: Москва, МТС Live Холл и онлайн
Участие бесплатно.Регистрация по ссылке.
В Java instance initializer blocks (блоки инициализации экземпляра) выполняются в следующем порядке:
- Они выполняются каждый раз, когда создается новый объект класса.
- Выполнение происходит после вызова конструктора родительского класса (super()
), но до тела конструктора текущего класса.
Порядок инициализации:
1. Сначала инициализируются поля в порядке их объявления.
2. Затем выполняются instance initializer blocks, в том порядке, в котором они написаны в коде.
3. После этого выполняется тело конструктора.
Пример:
class Example {
int x = 10;
{
System.out.println("Instance initializer block");
x = 20;
}
Example() {
System.out.println("Constructor");
System.out.println("x = " + x);
}
public static void main(String[] args) {
Example ex = new Example();
}
}
Instance initializer block
Constructor
x = 20
static {}
) — другое дело: они выполняются один раз при загрузке класса.🧠 Сегодня покажу вам полезный трюк для Spring Boot: как элегантно валидировать параметры контроллера без лишнего кода.
Часто вижу, как в контроллерах вручную проверяют @RequestParam
на пустоту или формат. Это шумит код и приводит к ошибкам.
Вместо этого используйте аннотации валидации прямо на параметрах:
@RestController
@RequestMapping("/api")
@Validated // Обязательно!
public class UserController {
@GetMapping("/users")
public List<User> getUsers(
@RequestParam @NotBlank String name,
@RequestParam @Min(18) int age
) {
// Если валидация не пройдена — автоматически вернётся 400 Bad Request
return userService.findUsers(name, age);
}
}
@Validated
над классом контроллера.jakarta.validation.constraints
.MethodArgumentNotValidException
.@ExceptionHandler
.@Validated
аннотации на контроллере валидация параметров работать не будет!🚀 Подборка Telegram каналов для программистов
Системное администрирование, DevOps 📌
/channel/bash_srv Bash Советы
/channel/win_sysadmin Системный Администратор Windows
/channel/sysadmin_girl Девочка Сисадмин
/channel/srv_admin_linux Админские угодья
/channel/linux_srv Типичный Сисадмин
/channel/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
/channel/linux_odmin Linux: Системный администратор
/channel/devops_star DevOps Star (Звезда Девопса)
/channel/i_linux Системный администратор
/channel/linuxchmod Linux
/channel/sys_adminos Системный Администратор
/channel/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
/channel/sysadminof Книги для админов, полезные материалы
/channel/i_odmin Все для системного администратора
/channel/i_odmin_book Библиотека Системного Администратора
/channel/i_odmin_chat Чат системных администраторов
/channel/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
/channel/sysadminoff Новости Линукс Linux
1C разработка 📌
/channel/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
/channel/DevLab1C 1С:Предприятие 8
/channel/razrab_1C 1C Разработчик
/channel/buh1C_prog 1C Программист | Бухгалтерия и Учёт
/channel/rabota1C_rus Вакансии для программистов 1С
Программирование C++📌
/channel/cpp_lib Библиотека C/C++ разработчика
/channel/cpp_knigi Книги для программистов C/C++
/channel/cpp_geek Учим C/C++ на примерах
Программирование Python 📌
/channel/pythonofff Python академия.
/channel/BookPython Библиотека Python разработчика
/channel/python_real Python подборки на русском и английском
/channel/python_360 Книги по Python
Java разработка 📌
/channel/BookJava Библиотека Java разработчика
/channel/java_360 Книги по Java Rus
/channel/java_geek Учим Java на примерах
GitHub Сообщество 📌
/channel/Githublib Интересное из GitHub
Базы данных (Data Base) 📌
/channel/database_info Все про базы данных
Мобильная разработка: iOS, Android 📌
/channel/developer_mobila Мобильная разработка
/channel/kotlin_lib Подборки полезного материала по Kotlin
Фронтенд разработка 📌
/channel/frontend_1 Подборки для frontend разработчиков
/channel/frontend_sovet Frontend советы, примеры и практика!
/channel/React_lib Подборки по React js и все что с ним связано
Разработка игр 📌
/channel/game_devv Все о разработке игр
Библиотеки 📌
/channel/book_for_dev Книги для программистов Rus
/channel/programmist_of Книги по программированию
/channel/proglb Библиотека программиста
/channel/bfbook Книги для программистов
БигДата, машинное обучение 📌
/channel/bigdata_1 Big Data, Machine Learning
Программирование 📌
/channel/bookflow Лекции, видеоуроки, доклады с IT конференций
/channel/rust_lib Полезный контент по программированию на Rust
/channel/golang_lib Библиотека Go (Golang) разработчика
/channel/itmozg Программисты, дизайнеры, новости из мира IT
/channel/php_lib Библиотека PHP программиста 👨🏼💻👩💻
/channel/nodejs_lib Подборки по Node js и все что с ним связано
/channel/ruby_lib Библиотека Ruby программиста
/channel/lifeproger Жизнь программиста. Авторский канал.
QA, тестирование 📌
/channel/testlab_qa Библиотека тестировщика
Шутки программистов 📌
/channel/itumor Шутки программистов
Защита, взлом, безопасность 📌
/channel/thehaking Канал о кибербезопасности
/channel/xakep_2 Хакер Free
Книги, статьи для дизайнеров 📌
/channel/ux_web Статьи, книги для дизайнеров
Математика 📌
/channel/Pomatematike Канал по математике
/channel/phis_mat Обучающие видео, книги по Физике и Математике
/channel/matgeoru Математика | Геометрия | Логика
Excel лайфхак📌
/channel/Excel_lifehack
/channel/mir_teh Мир технологий (Technology World)
Вакансии 📌
/channel/sysadmin_rabota Системный Администратор
/channel/progjob Вакансии в IT
🤖 Хотите автоматизировать инфраструктуру для тестирования прямо в Gradle?
На открытом уроке «Облако в кармане: запускаем всю инфраструктуру для теста при сборке» от OTUS мы расскажем, как избежать ручных настроек и запусков. Вместо этого вы научитесь автоматизировать весь процесс с помощью Docker, DockerCompose и TestContainers, интегрируя их с Gradle.
Урок полезен для разработчиков на Kotlin и Java, которые работают с автотестами — интеграционными и end-to-end.
В ходе урока вы освоите:
▫️Автоматический запуск всей необходимой инфраструктуры для тестирования.
▫️Создание Docker-образов для тестов и деплоя.
▫️Разработку автотестов, которые поднимут ваши навыки на новый уровень.
Участники получат скидку на курс «Kotlin Backend Developer. Professional».
➡️ Встречаемся 29 апреля в 20:00 МСК, регистрация открыта: https://vk.cc/cL78v6
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🧠 Как избежать N+1 при использовании @OneToMany
в JPA
Одна из самых коварных ловушек JPA - это N+1 проблема. Особенно часто она проявляется при @OneToMany
, например:
@Entity
class Author {
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
private List<Book> books;
}
getBooks()
— и BAM 💥: 1 запрос на авторов и N запросов на книги. @EntityGraph
или JOIN FETCH
@EntityGraph
— декларативный и более гибкий способ:
@EntityGraph(attributePaths = "books")
List<Author> findAll(); // Spring Data JPA
@Query("SELECT a FROM Author a JOIN FETCH a.books")
List<Author> findAllWithBooks();
LIMIT
. В таких случаях лучше использовать @BatchSize
или подзапросы.Чем отличаются checked и unchecked исключения в java?
В Java исключения делятся на два основных типа: checked и unchecked. Разница между ними ключевая и касается как обработки, так и структуры кода.
✅ Checked Exceptions (Проверяемые исключения)
Примеры: IOException
, SQLException
, FileNotFoundException
Отличия:
1. Проверяются компилятором — вы обязаны либо обработать их с помощью try-catch
, либо явно пробросить (throws
) в сигнатуре метода.
2. Производные от Exception
, но не от RuntimeException
.
3. Используются для ситуаций, которые можно разумно ожидать и обработать (например, отсутствие файла, проблемы с сетью).
Пример:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // может выбросить IOException
}
NullPointerException
, ArrayIndexOutOfBoundsException
, IllegalArgumentException
RuntimeException
.
public void printLength(String str) {
System.out.println(str.length()); // может выбросить NullPointerException
}
Осталось всего 2 дня — углубитесь в функциональное программирование на Scala в Otus 📢
24 апреля в 20:00 пройдёт открытый вебинар с Алексеем Воронцом — руководителем разработки в Naumen, 14 лет опыта, из них 9 лет на Scala. Он расскажет:
— почему Scala — функциональный язык
— как работать с ключевыми библиотеками
— как повысить выразительность кода
Если вы уже знакомы со Scala или желаете перейти на него и хотите развивать функциональный подход в своих проектах — этот вебинар для вас.
Каждый участник:
— сможет задать вопросы эксперту
— получит скидку на полный курс по Scala-разработке
👉 Не упустите возможность перейти на новый уровень — регистрируйтесь, осталось 2 дня до начала
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
23 апреля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Илья Аров, старший разработчик в Т1, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Илья будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Илье
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2Vtzqvv6bu4
🧠 Lazy Initialization по-взрослому: не создавай проблемы на ровном месте
В Spring Boot часто можно встретить вот такую конструкцию:
@Service
public class EmailService {
private final SmtpClient client = new SmtpClient(); // дорогая инициализация
}
SmtpClient
создаётся сразу при старте приложения. Даже если EmailService
ни разу не вызовется. Это не только waste of resources, но и может сломать запуск, если SmtpClient
требует специфического окружения.null
-check, а красиво, безопасно и читаемо:Lazy<T>
wrapper
@Component
public class EmailService {
private final Supplier<SmtpClient> client = Suppliers.memoize(SmtpClient::new);
public void sendEmail(...) {
client.get().send(...);
}
}
public class Lazy<T> {
private Supplier<T> supplier;
public Lazy(Supplier<T> supplier) {
this.supplier = () -> {
T value = supplier.get();
this.supplier = () -> value;
return value;
};
}
public T get() {
return supplier.get();
}
}
@Service
public class EmailService {
private final ObjectProvider<SmtpClient> client;
public EmailService(ObjectProvider<SmtpClient> client) {
this.client = client;
}
public void sendEmail(...) {
client.getObject().send(...);
}
}
Supplier
, ObjectProvider
или Lazy<T>
.🧠 Сейчас покажу баг, который легко пропустить при работе с @Transactional
в Spring Boot 3+.
📌 Проблема — транзакция не работает, потому что метод вызывается изнутри того же класса.
Рассмотрим пример:
@Service
public class UserService {
@Transactional
public void createUser(User user) {
saveUser(user);
sendWelcomeEmail(user); // бросает исключение
}
public void saveUser(User user) {
userRepository.save(user);
}
}
sendWelcomeEmail
выбросит исключение — транзакция не откатится, потому что @Transactional
работает через прокси. Вызов createUser()
должен идти извне, чтобы Spring "знал", что нужно обернуть вызов в транзакцию.
@Service
public class UserCreationService {
@Transactional
public void createUser(User user) {
// ...
}
}
@Autowired
private UserService self;
public void externalCaller(User user) {
self.createUser(user);
}
AopContext
:
((UserService) AopContext.currentProxy()).createUser(user);
exposeProxy = true
в @EnableAspectJAutoProxy
.🧠 Простое ускорение @Transactional
методов в Spring Boot
Знаете, что @Transactional
по умолчанию оборачивает метод в прокси?
Это значит:
- Внутренние вызовы в том же классе не проходят через транзакцию;
- Каждый такой прокси — это AOP-магия, которую можно обойти ради производительности.
📌 Если вы точно знаете, что метод будет вызываться только извне, и вам не нужна прокси-обёртка — используйте @Transactional
на уровне интерфейса и включите interface-based proxy.
@Configuration
@EnableTransactionManagement(proxyTargetClass = false) // JDK proxy
public class TransactionConfig {
}
public interface UserService {
@Transactional
void createUser(User user);
}
@Transactional
-методов.this.someMethod()
внутри сервиса.proxyTargetClass = true
на false
даёт +3-5% к throughput.👩💻 JDBC — ваш швейцарский нож для работы с данными
Приглашаем на открытый урок.
🗓 22 апреля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Professional».
О чём поговорим:
✔️Основы JDBC: что это такое, зачем нужно и как работает
✔️Практические примеры выполнения сложных запросов
✔️Работа с транзакциями и обработка ошибок в JDBC
✔️ Оптимизация производительности при работе с данными через JDBC
Кому будет интересно:
Вебинар будет полезен разработчикам, инженерам по базам данных и архитекторам ПО, стремящимся улучшить навыки работы с базами данных и оптимизировать взаимодействие с данными.
В результате урока:
Вы научитесь эффективно использовать JDBC для работы с базами данных и сможете применять полученные знания в реальных проектах
🔗 Ссылка на регистрацию: https://vk.cc/cKRDCS
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576