TGViewer
Библиотека джависта | Java, Spring, Maven, Hibernate Библиотека джависта | Java, Spring, Maven, Hibernate @javaproglib · 22K subscribers
Post #7658 2.18K
☕️ Как работает @Slf4j

Если пишешь @Slf4j над классом, вызываешь log.info(...) и не задумываешься, а как это работает, то пост для тебя. Разберём, что стоит за аннотацией, и как не напороться на неочевидные грабли.

🔹 Что делает аннотация

@Slf4j аннотация Lombok'а. При компиляции он через annotation processor генерирует в классе поле:
private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(YourClass.class);


Всё, никакой магии в рантайме. Просто кодогенерация на этапе javac. Если открыть .class — поле будет там как родное.

Нюанс: если и родитель, и наследник аннотированы @Slf4j, каждый получит свой собственный логгер, привязанный к своему классу.

🔹 SLF4J — это фасад, а не реализация

Ключевая идея, которую стоит держать в голове: SLF4J сам ничего не логирует. Это API-контракт. Реальная работа на binding'е:

→ Logback — нативный бэкенд, писался теми же людьми
→ Log4j2 — через log4j-slf4j2-impl
→ java.util.logging — через slf4j-jdk14

Binding определяется в classpath в compile/runtime. SLF4J при старте ищет класс org.slf4j.spi.SLF4JServiceProvider (начиная с 2.x) или StaticLoggerBinder (в 1.x). Нашёл — работает. Не нашёл — NOP logger, и ты молча теряешь все логи. В 2.x хотя бы warning кинет.

🔹 Два binding'а в classpath

Классическая проблема транзитивных зависимостей. Если в classpath окажутся и logback-classic, и log4j-slf4j2-impl — SLF4J выберет один (фактически — какой первый найдёт classloader). Поведение недетерминировано. Лечится в Maven через <exclusions> или в Gradle через exclude group.

🔹 Что под капотом вызова

log.info("User {} logged in from {}", username, ip);

Здесь нет конкатенации строк. SLF4J использует параметризованные сообщения — плейсхолдеры {} заменяются лениво, только если уровень логирования активен. Это важно: вызов log.debug(...) при выключенном DEBUG не тратит ресурсы на toString() аргументов.

Но есть подвох. Если ты передаёшь выражение, которое само по себе дорого вычислять:
log.debug("Heavy result: {}", calculateSomethingExpensive());

Метод всё равно вызовется — аргументы вычисляются до передачи в метод (JLS, eager evaluation). Вариант обхода:
if (log.isDebugEnabled()) {
log.debug("Heavy result: {}", calculateSomethingExpensive());
}

Или, если на Log4j2 API напрямую — там есть Supplier-based ленивые аргументы. В SLF4J 2.x появился fluent API:
log.atDebug()
.setMessage("Heavy result: {}")
.addArgument(() -> calculateSomethingExpensive())
.log();


🔹 Логирование исключений

Правильный способ — throwable последним аргументом без плейсхолдера:
log.error("Payment failed for order {}", orderId, exception);

Два {} — нет. Два аргумента — да. SLF4J сам определит, что последний аргумент — Throwable, и выведет стектрейс. Если засунуть exception в {}, получишь только toString() без стектрейса. Это одна из самых частых ошибок.

🔹 Мелочи, на которые стоит обратить внимание

▪️ @Slf4j vs @Log4j2
Lombok умеет генерировать логгеры для разных фасадов/реализаций. @Slf4j — для SLF4J API, @Log4j2 — напрямую для Log4j2 API (со всеми его фичами типа Supplier-аргументов и Markers). Выбирай осознанно.

▪️ Имя логгера

По умолчанию это FQCN класса. Можно переопределить: @Slf4j(topic = "audit"). Удобно для выделения audit/security логов в отдельный appender.

▪️ Serializable классы


Logger не сериализуем. Если класс implements Serializable, после десериализации log будет null. Lombok добавляет transient, но при ручном объявлении — легко забыть.

▪️ Тесты

Если в тестовом classpath нет binding'а, логи молча пропадут. Кинь slf4j-simple в testImplementation / test scope, чтобы видеть что происходит.

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#CoreJava
  • 👍 11
  • 🔥 6
  • ❤ 5
  • ⚡ 1
More from @javaproglib
  1. Oct 13, 2026🧠 Почему BigDecimal считает 2.0 и 2.00 разными Что выведут эти две строки? var a = new Bi…
  2. Oct 12, 2026👀 Как вы смотрите видео? Разбираете урок, слушаете интервью фоном или начинаете на телефо…
  3. Oct 10, 2026Post #7892
  4. Oct 10, 2026Read. Write. Edit. Bash. Это базовый набор операций Pi — агента, на котором построен OpenC…
  5. Oct 2, 2026🎹 Что делать после ChatGPT? Следующий шаг — AI-агенты. Они не просто отвечают на запросы,…
  6. Sep 30, 2026🔥 Последний день для разработчиков AI уже пишет код. Теперь важнее научиться встраивать е…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →