Глубокое понимание системы ведения журналов Java, никогда больше не заблудитесь

Java
Глубокое понимание системы ведения журналов Java, никогда больше не заблудитесь

Ставьте лайк и смотрите снова, вырабатывайте привычку, ищите в паблике [дайм тек] Обратите внимание на более оригинальные технические статьи. эта статьяGitHub org_hejianhui/JavaStudyБыл включен, есть моя серия статей.

предисловие

Ведение журнала является неотъемлемой частью приложения. Онлайн-отслеживание проблем, статистический анализ бизнес-логики на основе журналов и т. д. — все это неотделимо от журналов. В области java существует множество фреймворков журналов, в настоящее время наиболее часто используемые фреймворки журналов включают Log4j 1, Log4j 2, Commons Logging, Slf4j, Logback и Jul. Но как использовать фреймворк логирования в нашей системе? Вас все еще беспокоят сложные отношения между commons-logging.jar, log4j.jar, sl4j-api.jar и другими фреймворками ведения журналов? Вы все еще не знаете, как унифицировать вывод журнала системы? Например, если вы хотите изменить вывод журнала Spring на Log4j 2, но не знаете, какие пакеты jar импортировать, вы знаете только, как зайти в так называемый блог Baidu и скопировать его в соответствии с другими, но вы можете' не понял принцип? Эта статья позволит понять принцип, пока вы успокоитесь и прочитаете эту статью, вы можете изменить структуру журнала в своей системе, как вам нравится, и унифицировать вывод журнала!

Категория фреймворка журнала

структура регистрации

  1. Jul(Java Util Logging): инструмент ведения журнала в JDK, также известный как JDKLog, jdk-logging, официальная реализация журнала, начиная с Java 1.4.
  2. Log4j: Apache Log4j — это инструмент ведения журнала на основе Java. Он был разработан Ceki Gülcü и теперь является проектом Apache Software Foundation. Log4j — одна из нескольких сред ведения журналов Java.
  3. Log4j2: конкретная структура реализации журнала, следующая версия Log4j 1, претерпела большие изменения с Log4j 1,Log4j 2 несовместим с Log4j 1.
  4. Logback: Специфический фреймворк реализации лога, тот же автор, что и Slf4j, но его производительность лучше (Рекомендуемое использование).

Фреймворк регистрации фасада

  1. JCL: проект, принадлежащий Apache Foundation, который представляет собой набор интерфейсов ведения журналов Java, ранее называвшийся Jakarta Commons Logging, а затем переименованный в Commons Logging.
  2. SLF4J: представляет собой набор простых фасадов журналов Java,Реализация без регистрации. (Простой фасад ведения журнала для Java, сокращенно Slf4j)

Чувствуете ли вы себя сбитым с толку, когда видите так много фреймворков? В чем сходство и различие между этими фреймворками? Кто их поддерживает? Как выбрать фреймворк для логирования в проекте и как его использовать? Сначала произведите впечатление . Давайте сначала разберемся в истории их развития.

История каркаса журнала

Жалобы и жалобы журнала Java

  • В начале 1996 года проектная группа European Security Electronic Market решила написать собственный API трассировки программ (Tracing API). После постоянного улучшения этот API наконец стал очень популярным пакетом ведения журналов Java, а именно Log4j (созданный Ceki).
  • Позже Log4j стал участником проекта Apache Foundation, а Ceki также присоединился к организации Apache. Позже Log4j почти стал стандартом ведения журналов в сообществе Java. Говорят, что Apache Foundation однажды предложила Sun ввести Log4j в стандартную библиотеку Java, но Sun отказалась.
  • В 2002 году, когда была выпущена Java 1.4, Sun запустила собственную библиотеку протоколирования JUL (Java Util Logging), реализация которой в основном имитировала реализацию Log4j. До выхода JUL Log4j стала зрелой технологией, что давало Log4j определенное преимущество при выборе.
  • Затем Apache запустил Jakarta Commons Logging, JCL просто определяет набор интерфейсов журналов (он также обеспечивает простую реализацию Simple Log внутри), который поддерживает реализацию динамической загрузки компонентов журнала во время выполнения, то есть в коде вашего приложения, Просто вызовите интерфейс Commons Logging, и базовой реализацией может быть Log4j или Java Util Logging.
  • Позже (в 2006 году) Чеки покинул Apache, не адаптировавшись к тому, как работает Apache. Затем я создал два проекта, Slf4j (интерфейс фасада журнала, аналогичный Commons Logging) и Logback (реализация Slf4j), и вернулся в Швецию, чтобы создать компанию QOS.Официальный сайт QOS описывает Logback следующим образом: Общий, надежный, быстрый & Гибкая структура ведения журнала (универсальная, надежная, быстрая и гибкая структура ведения журнала).
  • Поле регистрации Java разделено на два лагеря: лагерь Commons Logging и лагерь Slf4j.
  • Commons Logging имеет большую базу пользователей под капотом дерева Apache. Но есть свидетельства того, что форматы меняются. В конце 2013 года кто-то проанализировал 30 000 проектов на GitHub и насчитал 100 самых популярных библиотек, видно, что тенденция развития у Slf4j лучше.
  • Увидев, что у Apache есть импульс, чтобы Logback обогнал его, он переписал Log4j 1.x в 2012-07 годах и создал новый проект Log4j 2, который имеет все функции Logback.

Великий Бог Чеки

log4j

В первые годы, когда вы работали, вы использовали фреймворк log4j для вывода в журнал, поэтому ваш код был написан так:

import org.apache.log4j.Logger;
//省略...
Logger logger = Logger.getLogger(Test.class);
logger.trace("trace");
//省略...

jul

Однако по прошествии лет компания Sun слегка завидовала появлению log4j. Итак, после версии jdk1.4 пакет был добавлен какjava.util.logging, Упоминается какjul, для борьбы с log4j. Итак, ваш лидер хочет, чтобы вы изменили структуру ведения журнала на jul. В настоящее время вы можете только изменить API log4j на API jul построчно, как показано ниже:

import java.util.logging.Logger;
//省略...
Logger loggger = Logger.getLogger(Test.class.getName()); 
logger.finest("finest");
//省略...

Как видно, API совершенно другое. Есть ли способ абстрагировать эти API от интерфейсов, чтобы при их последующем вызове можно было просто вызывать эти интерфейсы?

jcl

В это время появился jcl (Jakarta Commons Logging), говорящий о том, что jcl может быть всем немного незнаком, а говоря о компоненте commons-logging-xx.jar, у всех должно быть впечатление. JCL предоставляет только интерфейс журнала, а конкретная реализация находится динамически во время выполнения. Таким образом, разработчикам компонентов нужно разрабатывать только интерфейс JCL, а приложение, вызывающее компонент, может использовать свои любимые практические инструменты ведения журналов во время выполнения. Схема интеграции, которую может реализовать JCL, показана на следующем рисунке.Конфигурация jcl по умолчанию: если Log4j можно найти, по умолчанию используется реализация log4j, если нет, используется реализация jul (встроенная jdk) и реализация SimpleLog, предоставленная внутри jcl.

Итак, вы пишете это в коде

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//省略...
Log log =LogFactory.getLog(Test.class);
log.trace('trace');
//省略...

Что касается конкретного класса реализации этого журнала, JCL будет искать его в ClassLoader. В этом есть три недостатка:

  • Недостатком является низкая эффективность
  • Во-вторых, легко ввести в заблуждение.
  • В-третьих, в программе, использующей собственный ClassLoader, использование JCL приведет к утечке памяти.

slf4j

Итак, автор log4j (Ceki) посчитал, что jcl неудобен в использовании, поэтому он написал новый интерфейс api, тогда это был slf4j.

Нам нужно писать логи в коде, который становится следующим

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//省略...
Logger logger = LoggerFactory.getLogger(Test.class);
//省略...
logger.info("info");

В коде API конкретного фреймворка ведения журналов не отображается. Программа определяет, в какой кадр logger.info следует выводить, в соответствии с типом моста в пути к классам и типом кадра журнала! Обратите внимание, что если два моста случайно появляются в пути к классам, об ошибке будет сообщено напрямую!

Поэтому в руководстве по разработке Али есть только такая строчка.

Обязательно: API в системе ведения журналов (log4j, logback) нельзя использовать напрямую в приложении, но следует полагаться на API в фреймворке ведения журналов SLF4J. Использование бревенчатого каркаса фасадного режима способствует унификации методов обслуживания и обработки бревен различных классов.

Использование Slf4j

Описание связи между Slf4j и другими компонентами журнала

  • Идея дизайна Slf4j относительно проста и использует шаблон проектирования Facade.Сам Slf4j предоставляет только пакет slf4j-api-version.jar.Этот jar в основном является абстрактным интерфейсом журнала, а сам jar не реализует абстрактный интерфейс.
  • Для различных схем реализации журнала (например, Logback, Log4j...) инкапсулируйте различные компоненты моста (например, logback-classic-version.jar, slf4j-log4j12-version.jar), чтобы вы могли гибко выбирать себя во время использования. внедрение лога в проект.

Схема интеграции Slf4j с другими компонентами журнала

Как показано на рисунке, приложение вызывает sl4j-api, т.е.интерфейс бревенчатого фасада. Сам интерфейс логфасада обычно не имеет собственно возможности вывода лога, ему все равно нужно вызывать API конкретного логфреймворка на нижнем уровне, то есть, по сути, его нужно использовать в сочетании с конкретным логфреймворком. Поскольку существует множество конкретных бревенчатых каркасов, и большинство из них несовместимы друг с другом, для интерфейса бревенчатого фасада могут потребоваться соответствующие мосты, если он должен быть объединен с любым бревенчатым каркасом.Компоненты в красной рамке на приведенном выше рисунке являются соответствующими мосты!

Инструкции по соединению Slf4j с различными другими компонентами ведения журнала

имя пакета jar иллюстрировать
slf4j-log4j12-1.7.30.jar Для версии моста Log4j1.2 необходимо добавить Log4j.jar в путь к классам.
slf4j-jdk14-1.7.30.jar Мост java.util.logging, собственной среды ведения журналов Jdk.
slf4j-nop-1.7.30.jar Мост NOP, молча отбрасывающий все журналы.
slf4j-simple-1.7.30.jar Мост с простой реализацией, который выводит все события в System.err, печатаются только Info и сообщения выше этого уровня, что может быть полезно в небольших приложениях.
slf4j-jcl-1.7.30.jar Мост для ведения журналов Jakarta Commons.Этот мост делегирует все журналы Slf4j в Jcl.
logback-classic-1.0.13.jar(requires logback-core-1.0.13.jar) Нативная реализация Slf4j, Logback, напрямую реализует интерфейс Slf4j, поэтому использование Slf4j в сочетании с Logback также означает меньше памяти и вычислительных ресурсов.

Обратитесь к рисунку ниже для конкретных методов вмешательства

Анализ исходного кода Slf4j

Несколько основных классов и интерфейсов в slf4j-api-version.jar

Классы и интерфейсы использовать
org.slf4j.LoggerFactory(class) Фабричный класс для создания Logger, предоставленный вызывающей стороне, и привязка конкретного компонента реализации журнала во время компиляции.
org.slf4j.Logger(interface) Регистрация абстрактных методов, предоставляемых вызывающей стороне, таких как debug(String msg), info(String msg) и другие методы.
org.slf4j.ILoggerFactory(interface) Заводской интерфейс полученного Logger, конкретный компонент log реализует этот интерфейс
org.slf4j.helpers.NOPLogger(class) Неактивная реализация интерфейса org.slf4j.Logger, которая также является реализацией ведения журнала по умолчанию для Slf4j.
org.slf4j.impl.StaticLoggerBinder(class) Класс моста, реализованный определенным компонентом реализации журнала. Конкретный компонент реализации журнала должен определить пакет org.slf4j.impl и предоставить этот класс в пакете org.slf4j.impl. Обратите внимание, что он не существует в slf4j-api- version.jar org.slf4j.impl.StaticLoggerBinder, существующий только в исходном пакете slf4j-api-version-source.jar

Анализ исходного кода процесса вызова Slf4j, добавьте только slf4j-api-version.jar, не добавляйте пакет реализации

конфигурация пом

<!--只有slf4j-api依赖-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>

Класс входа в программу

package com.niuh;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {
    final static Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        logger.info("Hello World");
    }
}

Анализ отслеживания исходного кода

  1. Вызовите метод getLogger() LoggerFactory, чтобы создать Logger.

  1. Вызовите метод getILoggerFactory LoggerFactory, чтобы создать ILoggerFactory.

  1. Вызовите метод executeInitialization LoggerFactory для инициализации

  1. Вызов метода bind() LoggerFactory

  1. Вызовите метод findPossibleStaticLoggerBinderPathSet() LoggerFactory, чтобы получить набор StaticLoggerBinderPath.

  1. Вызовите метод reportMultipleBindingAmbiguity() класса LoggerFactory для записи связанной информации StaticLoggerBinder.

  1. Метод ReportMultipleBindingAmbiguity() LoggerFactory

  1. Метод bind() LoggerFactory не может найти StaticLoggerBinder и выдает исключение NoClassDefFoundError.

  1. Метод bind() LoggerFactory перехватывает исключение NoClassDefFoundError, сопоставляет ключевое слово StaticLoggerBinder и записывает информацию в консоль.

  1. Метод PerformInitialization() LoggerFactory вызывает внутренний метод bind() для завершения

  1. Вызывается метод getILoggerFactory() в методе getLogger() LoggerFactory, создается NOPLoggerFactory, а затем NOPLoggerFactory вызывает внутренний метод getLogger() для создания NOPLogger.

  1. Регистратор внутри класса App на самом деле является NOPLogger, и вызов метода logger.info() фактически вызывает метод информации NOPLogger.

Анализ исходного кода процесса вызова Slf4j, добавление компонентов slf4j-api-version.jar и Logback.

Slf4j использует Logback в качестве фасада или использует другие компоненты, упомянутые выше, в качестве реализации Здесь в качестве реализации используется только компонент Logback.

конфигурация пом

<dependencies>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.30</version>
    </dependency>
    <!--logback-classic依赖logback-core,会自动级联引入-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>
</dependencies>

Класс входа в программу

То же

Анализ отслеживания исходного кода

  • 1, 2, 3, 4 как указано выше
    1. Вызовите метод findPossibleStaticLoggerBinderPathSet() LoggerFactory, чтобы получить набор StaticLoggerBinderPath.

    1. Вызовите назначение объекта коллекции staticLoggerBinderPathSet метода bind() LoggerFactory.

    1. Вызовите StaticLoggerBinder в пакете loback в методе bind() LoggerFactory, чтобы создать одноэлементный объект.

    1. Вызов reportActualBinding() в методе bind() LoggerFactory для записи информации о загрузке журнала.

    1. Значение INITIALIZATION_STATE в LoggerFactory равно SUCCESSFUL_INITIALIZATION, а одноэлементный объект StaticLoggerBinder вызывается для получения ILoggerFactory.

    1. В настоящее время ILoggerFactory, полученный в методе getLogger() в LoggerFactory, на самом деле является LoggerContext в банке logback.

    1. В настоящее время Logger, полученный LoggerFactory, вызывающим метод getLogger(), на самом деле является Logger в банке logback.

  • конечный результат

Slf4j вызовите анализ исходного кода процесса, добавьте slf4j-api-version.jar и добавьте различные компоненты реализации журнала.

В проекте, если slf4j-api используется в качестве фасада журнала, одновременно существует несколько компонентов реализации журнала, таких как Logback, slf4j-log4j12, slf4j-jdk14 и slf4j-jcl. будет определяться JVM, и оно будет случайным, что не будет соответствовать ожиданиям.Такой ситуации нужно избегать в процессе фактического использования.

конфигурация пом

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.30</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-jdk14</artifactId>
      <version>1.7.30</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-jcl</artifactId>
      <version>1.7.30</version>
    </dependency>
</dependencies>

Класс входа в программу

То же

Анализ отслеживания исходного кода

  • Основные шаги такие же, как и выше, здесь отслеживаются только основные отличия
  • (1) После вызова метода findPossibleStaticLoggerBinderPathSet() внутри метода bind() трассировки LoggerFactory найдите StaticLoggerBinder из 4 пакетов jar в пути к классам.

  • (2) В это время метод bind() LoggerFactory внутренне вызывает метод reportMultipleBindingAmbiguity(), выдавая предупреждающее сообщение о том, что в пути к классам одновременно есть несколько StaticLoggerBinder, и JVM случайным образом выберет StaticLoggerBinder

Как связать устаревший API при использовании Slf4j

В реальной среде мы часто сталкиваемся с разными платформами ведения журналов, используемыми разными компонентами.Например, компонент ведения журнала, используемый Spring Framework, — это Commons Logging, а XSocket полагается на Java Util Logging. Когда мы используем разные компоненты в одном проекте, должны ли мы решать несогласованность компонентов журнала, от которых зависят разные компоненты? Теперь нам нужно унифицировать схему журнала, использовать Slf4j единообразно, перенаправить их вывод журнала в Slf4j, а затем Slf4j передаст журнал конкретному инструменту реализации журнала в соответствии с связующим. Slf4j поставляется с несколькими модулями моста, которые могут перенаправлять Log4j, JCL и API в java.util.logging на Slf4j.

Устаревшая схема сопряжения API

имя пакета jar эффект
log4j-over-slf4j-version.jar Перенаправить Log4j на Slf4j
jcl-over-slf4j-version.jar Перенаправить Simple Logger в Commons Logging на slf4j
jul-to-slf4j-version.jar Перенаправить ведение журнала Java Util на Slf4j

Обратитесь к рисунку ниже для метода перемычки

Заметки о соединении с Slf4j

При использовании моста Slf4j обратите внимание на то, чтобы избежать образования бесконечного цикла.Следующие ситуации не должны существовать в пакете jar, от которого зависит проект.

Условия для нескольких пакетов журналов для формирования бесконечного цикла причина
И log4j-over-slf4j.jar, и slf4j-log4j12.jar существуют. Все вызовы журналирования делегируются log4j из-за наличия slf4j-log4j12.jar. Однако из-за одновременного существования log4j-over-slf4j.jar все вызовы log4j API будут делегированы соответствующему эквивалентному slf4j, поэтому существование log4j-over-slf4j.jar и slf4j-log4j12.jar при этом будет образовываться бесконечный цикл
И jul-to-slf4j.jar, и slf4j-jdk14.jar существуют Из-за существования файла slf4j-jdk14.jar все вызовы журнала будут делегированы журналу jdk. Однако из-за одновременного существования jul-to-slf4j.jar все вызовы jul API будут делегированы соответствующему эквиваленту slf4j, поэтому сосуществование jul-to-slf4j.jar и slf4j-jdk14. jar образует бесконечный цикл

Сравнение механизма реализации JCL и Slf4j

Представленные ранее интерфейсные среды ведения журналов в основном включают две JCL (Commons Logging) и Slf4j, Давайте кратко разберемся в их различиях:

Механизм реализации JCL (Commons Logging)

JCL (Commons Logging) использует собственный ClassLoader для поиска и загрузки конкретных локальных реализаций с помощью механизма динамического поиска во время работы программы. Подробные политики см. в файле org.apache.commons.logging.impl.LogFactoryImpl.java в пакете commons-logging-*.jar. Поскольку разные подключаемые модули Osgi используют независимые загрузчики классов, этот механизм Osgi гарантирует, что подключаемые модули не зависят друг от друга, и его механизм ограничивает нормальное использование Commons Logging в Osgi.

Механизм реализации Slf4j

Во время компиляции Slf4j статически связывает локальную библиотеку журналов, поэтому ее можно нормально использовать в Osgi. Это достигается путем нахождения org.slf4j.impl.StaticLoggerBinder в пути к классам, а затем привязки в StaticLoggerBinder.

бревно боевое

Дело номер один

В проекте один модуль использует log4j, а другой модуль использует slf4j+log4j2, как унифицировать вывод?

На самом деле, в некоторых малых и средних компаниях такая ситуация очень распространена. Я видел проект определенной компании, потому что исследования и разработки не понимают лежащего в основе принципа журнала, файл журнала содержит как log4j.properties, так и log4j2.xml, и смешаны различные API, что ужасно!

Некоторые люди используют API jul, а затем берут log4j.properties, приходят ко мне и спрашивают, почему конфигурация не действует! Это не передать словами!

Хорошо, вернемся к нашему вопросу, как унифицировать вывод! Хорошо, здесь используется адаптер slf4j, который предоставляет множество адаптеров для делегирования определенной структуры ведения журналов в slf4j. Наиболее очевидными способами интеграции являются следующие:Заполните пробелы и заполните условия в нашем случае По смыслу вопроса должен быть выбран адаптер log4j-over-slf4j, поэтому получается следующая картина

Лог можно унифицировать как log4j2 для вывода!

PS:В зависимости от принципа работы адаптера адаптированный фреймворк логирования удалять не нужно! В качестве примера возьмем приведенное выше изображение. Структура журнала log4j может быть удалена или нет, если вы можете убедиться, что порядок загрузки log4j следующий после log4j-over-slf4j. Поскольку принцип работы адаптера log4j-over-slf4j заключается в том, что он внутренне предоставляет тот же интерфейс API, что и log4j, поэтому, когда вы вызываете API log4j в своей программе, вы должны найти способ заставить его пройти через API адаптера. Если вы удалите структуру log4j, ваша программа должна использовать API в компоненте log4j-over-slf4j. Если вы не удаляете log4j, просто убедитесь, что его порядок в classpth выше, чем до log4j!

Случай 2

Как я могу заставить Spring выводить как log4j2?

Spring использует jcl для вывода журналов по умолчанию.Поскольку в настоящее время вы не представили структуру ведения журнала Log4j, jcl будет использовать jul в качестве среды ведения журнала. Схема интеграции выглядит следующим образомВ вашем приложении для логирования используется slf4j+log4j-core, то есть log4j2, тогда схема интеграции такаяИтак, теперь нам нужно, чтобы Spring выводил в виде log4j2? что делать?

Хорошо, первое решение — использовать адаптер jcl-over-slf4j.На данный момент схема интеграции выглядит следующим образом.В этой схеме, когда оператор вывода журнала встречается в структуре Spring, он будет выводиться в форме log4J2, как показано в процессе красной строки выше!

Хорошо, есть второй вариант?

Да, берите переходник jul-to-slf4j, схема интеграции такая

PS:В этом случае не забудьте выполнить в коде

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

Таким образом, адаптер jul-to-slf4j может работать правильно.Для получения подробной информации вы можете проверить принцип работы адаптера.

Случай 3

Предположим, мы вызываем sl4j-api в приложении, но вы привели четыре jar-пакета, slf4j-api-xx.jar, slf4j-log4j12-xx.jar, log4j-xx.jar, log4j-over-slf4j -xx.jar. , то у вас будет следующая неловкая сцена

Как показано на рисунке выше, в этом случае, если вы вызовете slf4j-api, вы попадете в бесконечный цикл! slf4j-api вызывает slf4j-log4j12, slf4j-log4j12 вызывает log4j, а log4j вызывает log4j-over-slf4j. В итоге log4j-over-slf4j снова подправил slf4j-api и попал в бесконечный цикл!

Разница в журналах spring4 и spring5

Система логирования Spring4

Создайте проект spring, используйте аннотацию java для быстрой сборки и вставьте только пакет spring-context в pom.

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.21.RELEASE</version>
    </dependency>
</dependencies>

Запустите следующий код, вы можете увидеть вывод журнала

public class MainClass {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

Найдите место для печати журнала, в режиме отладки проверьте журнал вывода.Видно, что это jdk14Logger, о котором говорится в JCL, это относится к JUL, то есть в системе журнала Spring по умолчанию используется JUL.

Далее вводим log4j по предыдущему методу, отлаживаем и запускаем вышеуказанную программу, и снова проверяем тип лога

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

Ну, на этот раз, в случае добавления пакета log4j jar и файла конфигурации, spring4 использовал log4j, так что это похоже на JCL, дерево неправильно, давайте откроем структуру зависимостей журнала spring4 в идее:Разве пакет common-loging не используется JCL? Видно, что Spring4 использует собственный JCL, поэтому log4j используется для печати журналов, когда log4j доступен, а JUL используется для печати журналов, когда он недоступен.

Система журналов Spring5

Схема структуры зависимостей:

Общая структура не изменилась, за исключением того, что оригинальный common-logging был заменен на spring-jcl. Из названия видно, что это пакет, созданный spring, jcl, и он помечен. Он использует ведение журнала JCL. система.

Мы по-прежнему проверяем, глядя на исходный код.Мы используем только отладку, чтобы найти журнал весной, чтобы увидеть, как он генерируется и его тип. На этот раз я нашел место, где журнал генерируется в AbstractApplicationContext

Введите getLog() этого метода, углубитесь и найдите метод createLog() в LogAdapter.Видно, что производство логов в Spring 5 не использует массив как в нативном JCL, а затем генерирует его в цикле.Здесь используется случай Switch.В какой части присваивается ключевое поле logApi? Следующее:Мы видим, что значение присваивается в блоке статического кода, для проверки мы собираемся использовать упомянутый в нем log4j2 для проверки (примечание: log4j невозможен, т.к. переключатель здесь не имеет опции log4j), сначала подготавливаем конфигурационный файл log4j2.xml

<Configuration status="WARN">

    <Appenders>

        <Console name="Console" target="SYSTEM_OUT">

            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

        </Console>

    </Appenders>

    <Loggers>

        <Root level="debug">

            <AppenderRef ref="Console"/>

        </Root>

    </Loggers>

</Configuration>

Затем подготовьте зависимости pom

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.10.0</version>
    </dependency>
</dependencies>

запустите код ниже

public class MainClass {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

В результате распечатывается журналИтак, в Spring5 по-прежнему используется JCL, но не нативный,Это модифицированный JCL, по умолчанию JUL, тогда как log4j используется по умолчанию в собственном JCL.

Выберите выбор каркаса журнала в проекте

Если он находится в новом проекте, рекомендуется использоватьSlf4j и логбэкВ совокупности это дает следующие преимущества.

  • Механизм реализации Slf4j определяет, что Slf4j имеет меньше ограничений и более широкий диапазон использования. Поскольку Slf4j статически связывает локальную библиотеку LOG во время компиляции, его универсальность лучше, чем Commons Logging.

  • Logback имеет лучшую производительность. Logback утверждает, что производительность некоторых ключевых операций, таких как определение того, следует ли регистрировать оператор журнала, была значительно улучшена. Эта операция занимает 3 наносекунды в Logback и 30 наносекунд в Log4J. LogBack также создает регистраторы быстрее: 13 мс по сравнению с 23 мс в Log4J. Более того, для извлечения существующего регистратора требуется всего 94 наносекунды по сравнению с 2234 наносекундами для Log4J, что сокращает время до 1/23. Улучшение производительности по сравнению с JUL также значительно.

  • Commons Logging дороже

# 在使Commons Logging时为了减少构建日志信息的开销,通常的做法是
if(log.isDebugEnabled()){
  log.debug("User name: " +
    user.getName() + " buy goods id :" + good.getId());
}

# 在Slf4j阵营,你只需这么做:
log.debug("User name:{} ,buy goods id :{}", user.getName(),good.getId());

# 也就是说,Slf4j把构建日志的开销放在了它确认需要显示这条日志之后,减少内存和Cup的开销,使用占位符号,代码也更为简洁
  • Документация по журналу бесплатна. Вся документация Logback полностью предоставляется бесплатно, в отличие от Log4J, который предоставляет только часть бесплатной документации и требует от пользователей покупки платной документации.

использованная литература

Статья постоянно обновляется, можно поискать на официальном аккаунте »дайм тек"Прочитайте впервые эту статью GitHuborg_hejianhui/JavaStudyОн был записан, добро пожаловать в Star.