Как slf4j привязывается к реализации? Действительно ли это происходит во время компиляции?

В документации для slf4j говорится, что привязка происходит во время выполнения:

"SLF4J не полагается на какое-либо специальное оборудование загрузчика классов. Фактически, каждая привязка SLF4J жестко привязана во время компиляции, чтобы использовать одну и только одну конкретную структуру ведения журнала. Например, привязка slf4j-log4j12-1.7.5.jar привязывается во время компиляции, чтобы использовать log4j. В вашем коде, помимо slf4j-api-1.7.5.jar, вы просто отбрасываете одно и только одно привязку по вашему выбору в соответствующее место пути класса. Не помещайте более одного привязка к вашему пути к классу. Вот графическая иллюстрация общей идеи". http://www.slf4j.org/manual.html

Как это работает?

Ответ 1

Вот исходный код slf4j.  Slf4j найдет весь класс в пути к классам, путь которого "org/slf4j/impl/StaticLoggerBinder.class". И если их несколько, jvm выберет только один случайным образом. Более подробную информацию вы можете увидеть здесь:http://www.slf4j.org/codes.html#multiple_bindings

// We need to use the name of the StaticLoggerBinder class, but we can't
// reference
// the class itself.

private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

static Set<URL> findPossibleStaticLoggerBinderPathSet() {
 // use Set instead of list in order to deal with bug #138
 // LinkedHashSet appropriate here because it preserves insertion order
 // during iteration
    Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>(); 
    try {
        ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
        Enumeration<URL> paths;
        if (loggerFactoryClassLoader == null) {
            paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
        } else {
            paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
        }
        while (paths.hasMoreElements()) {
            URL path = paths.nextElement();
            staticLoggerBinderPathSet.add(path);
        }
    } catch (IOException ioe) {
        Util.report("Error getting resources from path", ioe);
    }
    return staticLoggerBinderPathSet;
}

Ответ 2

Это был мой вопрос, и я хотел бы добавить свой ответ, так как нашел, что два других ответа недостаточно ясны (хотя они совершенно правильны).

Сначала проверьте эту строку в реализации LoggerFactory.bind() в slf4j-api (ссылка)

// the next line does the binding
StaticLoggerBinder.getSingleton();

Существует класс под названием org.slf4j.impl.StaticLoggerBinder. Проверьте его реализацию на github.

Теперь перейдите и скачайте slf4j-api.jar из центрального репозитория maven, извлеките его и найдите StaticLoggerBinder.class файл.

Не пытайтесь! Вы не можете. Фактически все org.slf4j.impl было удалено из пакета. Проверьте pom.xml проекта:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
      <execution>
        <phase>process-classes</phase>
        <goals>
         <goal>run</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <tasks>
        <echo>Removing slf4j-api dummy StaticLoggerBinder and StaticMarkerBinder</echo>
        <delete dir="target/classes/org/slf4j/impl"/>
      </tasks>
    </configuration>
  </plugin>

Наконец, проверьте один из пакетов связывания SLF4j, например slf4j-simple. Вы можете найти класс org.slf4j.impl.StaticLoggerBinder?

В сумме, когда у вас есть slf4j-api.jar рядом с одним (и только одним) пакетов привязки в вашей среде выполнения, у вас есть только один класс org.slf4j.impl.StaticLoggerBinder, который выполняет привязку.

Ответ 3

Из того, что я видел, он делает это, ожидая, что класс StaticLoggingBinder будет в одном пакете (org.slf4j.impl), независимо от реализации, поэтому он всегда находит его в одном и том же месте.

Ответ 4

Технически, во время компиляции нет волшебной "привязки". "Связывание" произошло, когда разработчики SLF4J создали библиотеки для обработки самых популярных фреймворков регистрации Java.

Когда документы говорят, что "привязка жестко привязана во время компиляции", это означает, что разработчики SLF4J создали целевую библиотеку для конкретной структуры ведения журнала Java. В SLF4J есть библиотеки, посвященные Java Logging, Jakarta Commons Logging, Log4J и вывод консоли. Вам нужно будет включить только одну из этих библиотек во время выполнения, чтобы SLF4J успешно создавал сообщения журнала.

Для получения дополнительной информации о том, как работает SLF4J: Более визуальный способ понять SLF4J.

Ответ 5

Это так же, как сказал @Rad.

Что я хочу пополнить, так это то, что если в вашей среде выполнения есть несколько орудий StaticLoggerBinder, slf4j выбирает одно из них RANDOMLY, как сказано в множественных привязках:

Способ, которым SLF4J выбирает привязку, определяется JVM и для всех практических целей должен рассматриваться как случайный. Начиная с версии 1.6.6, SLF4J будет называть фреймворк/класс реализации, с которым он на самом деле связан.

Еще одно внимание: если ваш проект планируется использовать в качестве библиотеки для других проектов, следует включать только slf4j-api, любая реализация для slf4j-api не допускается:

Встроенные компоненты, такие как библиотеки или платформы, не должны объявлять зависимость от какой-либо привязки SLF4J, а зависят только от slf4j-api. Когда библиотека объявляет зависимость времени компиляции от привязки SLF4J, она накладывает эту привязку на конечного пользователя, тем самым отрицая назначение SLF4J.

Ответ 6

Реализация не связана во время компиляции (это не статическая/ранняя привязка) или, другими словами, реализация , которая не известна во время компиляции.

На самом деле это наоборот , где реализация связана во время выполнения, что означает, что реализация обнаруживается посредством динамического/динамического связывания. Люди из Slf4j на самом деле объявили о том, как происходит связывание, в своем руководстве https://www.slf4j.org/manual.html:

SLF4J позволяет конечному пользователю подключить желаемую структуру ведения журналов во время развертывания.