🧠 Проблема ленивой инициализации
Когда вы используете
📌 Типичный баг:
🔍 Если где-то в коде вызвать
⚠️ В результате — метод выполнится без транзакции, и вы не поймёте почему.
💡 Как избежать:
* Никогда не используйте
* Лучше разделите логику: сервис без прокси — отдельно, бизнес-методы с
✅ Надёжный способ: вызывать
👉 @java_geek
@Transactional
-сервисов в Spring BootКогда вы используете
@Transactional
на методе сервиса, Spring оборачивает бин в прокси. Но если вы решите сделать ленивую инициализацию (@Lazy
) или внедрите такой бин в другой с помощью ObjectProvider.getIfAvailable()
или @Autowired(required = false)
— есть риск неожиданного поведения.📌 Типичный баг:
@Service
@Lazy
public class MyService {
@Transactional
public void doSomething() {
// ...
}
}
🔍 Если где-то в коде вызвать
applicationContext.getBean(MyService.class)
в момент, когда прокси ещё не создан — вы получите оригинальный, не-прокси-объект. А значит, @Transactional
не сработает.⚠️ В результате — метод выполнится без транзакции, и вы не поймёте почему.
💡 Как избежать:
* Никогда не используйте
@Lazy
или ленивое получение @Transactional
-сервисов, если не понимаете нюансов проксирования.* Лучше разделите логику: сервис без прокси — отдельно, бизнес-методы с
@Transactional
— в другом бине.✅ Надёжный способ: вызывать
@Transactional
-методы только через Spring-контейнер. Даже внутри самого сервиса — через self-injection:
@Service
public class MyService {
private final MyService self;
public MyService(@Lazy MyService self) {
this.self = self;
}
public void doWrapper() {
self.doTransactional(); // прокси работает
}
@Transactional
public void doTransactional() {
// ...
}
}
👉 @java_geek
🧠 Ленивая инициализация бинов в Spring Boot 3 — когда это спасает прод
Иногда на проде случаются сбои при старте из-за тяжёлых или нестабильных бинов. Это может быть внешняя интеграция, длительная инициализация или просто нестабильный ресурс. В таких случаях поможет ленивая инициализация.
📌 Как включить ленивую инициализацию глобально:
📌 Или в
💡 Бины будут создаваться только при первом запросе к ним. Это уменьшает время старта и помогает "пережить" временные проблемы.
⚠️ Минусы:
* Ошибки сдвигаются с этапа запуска на runtime.
* Если бин важен для старта (например, контроллер или Scheduler), его лучше инициализировать сразу.
📌 Тонкая настройка:
Хотите ленивую инициализацию только для части приложения?
💡 Работает и с
📈 Используйте в микросервисах с большим числом зависимостей или при миграции на Spring Boot 3+, где время старта стало критичным (например, в serverless-архитектуре).
👉 @java_geek
Иногда на проде случаются сбои при старте из-за тяжёлых или нестабильных бинов. Это может быть внешняя интеграция, длительная инициализация или просто нестабильный ресурс. В таких случаях поможет ленивая инициализация.
📌 Как включить ленивую инициализацию глобально:
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(App.class);
app.setLazyInitialization(true);
app.run(args);
}
}
📌 Или в
application.yml
:
spring:
main:
lazy-initialization: true
💡 Бины будут создаваться только при первом запросе к ним. Это уменьшает время старта и помогает "пережить" временные проблемы.
⚠️ Минусы:
* Ошибки сдвигаются с этапа запуска на runtime.
* Если бин важен для старта (например, контроллер или Scheduler), его лучше инициализировать сразу.
📌 Тонкая настройка:
Хотите ленивую инициализацию только для части приложения?
@Lazy
@Component
public class HeavyService {
// ...
}
💡 Работает и с
@Bean
, @Service
, @Repository
.📈 Используйте в микросервисах с большим числом зависимостей или при миграции на Spring Boot 3+, где время старта стало критичным (например, в serverless-архитектуре).
👉 @java_geek
14 мая(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqvEJJNG
Please open Telegram to view this post
VIEW IN TELEGRAM
🧠 Почему
В Spring
📌 Прокси перехватывает только ВНЕШНИЕ вызовы метода.
Если вы вызываете
Пример:
💡 Даже если вы сделаете метод
⚠️ Аннотация
✅ Правильный подход:
Вынесите транзакционный метод в отдельный бин:
И используйте его из другого бина:
📌 Или используйте аспектно-ориентированную реализацию с
👉 @java_geek
@Transactional
не работает в private-методах?В Spring
@Transactional
работает через прокси. Это значит, что Spring оборачивает бин в обёртку, которая и управляет транзакцией. Но есть важный нюанс:📌 Прокси перехватывает только ВНЕШНИЕ вызовы метода.
Если вы вызываете
@Transactional
-метод изнутри того же класса, транзакция не начнётся.Пример:
@Service
public class UserService {
public void createUser() {
// вызов внутреннего метода — транзакция не активируется
saveUser();
}
@Transactional
private void saveUser() {
// НЕ будет работать как транзакционный
}
}
💡 Даже если вы сделаете метод
public
, но вызов будет из того же класса — эффект тот же: Spring-прокси его не "перехватит".⚠️ Аннотация
@Transactional
не работает на private
-методах вообще. Прокси просто не может их подменить.✅ Правильный подход:
Вынесите транзакционный метод в отдельный бин:
@Service
public class UserSaver {
@Transactional
public void saveUser() {
// теперь работает!
}
}
И используйте его из другого бина:
@Service
public class UserService {
private final UserSaver userSaver;
public UserService(UserSaver userSaver) {
this.userSaver = userSaver;
}
public void createUser() {
userSaver.saveUser(); // транзакция начнётся
}
}
📌 Или используйте аспектно-ориентированную реализацию с
@EnableAspectJAutoProxy(exposeProxy = true)
+ AopContext.currentProxy()
, но это уже хардкор.👉 @java_geek
🚀 Открой для себя идеальный путь к лидерству с карьерным тестом от ОЭЗ «Алабуга»! 🌟
Мечтаете о карьере в крупной компании, где ваш потенциал раскроется на полную? Наш тест поможет вам определить вашу уникальную лидерскую роль. Может быть, именно вы станете тем лидером, который выведет команду на новый уровень?
После прохождения теста вы можете заполнить заявку и получить приглашение на эксклюзивную лидерскую программу. Участие в программе открывает реальные перспективы трудоустройства в ОЭЗ «Алабуга», предоставляя шанс начать путь к профессиональному признанию.
Сделайте первый шаг к своему будущему сегодня! Пройдите тест, подайте заявку и начните строить свою карьеру вместе с нами. 🎯
Мечтаете о карьере в крупной компании, где ваш потенциал раскроется на полную? Наш тест поможет вам определить вашу уникальную лидерскую роль. Может быть, именно вы станете тем лидером, который выведет команду на новый уровень?
После прохождения теста вы можете заполнить заявку и получить приглашение на эксклюзивную лидерскую программу. Участие в программе открывает реальные перспективы трудоустройства в ОЭЗ «Алабуга», предоставляя шанс начать путь к профессиональному признанию.
Сделайте первый шаг к своему будущему сегодня! Пройдите тест, подайте заявку и начните строить свою карьеру вместе с нами. 🎯
Метод isEmpty()
👉 @java_geek
isEmpty()
– проверяет список на наличие элементов. Если список пустой, то возвращает true, в противном случае – false.👉 @java_geek
❓Зачем нужны и какие бывают блоки инициализации?
Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.
• Существуют статические и нестатические блоки инициализации.
• Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.
• Несколько блоков инициализации выполняются в порядке следования в коде класса.
• Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.
• Блок инициализации возможно создать и в анонимном классе.
👉 @java_geek
Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.
• Существуют статические и нестатические блоки инициализации.
• Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.
• Несколько блоков инициализации выполняются в порядке следования в коде класса.
• Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.
• Блок инициализации возможно создать и в анонимном классе.
👉 @java_geek
4 июня(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqxFHKss
Please open Telegram to view this post
VIEW IN TELEGRAM
Collections.disjoint()
👉 @java_geek
Collections.disjoint()
проверяет, не имеют ли две коллекции общих элементов. Это полезно для фильтрации, сравнения и оптимизации поиска пересечений.👉 @java_geek
HashMap: chain hashing и битовый спрединг
🧠 HashMap использует chain hashing + битовый спрединг
🔹 Хэш-функция (bit mixing):
🔹 Выбор бакета:
📌 Separate chaining: в каждом бакете хранится связный список (Java 8+ превращает списки длиной >8 в красно-черное дерево для ускорения).
📈 Сложность: средняя O(1), в худшем случае O(n) → O(log n) после treeification.
💡 Bit mixing объединяет старшие и младшие биты, чтобы при взятии по модулю power-of-two (маска
⚠️ Не для криптографии: это простая битовая операция, а не криптостойкая хэш-функция.
👉 @java_geek
🧠 HashMap использует chain hashing + битовый спрединг
🔹 Хэш-функция (bit mixing):
int h = key.hashCode();
int hash = h ^ (h >>> 16);
🔹 Выбор бакета:
int idx = hash & (table.length - 1);
📌 Separate chaining: в каждом бакете хранится связный список (Java 8+ превращает списки длиной >8 в красно-черное дерево для ускорения).
📈 Сложность: средняя O(1), в худшем случае O(n) → O(log n) после treeification.
💡 Bit mixing объединяет старшие и младшие биты, чтобы при взятии по модулю power-of-two (маска
&
) распределение оставалось равномерным.⚠️ Не для криптографии: это простая битовая операция, а не криптостойкая хэш-функция.
👉 @java_geek
🧠 Почему
Один из самых частых вопросов: "Я поставил
📌 Ответ — в механизме прокси Spring.
Spring оборачивает бины с
💡 Пример:
📎 Решения:
1. Вынести метод в другой бин:
2. Или вызвать себя через `ApplicationContext`:
⚠️ Но лучше использовать первый способ — он чище архитектурно.
👉 @java_geek
@Transactional
не работает?Один из самых частых вопросов: "Я поставил
@Transactional
, но транзакция не откатывается. Почему?"📌 Ответ — в механизме прокси Spring.
Spring оборачивает бины с
@Transactional
в прокси, которые перехватывают вызовы и управляют транзакцией. Но работает это только при вызове метода извне. Если ты вызываешь метод с @Transactional
внутри того же класса, прокси не используется, и аннотация игнорируется.💡 Пример:
@Service
public class UserService {
public void registerUser() {
createUser(); // ❌ Транзакция не работает!
}
@Transactional
public void createUser() {
// изменения в БД
}
}
📎 Решения:
1. Вынести метод в другой бин:
@Service
public class UserService {
private final UserWriter writer;
public UserService(UserWriter writer) {
this.writer = writer;
}
public void registerUser() {
writer.createUser(); // ✅ работает
}
}
@Service
public class UserWriter {
@Transactional
public void createUser() {
// изменения в БД
}
}
2. Или вызвать себя через `ApplicationContext`:
@Autowired
private ApplicationContext context;
public void registerUser() {
context.getBean(UserService.class).createUser(); // ✅ работает
}
⚠️ Но лучше использовать первый способ — он чище архитектурно.
👉 @java_geek
Приглашаем на открытый урок.
🗓 24 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java-разработчик».
О чём поговорим:
Кому будет интересно:
Начинающим Java-разработчикам, студентам и всем, кто хочет перестать бояться слов «тестирование» и «баги».
В результате вебинара вы:
Создадите свой первый тест на Java, поймёте, как тестировать методы с исключениями, и начнёте писать код, которым можно гордиться.
🔗 Ссылка на регистрацию: https://vk.cc/cMXt49
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM