fa
Feedback
Библиотека Java разработчика

Библиотека Java разработчика

رفتن به کانال در Telegram

📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

نمایش بیشتر

📈 تحلیل کانال تلگرام Библиотека Java разработчика

کانال Библиотека Java разработчика (@bookjava) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 10 042 مشترک است و جایگاه 11 640 را در دسته فناوری و برنامه‌ها و رتبه 62 744 را در منطقه روسيا دارد.

📊 شاخص‌های مخاطب و پویایی

از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 10 042 مشترک جذب کرده است.

بر اساس آخرین داده‌ها در تاریخ 05 اکتبر, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -48 و در ۲۴ ساعت گذشته برابر -2 بوده و همچنان دسترسی گسترده‌ای حفظ شده است.

  • وضعیت تأیید: تأیید نشده
  • نرخ تعامل (ER): میانگین تعامل مخاطب 8.21% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 3.65% واکنش نسبت به کل مشترکان کسب می‌کند.
  • دسترسی پست‌ها: هر پست به طور میانگین 825 بازدید دریافت می‌کند. در اولین روز معمولاً 367 بازدید جمع‌آوری می‌شود.
  • واکنش‌ها و تعامل: مخاطبان به‌طور فعال حمایت می‌کنند؛ میانگین واکنش به هر پست 5 است.
  • علایق موضوعی: محتوا بر موضوعات کلیدی مانند string, интерфейс, строка, boot, api تمرکز دارد.

📝 توضیح و سیاست محتوایی

نویسنده این فضا را محل بیان دیدگاه‌های شخصی توصیف می‌کند:
“📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP”

به لطف به‌روزرسانی‌های پرتکرار (آخرین داده در تاریخ 06 اکتبر, 2026)، کانال همواره به‌روز و دارای دسترسی بالاست. تحلیل‌ها نشان می‌دهد مخاطبان به‌طور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامه‌ها تبدیل کرده‌اند.

10 042
مشترکین
-224 ساعت
-177 روز
-4830 روز
جذب مشترکین
اکتبر '26
اکتبر '26
+1
در 0 کانال‌ها
سپتامبر '26
+27
در 0 کانال‌ها
Get PRO
اوت '26
+17
در 0 کانال‌ها
Get PRO
ژوئیه '26
+20
در 0 کانال‌ها
Get PRO
ژوئن '26
+46
در 0 کانال‌ها
Get PRO
مه '26
+64
در 0 کانال‌ها
Get PRO
آوریل '26
+27
در 0 کانال‌ها
Get PRO
مارس '26
+28
در 0 کانال‌ها
Get PRO
فوریه '26
+39
در 0 کانال‌ها
Get PRO
ژانویه '26
+43
در 1 کانال‌ها
Get PRO
دسامبر '25
+16
در 0 کانال‌ها
Get PRO
نوامبر '25
+72
در 31 کانال‌ها
Get PRO
اکتبر '25
+47
در 1 کانال‌ها
Get PRO
سپتامبر '25
+61
در 36 کانال‌ها
Get PRO
اوت '25
+55
در 0 کانال‌ها
Get PRO
ژوئیه '25
+63
در 27 کانال‌ها
Get PRO
ژوئن '25
+44
در 19 کانال‌ها
Get PRO
مه '25
+65
در 44 کانال‌ها
Get PRO
آوریل '25
+90
در 38 کانال‌ها
Get PRO
مارس '25
+78
در 38 کانال‌ها
Get PRO
فوریه '25
+100
در 31 کانال‌ها
Get PRO
ژانویه '25
+83
در 33 کانال‌ها
Get PRO
دسامبر '24
+116
در 34 کانال‌ها
Get PRO
نوامبر '24
+67
در 32 کانال‌ها
Get PRO
اکتبر '24
+99
در 29 کانال‌ها
Get PRO
سپتامبر '24
+131
در 28 کانال‌ها
Get PRO
اوت '24
+97
در 18 کانال‌ها
Get PRO
ژوئیه '24
+45
در 0 کانال‌ها
Get PRO
ژوئن '24
+99
در 23 کانال‌ها
Get PRO
مه '24
+234
در 18 کانال‌ها
Get PRO
آوریل '24
+210
در 0 کانال‌ها
Get PRO
مارس '24
+282
در 21 کانال‌ها
Get PRO
فوریه '24
+274
در 17 کانال‌ها
Get PRO
ژانویه '24
+329
در 23 کانال‌ها
Get PRO
دسامبر '23
+222
در 23 کانال‌ها
Get PRO
نوامبر '23
+117
در 16 کانال‌ها
Get PRO
اکتبر '23
+136
در 18 کانال‌ها
Get PRO
سپتامبر '23
+243
در 0 کانال‌ها
Get PRO
اوت '23
+325
در 0 کانال‌ها
Get PRO
ژوئیه '23
+322
در 0 کانال‌ها
Get PRO
ژوئن '23
+306
در 0 کانال‌ها
Get PRO
مه '23
+287
در 0 کانال‌ها
Get PRO
آوریل '23
+271
در 0 کانال‌ها
Get PRO
مارس '23
+603
در 0 کانال‌ها
Get PRO
فوریه '23
+153
در 0 کانال‌ها
Get PRO
ژانویه '23
+214
در 0 کانال‌ها
Get PRO
دسامبر '22
+206
در 0 کانال‌ها
Get PRO
نوامبر '22
+140
در 0 کانال‌ها
Get PRO
اکتبر '22
+207
در 0 کانال‌ها
Get PRO
سپتامبر '22
+226
در 0 کانال‌ها
Get PRO
اوت '22
+288
در 0 کانال‌ها
Get PRO
ژوئیه '22
+299
در 0 کانال‌ها
Get PRO
ژوئن '22
+278
در 0 کانال‌ها
Get PRO
مه '22
+315
در 0 کانال‌ها
Get PRO
آوریل '22
+318
در 0 کانال‌ها
Get PRO
مارس '22
+417
در 0 کانال‌ها
Get PRO
فوریه '22
+328
در 0 کانال‌ها
Get PRO
ژانویه '22
+245
در 0 کانال‌ها
Get PRO
دسامبر '21
+222
در 0 کانال‌ها
Get PRO
نوامبر '21
+172
در 0 کانال‌ها
Get PRO
اکتبر '21
+323
در 0 کانال‌ها
Get PRO
سپتامبر '21
+207
در 0 کانال‌ها
Get PRO
اوت '21
+331
در 0 کانال‌ها
Get PRO
ژوئیه '21
+310
در 0 کانال‌ها
Get PRO
ژوئن '21
+271
در 0 کانال‌ها
Get PRO
مه '21
+297
در 0 کانال‌ها
Get PRO
آوریل '21
+328
در 0 کانال‌ها
Get PRO
مارس '21
+419
در 0 کانال‌ها
Get PRO
فوریه '21
+436
در 0 کانال‌ها
Get PRO
ژانویه '21
+452
در 0 کانال‌ها
Get PRO
دسامبر '20
+7 112
در 0 کانال‌ها
تاریخ
رشد مشترکین
اشارات
کانال‌ها
06 اکتبر0
05 اکتبر0
04 اکتبر+1
03 اکتبر0
02 اکتبر0
01 اکتبر0
پست‌های کانال
🧠 Dependency Inversion Principle (D в SOLID) Зависимости должны идти от высокоуровневой политики к низкоуровневым деталям, а не наоборот. Абстракции — хозяева, реализации — обслуживающий персонал. 📌 Коротко о сути * Модули верхнего уровня (бизнес-логика) зависят только от интерфейсов/абстракций. * Модули нижнего уровня (база, сеть, файлы) также зависят от тех же абстракций. * Сами абстракции не знают ничего о деталях, тем самым разрывая «бетонную» сцепку между слоями. 💡 Мини-пример (Java 17+, Spring Boot 3+)

// 1️⃣ Абстракция — контракт
public interface NotificationSender {
    void send(Message msg);
}

// 2️⃣ Верхний уровень — бизнес-служба
@Service
public class BillingService {
    private final NotificationSender sender;

    public BillingService(NotificationSender sender) {
        this.sender = sender;                 // зависим от контракта
    }

    public void bill(Client c) {
        // ...
        sender.send(new Message("Invoice #42"));
    }
}

// 3️⃣ Низкий уровень — деталь
@Component
public class EmailSender implements NotificationSender {
    public void send(Message msg) {
        // SMTP-магия
    }
}
BillingService может жить в модульном jar без spring-email-starter и SMTP-кода — протестировать его теперь элементарно. ⚠️ Где рождаются проблемы 1. Путаница DI container ≠ DIP IoC/DI-фреймворк (Spring, CDI) — лишь удобный способ «сращивать» зависимости, но принцип работает и без контейнера (чистый constructor injection). 2. Абстракции ради галочки Интерфейс OneImplService с единственной реализацией ломает читаемость, тесты и автоконфиг 📉. ➜ Создавай абстракцию, когда реально нужны сменяемость, тестируемость или расширяемость. 3. Утечки деталей Если интерфейс таскает DTO из слоя хранения, ты всё ещё «протёк» к базе. Держи контракты чистыми. 4. Слепая вера в фреймворк Жизненный цикл бинов, прокси, lazy-init — магия мешает понимать, кто кем владеет. ➜ Всегда можешь собрать объект вручную в юнит-тесте. Если сложно — запах нарушения DIP. 5. Слишком много уровней абстракций «Контроллер → сервис → менеджер → порт → адаптер → репозиторий» превращает код в матрёшку. Дизайн важнее количества слоёв. 📝 Практические советы * Используй constructor injection по умолчанию. Поле final = явная зависимость. * Группируй интерфейсы по use-case, а не по технологии (например, TransferPort, а не JdbcTransferRepository). * В тестах не мокай фреймворк — мокай контракт. * Для одноразовых реализаций начни с class. Если появится второй вариант — быстро вынесешь интерфейс (IDE поможет). * Проверка себя: можно ли запустить модуль верхнего уровня без нижнего? Если да — DIP соблюдён. 💬 Итог DIP — это не про «везде интерфейсы» и не про «подключи Spring». Это про правильное направление зависимостей, которое делает код гибким, тестируемым и не заложником технологий. А проблемы возникают, когда путают инструмент с принципом и забывают, что абстракция должна прятать детали, а не выпячивать их. 📲 Мы в MAX 👉@BookJava

2
Три похожих слова в Java — final, finally, finalize — но смысл у них совершенно разный. Разберёмся 🧠 🔒 final Ключевое слово
Три похожих слова в Java — final, finally, finalize — но смысл у них совершенно разный. Разберёмся 🧠 🔒 final Ключевое слово. Используется для ограничений: * final class — нельзя наследовать. * final method — нельзя переопределить. * final variable — нельзя изменить значение (один раз присвоил — всё). 📌 Особенно важно для immutability и thread-safety. final int x = 10; x = 20; // ошибка компиляции 🧯 finally Блок в конструкции try-catch-finally. Выполняется всегда, даже если был return или exception. 💡 Используется для освобождения ресурсов: закрытия потоков, соединений и т.д. try { // что-то может выбросить исключение } catch (Exception e) { // обработка ошибки } finally { // всегда выполнится } ⚰️ finalize() Метод из Object, вызывался перед удалением объекта сборщиком мусора. ⚠️ УСТАРЕЛ с Java 9, удалён в Java 18. Не используй. 🔪 Непредсказуем, плохо работает, тормозит GC. Вместо него — AutoCloseable и try-with-resources. @Override protected void finalize() throws Throwable { System.out.println("До свидания..."); } 🧠 Важно не путать: * final — про нельзя менять * finally — про всегда выполнится * finalize — про устаревший и бесполезный метод 📲 Мы в MAX 👉@BookJava
636
3
🧠 Ленивая инициализация через Supplier — элегантная альтернатива double-checked locking Когда нужно отложить создание тяжёло
🧠 Ленивая инициализация через Supplier — элегантная альтернатива double-checked locking Когда нужно отложить создание тяжёлого объекта до первого обращения, многие вспоминают double-checked locking: private volatile SomeHeavyObject obj; public SomeHeavyObject getObj() { if (obj == null) { synchronized (this) { if (obj == null) { obj = new SomeHeavyObject(); } } } return obj; } ⚠️ Многословно, хрупко, легко ошибиться. Есть лучше. 📌 Современный подход — использовать Supplier с ленивой инициализацией: private final Supplier<SomeHeavyObject> lazyObj = Suppliers.memoize(SomeHeavyObject::new); public SomeHeavyObject getObj() { return lazyObj.get(); } 💡 Suppliers.memoize — из Guava. Он гарантирует потокобезопасную инициализацию один раз при первом вызове get(). Плюсы: — Читается за секунду — Потокобезопасно — Нет дублирования кода — Легко тестировать и заменять 🔁 Альтернатива в чистой Java: использовать AtomicReference и updateAndGet, но это уже длиннее и менее выразительно. Если используешь Spring — можно просто обернуть бин в @Lazy. Но вне Spring, в обычных Java-приложениях или утилитах — Supplier с memoize() идеален. 📲 Мы в MAX 👉@BookJava
725
4
Что такое механизм try-with-resources? Механизм try-with-resources в Java — это конструкция, которая упрощает работу с ресурс
Что такое механизм try-with-resources? Механизм try-with-resources в Java — это конструкция, которая упрощает работу с ресурсами, требующими закрытия (например, файлы, сокеты, соединения с БД и т.д.). Он автоматически закрывает ресурсы после завершения блока try, избавляя от необходимости писать finally вручную. 📌 Поддерживается с Java 7 📌 Ресурсы должны реализовывать интерфейс AutoCloseable 💡 Пример: try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) { String line = reader.readLine(); System.out.println(line); } catch (IOException e) { e.printStackTrace(); } // reader будет закрыт автоматически, даже если произойдёт исключение 🧠 Почему это важно: * Уменьшает boilerplate-код * Исключает утечки ресурсов * Упрощает обработку исключений ⚠️ Совет: С Java 9 можно использовать уже объявленные переменные, если они final или effectively final: BufferedReader reader = new BufferedReader(new FileReader("file.txt")); try (reader) { System.out.println(reader.readLine()); } 📲 Мы в MAX 👉@BookJava
890
5
📌 picocli — это современная библиотека для создания CLI-приложений на Java. Она упрощает разработку командных интерфейсов, о
📌 picocli — это современная библиотека для создания CLI-приложений на Java. Она упрощает разработку командных интерфейсов, обеспечивая: * Автоматическую генерацию --help и --version * Поддержку подкоманд (как в git commit, git push) * Аргументы, параметры, опции с короткими и длинными флагами (-v, --verbose) * Интеграцию с GraalVM (подходит для нативной компиляции) * Поддержку аннотаций (аннотируй POJO — и готово!) * Автоматическую валидацию аргументов * Цветной вывод и гибкое форматирование * Интерактивный режим и автодополнение Проект активно развивается, полностью документирован и используется в сотнях продакшн-проектов. Если ты ищешь мощную и простую в использовании CLI-библиотеку на Java — picocli отличный выбор. https://github.com/remkop/picocli 📲 Мы в MAX 👉@BookJava
898
6
Double-brace инициализация в Java — это идиома, которая используется для инициализации коллекций (и иногда других объектов) в
Double-brace инициализация в Java — это идиома, которая используется для инициализации коллекций (и иногда других объектов) в краткой форме. Она выглядит как две открывающие фигурные скобки подряд {{ и имеет специфическое поведение. Пример: import java.util.*; List<String> list = new ArrayList<String>() {{ add("one"); add("two"); add("three"); }}; Как это работает: Double-brace инициализация — это комбинация двух конструкций: 1. Анонимный внутренний класс: new ArrayList<String>() { ... } Создаётся новый безымянный подкласс ArrayList. 2. Инициализатор экземпляра: {{ ... }} Это блок, который выполняется при создании объекта. В него можно вставлять вызовы методов (например, add()). Преимущества: * Компактный и удобочитаемый синтаксис для заполнения коллекций. * Можно использовать в полях final, например: private static final Set<String> set = new HashSet<>() {{ add("A"); add("B"); }}; Недостатки: 1. Создаётся лишний анонимный класс — это увеличивает количество байткода и может мешать сериализации. 2. Утечки памяти — если такой класс находится внутри внешнего класса, он может неявно хранить ссылку на него. 3. Читаемость — не все разработчики знают, как это работает, и это может сбивать с толку. 4. Нарушение принципов OOP — логика инициализации размещается в конструкторе, который не явно виден. Альтернативы: Java 8+ (через Stream и Collectors): List<String> list = Stream.of("one", "two", "three") .collect(Collectors.toList()); Статический метод инициализации: public static List<String> createList() { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); return list; } Java 9+ (immutable): List<String> list = List.of("one", "two", "three"); Set<String> set = Set.of("A", "B"); Вывод: Double-brace инициализация — это удобный, но потенциально опасный трюк, который не рекомендуется использовать в продакшене. Лучше предпочесть более читаемые и безопасные альтернативы, особенно с учётом новых возможностей Java 8+. 📲 Мы в MAX 👉@BookJava
911
7
🧠@Value vs @ConfigurationProperties — не выбирай наобум Оба способа хороши для конфигурации, но используют их по-разному. И
🧠@Value vs @ConfigurationProperties — не выбирай наобум Оба способа хороши для конфигурации, но используют их по-разному. И если ты всё ещё везде пихаешь @Value, держи краткий гайд, когда лучше что: 📌 @Value — просто, но не гибко: @Value("${my.prop}") private String value; ✅ Хорошо для единичных значений ❌ Плохо для сложных структур, списков, валидации ❌ Трудно покрыть тестами (без TestPropertySource) ❌ Нет биндинга по префиксу → нет группировки 📌 @ConfigurationProperties — сила и масштаб: @ConfigurationProperties(prefix = "app.feature") public class FeatureProperties { private boolean enabled; private List<String> items; } 💡 Используй с @EnableConfigurationProperties или аннотируй как @Component ✅ Удобно группировать и документировать ✅ Работает с вложенными структурами, коллекциями ✅ Поддерживает JSR-303 валидацию (@Validated) ✅ Легче мокать в тестах ✅ Интеграция с Spring Boot Actuator (/actuator/configprops) ⚠️ Не смешивай: не нужно тянуть @Value внутрь @ConfigurationProperties — это антипаттерн. Если конфигурация простая — @Value норм. Но как только появляется структура, коллекции, логика — всегда используй @ConfigurationProperties. 📲 Мы в MAX 👉@BookJava
822
8
🧠 Трюк с @EventListener в Spring — убираем лишний @TransactionalEventListener Когда тебе нужно обрабатывать события в рамках
🧠 Трюк с @EventListener в Spring — убираем лишний @TransactionalEventListener Когда тебе нужно обрабатывать события в рамках транзакции, мы часто пишем: @TransactionalEventListener public void handleEvent(MyEvent event) { // ... } ⚠️ Но есть нюанс: @TransactionalEventListener по умолчанию срабатывает после коммита. Иногда это не очевидно и вызывает баги, особенно если ожидаешь, что событие обработается внутри транзакции. 📌 Альтернатива: обычный @EventListener, но вместе с TransactionSynchronizationManager. 💡 Сниппет: @Component public class MyEventHandler { @EventListener public void handle(MyEvent event) { if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization( new TransactionSynchronizationAdapter() { @Override public void afterCommit() { // обработка события после коммита } } ); } else { // fallback: нет активной транзакции — выполняем сразу } } } 📎 Плюсы: — Лучше контроль: ты сам решаешь, когда обрабатывать (до/после/вне транзакции) — Можно централизовать поведение через utility-метод — Гибкость: логика обработки не зависит от аннотаций Spring'а ⚠️ Минус: чуть больше кода, но понятнее поведение. 📲 Мы в MAX 👉@BookJava
845
9
👩‍💻 HTTP-сервер на чистой Java за 30 минут Приглашаем на открытый урок. 🗓 21 сентября в 20:00 МСК 🆓 Бесплатно. Урок в рам
👩‍💻 HTTP-сервер на чистой Java за 30 минут Приглашаем на открытый урок. 🗓 21 сентября в 20:00 МСК 🆓 Бесплатно. Урок в рамках старта курса «Java разработчик. Продвинутый уровень». Разберем, как браузер общается с сервером, и создадим работающий HTTP-сервис без Spring и сторонних библиотек. О чем поговорим: ✔️ Как устроен HTTP-запрос ✔️ Создадим сервер на Java ✔️ Добавим несколько адресов ✔️ Откроем результат в браузере ✔️ Разберём, что скрывает Spring 🔗 Ссылка на регистрацию: https://vk.cc/d1sLwn Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
1 084
10
🧠 Как не словить LazyInitializationException в Spring Boot + Hibernate Одна из самых частых ошибок при работе с JPA: org.hib
🧠 Как не словить LazyInitializationException в Spring Boot + Hibernate Одна из самых частых ошибок при работе с JPA: org.hibernate.LazyInitializationException: failed to lazily initialize a collection 📌 Причина: лениво загружаемая коллекция (LAZY) обращается к БД вне транзакции — например, в слое контроллера или после закрытия Session. 💡 Как избежать? ✅ Решение 1: @Transactional в сервисе Убедитесь, что вы обращаетесь к ленивым коллекциям внутри метода с @Transactional: @Transactional public UserDto getUser(Long id) { User user = userRepository.findById(id) .orElseThrow(); // OK: коллекция friends будет инициализирована в транзакции return new UserDto(user.getName(), user.getFriends()); } ⚠️ Не используйте @Transactional в контроллерах - это плохая практика. ✅ Решение 2: Fetch Join Подгрузите нужные данные сразу через JOIN FETCH: @Query("SELECT u FROM User u LEFT JOIN FETCH u.friends WHERE u.id = :id") Optional<User> findByIdWithFriends(@Param("id") Long id); 📌 Плюс: 1 запрос вместо N (N+1 проблема решается). 📌 Минус: может быть избыточная загрузка, особенно с большими коллекциями. ✅ Решение 3: DTO проекция Лучший способ в большинстве случаев - проецировать сразу в DTO: @Query(""" SELECT new com.example.UserDto(u.name, f.name) FROM User u LEFT JOIN u.friends f WHERE u.id = :id """) List<UserDto> findUserWithFriendNames(@Param("id") Long id); 📌 Выгружает только нужные данные. Быстро, безопасно, эффективно. Ленивая инициализация - ок, если вы контролируете границы транзакций. Проекции и fetch join - ваши лучшие друзья, если нужен контроль и производительность. 📲 Мы в MAX 👉@BookJava
880
11
📌 Java Collections 📲 Мы в MAX 👉@BookJava+2
📌 Java Collections 📲 Мы в MAX 👉@BookJava
949
12
🧠 Spring Boot: ленивые зависимости через ObjectProvider Иногда сервису не нужно всегда инжектить другую зависимость при стар
🧠 Spring Boot: ленивые зависимости через ObjectProvider Иногда сервису не нужно всегда инжектить другую зависимость при старте — только иногда по ходу работы. Но @Autowired всё равно тянет её сразу, даже если она вам пока не нужна. Это бьёт по времени старта и может вызвать циклические зависимости. 💡 Решение: использовать ObjectProvider<T>. Пример: @Service public class NotificationService { private final ObjectProvider<EmailSender> emailSenderProvider; public NotificationService(ObjectProvider<EmailSender> emailSenderProvider) { this.emailSenderProvider = emailSenderProvider; } public void sendEmailIfEnabled(String to, String body) { if (featureEnabled()) { EmailSender sender = emailSenderProvider.getIfAvailable(); if (sender != null) { sender.send(to, body); } } } } 📌 ObjectProvider: ▫️не создаёт бин сразу — ленивый доступ; ▫️ позволяет проверить наличие бина (getIfAvailable() / ifAvailable(...)); ▫️можно использовать stream() — для коллекций бинов. ⚠️ Это не альтернатива DI. Это способ контролировать создание и использование бинов вручную, когда это действительно нужно. 📈 Отлично помогает: ▫️при борьбе с циклическими зависимостями; ▫️для optional-бинов; ▫️чтобы ускорить старт приложения. 📲 Мы в MAX 👉@BookJava
1 216
13
💡 Чем опасен @Scheduled(fixedRate) без @Transactional? Расписание в Spring через @Scheduled — удобный способ запускать задач
💡 Чем опасен @Scheduled(fixedRate) без @Transactional? Расписание в Spring через @Scheduled — удобный способ запускать задачи по таймеру. Но часто разработчики забывают про транзакции, особенно с fixedRate, и попадают в ловушку. 📌 Пример проблемы: @Scheduled(fixedRate = 10_000) public void cleanUp() { List<Job> jobs = jobRepository.findAllByStatus(PENDING); jobs.forEach(job -> { job.setStatus(PROCESSING); jobRepository.save(job); }); } 🧨 Каждые 10 секунд метод запускается заново. Если выполнение предыдущего ещё не закончено, начнётся второй поток, который заберёт те же PENDING -записи. В итоге — дублирование обработки, гонки, повреждение данных. 📉 Особенно критично при долгих задачах или высокой нагрузке. ✅ Решение — обернуть метод в транзакцию + использовать блокировки: @Transactional @Scheduled(fixedRate = 10_000) public void cleanUp() { List<Job> jobs = jobRepository.findAllByStatusForUpdate(PENDING); // SELECT ... FOR UPDATE jobs.forEach(job -> { job.setStatus(PROCESSING); jobRepository.save(job); }); } 📌 Или добавить флаг “locked”, чтобы явно помечать взятые задачи. 💡 Лучше использовать @Scheduled(fixedDelay) — он ждёт завершения предыдущего запуска. Это безопаснее по умолчанию. 🧠 Подумайте о том, чтобы заменить @Scheduled на: * Spring Batch (если сложные джобы) * Spring Integration / Flowable / Camunda (если нужны гарантии и retry) * Quartz (если нужен контроль и очереди) 📲 Мы в MAX 👉@BookJava
981
14
🔴 Завтра тестовое собеседование с Java-разработчиком 2 сентября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собес
🔴 Завтра тестовое собеседование с Java-разработчиком 2 сентября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Сергею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.
914
15
🔧 Maven vs. Gradle: что выбрать разработчику? Когда речь заходит о сборке Java-проектов, выбор обычно падает на два главных
🔧 Maven vs. Gradle: что выбрать разработчику? Когда речь заходит о сборке Java-проектов, выбор обычно падает на два главных инструмента: Maven и Gradle. Оба давно стали стандартом индустрии, но каждый имеет свои особенности. Разберёмся, что выбрать 👇 ☕ Maven — проверенная классика ✅ Строгая структура: легче читать и сопровождать ✅ Надёжность и предсказуемость сборки ✅ Большое комьюнити и множество плагинов ⚠️ XML-конфигурация громоздкая ⚠️ Медленнее по сравнению с Gradle ⚡ Gradle — гибкость и скорость ✅ Поддержка Kotlin и Groovy DSL ✅ Инкрементальные сборки и кэширование → быстрее ✅ Более гибкий подход к настройке ⚠️ Порог входа выше ⚠️ Иногда сложно отлаживать конфигурацию 💡 Вывод: * 🔹 Выбирай Maven, если важны стабильность, простота и читаемость. * 🔹 Выбирай Gradle, если хочешь максимум производительности и гибкости. 🎯 В крупных проектах Gradle становится всё популярнее, особенно при использовании Kotlin. Но в enterprise-среде Maven по-прежнему правит бал. 📲 Мы в MAX 👉@BookJava
870
16
🧠 Трюк с @Configuration и @ComponentScan: как не словить баг при миграции на Spring Boot 3+ Когда вы выносите конфигурацию в
🧠 Трюк с @Configuration и @ComponentScan: как не словить баг при миграции на Spring Boot 3+ Когда вы выносите конфигурацию в отдельный модуль или создаёте библиотеку с @Configuration-классами — не забывайте: 📌 Spring Boot 3+ по умолчанию НЕ сканирует пакеты вне стартового (main). Пример: // Внутри библиотеки @Configuration public class MyLibConfig { @Bean public MyService myService() { return new MyService(); } } И вы такие: @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } 🔥 Но MyService не создаётся! Почему? 💡 Потому что @ComponentScan по умолчанию сканирует ТОЛЬКО package текущего класса и ниже. 📌 Решения: 1. Ручной импорт конфигурации: @SpringBootApplication @Import(MyLibConfig.class) public class App { ... } 2. Сделать конфигурацию @AutoConfiguration и подключить через spring.factories или META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports — актуально для библиотек. 3. Переместить MyLibConfig в подпакет стартового класса (не всегда возможно или удобно). ⚠️ Часто баг проявляется неявно: контекст стартует, но бины "теряются", и вы получаете NoSuchBeanDefinitionException в рантайме. ✅ После миграции на Spring Boot 3+ обязательно проверьте, что нужные конфигурации действительно подхватываются. Особенно, если раньше они подключались "магически". 📲 Мы в MAX 👉@BookJava
835
17
🧠 Неочевидный performance-трюк с @Transactional(readOnly = true) Многие используют @Transactional(readOnly = true) просто по
🧠 Неочевидный performance-трюк с @Transactional(readOnly = true) Многие используют @Transactional(readOnly = true) просто по инерции. Но вы знали, что в Spring это влияет не только на семантику, но и на производительность? 📌 Что делает readOnly = true: * Подсказывает Hibernate, что внутри транзакции не будет изменений сущностей. * Это позволяет избежать затрат на грязную проверку (dirty checking). * Не создаётся snapshot состояний сущностей → меньше памяти и операций. 💡 Пример: @Transactional(readOnly = true) public List<User> findActiveUsers() { return userRepository.findByActiveTrue(); } ⚠️ А теперь важно: если вы случайно измените сущность в таком методе, Hibernate проигнорирует изменения — потому что readOnly намекает: "не трогай". 📉 В реальном приложении с большим количеством запросов к БД, особенно читающих, такой подход даёт ощутимый буст — меньше нагрузки на ORM, меньше GC, быстрее ответы. 📌 Где применять: * Методы только для чтения. * REST-эндпоинты GET. * Сервис-методы, возвращающие DTO и не модифицирующие Entity. ⚠️ Где не надо: * Методы с lazy-loading и последующими модификациями. * Там, где возможно случайное изменение Entity (например, через mapper'ы). 👉 Используйте @Transactional(readOnly = true) не как декор, а как инструмент для оптимизации. 📲 Мы в MAX 👉@BookJava
865
18
🧠 Spring Boot: правильно логируем @ExceptionHandler Сейчас покажу простой, но часто упускаемый момент при обработке ошибок в
🧠 Spring Boot: правильно логируем @ExceptionHandler Сейчас покажу простой, но часто упускаемый момент при обработке ошибок в Spring Boot. Если у вас есть глобальный @ExceptionHandler, убедитесь, что вы не теряете stacktrace при логировании. ❌ Плохо: @ExceptionHandler(MyException.class) public ResponseEntity<String> handle(MyException ex) { log.error("MyException occurred: {}", ex.getMessage()); // stacktrace теряется! return ResponseEntity.status(500).body("Error"); } ✅ Хорошо: @ExceptionHandler(MyException.class) public ResponseEntity<String> handle(MyException ex) { log.error("MyException occurred", ex); // stacktrace будет видно в логе return ResponseEntity.status(500).body("Error"); } 📌 log.error(String, Throwable) — правильный способ логировать исключения. Это позволяет: * Сохранять stacktrace для дебага; * Не терять вложенные причины (getCause()); * Работать с лог-агрегаторами (ELK, Grafana, etc). 💡 Если вы используете Slf4j и формат log.error("message: {}", ex.getMessage()), вы теряете почти всю полезную информацию об ошибке. ⚠️ И не забывайте: глобальные хендлеры — это хорошо, но не глушите все ошибки без разбора. Лучше создавать разные @ExceptionHandler под каждую категорию исключений. 📲 Мы в MAX 👉@BookJava
1 096
19
🧠 Spring Boot: как НЕ попасть в ловушку с @Scheduled и многопоточностью Когда используете @Scheduled для периодических задач
🧠 Spring Boot: как НЕ попасть в ловушку с @Scheduled и многопоточностью Когда используете @Scheduled для периодических задач в Spring Boot, важно понимать: по умолчанию все задачи выполняются в одном потоке. @Scheduled(fixedRate = 5000) public void syncData() { // долгая операция } 📌 Если таких задач несколько или они работают долго — остальные ждут. Это создаёт бутылочное горлышко и приводит к неожиданным задержкам. 💡 Решение: настроить кастомный executor: @Configuration @EnableScheduling public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar registrar) { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(5); // количество параллельных задач scheduler.setThreadNamePrefix("scheduled-task-"); scheduler.initialize(); registrar.setTaskScheduler(scheduler); } } Теперь все @Scheduled - методы будут использовать пул потоков, а не один. ⚠️ Не забывайте: если задача критична к ресурсам или зависит от внешних сервисов — добавьте внутреннюю защиту от повторного выполнения, например, с помощью Redis lock или базы. ✅ Подключение пула — must-have для production-проектов, где @Scheduled выполняет реальные задачи, а не просто println. 📲 Мы в MAX 👉@BookJava
1 001
20
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин https://max.ru/channel_win_sysadmin Системный Администратор Windows https://max.ru/channel_linux_admin Linux: Системный администратор https://max.ru/channel_linuxmod Linux https://max.ru/channel_i_linux Системный администратор https://max.ru/channel_devopslib DevOps, SRE, Sysadmin https://max.ru/channel_devops_star DevOps Star (Звезда Девопса) Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С https://max.ru/channel_DevLab1C 1С:Предприятие 8 Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика https://max.ru/channel_cpp_geek C++ geek Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Rust📌 https://max.ru/channel_rust_lib Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика https://max.ru/channel_java_geek Java Geek GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии в IT📌 https://max.ru/progjob https://max.ru/channel_rabotait Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Городские📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП https://max.ru/channel_krasnodar_novosty Краснодар Новости https://max.ru/channel_novosibirsk_novosti Новосибирск https://max.ru/channel_samara_novosti Новости Самары https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга https://max.ru/channel_kazan_novosti Новости Казани https://max.ru/channel_omsk_novosti Новости Омска https://max.ru/channel_moskva_24 Москва 24
910