2017-02-12 22 views
6

Я учусь Java, и я считаю, что есть много функциональных возможностей, которые стандартизированы:Как SLF4J/JPA/JAX-RS находят их реализацию?

  • вход (с использованием SLF4J)
  • Стойкости (с использованием JPA)
  • REST (с использованием JAX-RS)
  • SOAP (с использованием JAX-WS)
  • т.д.

Давайте возьмем пример Sl4j: правильно использовать его с log4j, мы необходимо импортировать sl4j api, sl4j/log4j bridge и реализацию log4j.

Вопрос: В моем классе я общаюсь только с API-интерфейсом Slf4j.

Как мое приложение знает о реализации log4j? Может кто-нибудь объяснить, что происходит именно под капотом?

С уважением

+0

Вы говорите о модуле log4j-over-slf4j? – Andremoniy

+0

В моем случае, чтобы использовать 'log4j' через' slf4j', у меня есть следующие JAR: 'slf4j-api',' log4j-core' и 'log4j-sl4j-impl' – Kevin

+1

Возможный дубликат [Как slf4j связывается с реализация? Действительно ли это происходит во время компиляции?] (Http://stackoverflow.com/questions/17829995/how-does-slf4j-bind-to-implementation-does-it-really-do-so-during-compile-time) – sm4

ответ

4

ОП задает общий вопрос о том, как внедрение вводится в некоторых разных случаях.

Вход

Как насыщены во многих ответах, то SLF4J дает интерфейс и log4j-slf4j дает реализацию.

При использовании следующее заявление:

import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory; 
    ... 
    private static final Logger LOG = LoggerFactory.getLogger(FooBarClass.class); 
    ... 
    LOG.debug("Foobar"); 

Это то, что происходит:

Мы стараемся, чтобы получить Logger от getLogger метода, объявленного в LoggerFactory class:

public static ILoggerFactory getILoggerFactory() { 
     if (INITIALIZATION_STATE == UNINITIALIZED) { 
      synchronized (LoggerFactory.class) { 
       if (INITIALIZATION_STATE == UNINITIALIZED) { 
        INITIALIZATION_STATE = ONGOING_INITIALIZATION; 
        performInitialization(); 
       } 
      } 
     } 
     switch (INITIALIZATION_STATE) { 
     case SUCCESSFUL_INITIALIZATION: 
      return StaticLoggerBinder.getSingleton().getLoggerFactory(); 
     } 
     ... 
    } 

Так магия происходит в этом заявлении:

return StaticLoggerBinder.getSingleton().getLoggerFactory(); 

Потому что путь к классу знает, что вы реализовали почему, реализация StaticLoggerBinderis provided by log4j. Как мы можем заметить, log4j предоставляет свою собственную реализацию:

private final ILoggerFactory loggerFactory; 
... 
private StaticLoggerBinder() { 
    loggerFactory = new Log4jLoggerFactory(); 
} 

И это все!

Постоянство

Для JPA/Hibernate части, вы должны включить hibernate-jpa-api и hibernate-* (ядро, EntityManager и т.д.).

Допустим, вы хотите создать EntityManagerFactory:

import javax.persitence.EntityManagerFactory 
    import javax.persitence.Persistence; 
    ... 
    private static EntityManagerFactory EMF = Peristence.createEntityManagerFactory("foobar", null); 

Что касается List и ArrayList, ваш пути к классам подаются с интерфейсом и реализацией благодаря баночке вы импортируете.

EntityManagerFactory происходит от hibernate-jpa-api, где у нас есть Persistence class. Мы можем заметить, что метод createEntityManagerFactory сначала перечисляет всех поставщиков и для каждого из них увольняется createEntityManagerFactory. Здесь наступает hibernate. Он предоставляет HibernatePersistenceProvider, что implements the PersistenceProvider class.

Вот как вводится Hibernate.

2

Если говорить о работе с slf4j лесорубов, как:

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooClass.class); 

, то это довольно просто: org.slf4j.Logger это просто интерфейс, который имеет несколько реализаций. В случае библиотеки использования slf4j-log4j12, этот интерфейс реализован классом org.slf4j.impl.Log4jLoggerAdapter который внутри содержит

final transient org.apache.log4j.Logger logger;

Так просто адаптер, который оборачивает ваши запросы лесозаготовительных и вызывать их на log4j регистратора объекта:

public void debug(String msg) { 
    logger.log(FQCN, Level.DEBUG, msg, null); 
} 

В частности, надлежащее исполнение Logger произведено LoggerFactory, которое вначале создает Log4jLoggerFactory через

StaticLoggerBinder.getSingleton().getLoggerFactory() 

, последний создает необходимый Log4jLoggerAdapter экземпляр.


Обычно он работает через уровень адаптации, как изображен на Img из documentation:

enter image description here

2

Slf4j может быть использован с log4j или любой другой основными каротажной библиотекой.

В случае log4j он использует log4j-slf4j-impl.jar, который содержит необходимые классы для общения с библиотекой log4j.

Согласно documentation -

SLF4J не решает реализацию протоколирования при исполнении, но непосредственно в компиляции с мостиком API. Поэтому больше, чем JAR SLF4J, вам понадобятся следующие JAR: мостовой JAR и JAR . Вот что вы получаете с Log4J:

Slf4j-log4j Integration

1

Руководство SLF4J относится к тому, как под обручем SLF4J находит реализацию в использовании: Binding with a logging framework at deployment time.

SLF4J относится вещь, которая позволяет использовать реализацию (Logback, Log4J и т.д ...), как "SLF4J привязок":

Как уже упоминалось ранее, SLF4J поддерживает различные рамки протоколирования. Распределение SLF4J с несколькими файлами jar, называемыми «Связи SLF4J», с каждой привязкой, соответствующей поддерживаемой платформе .

У вас есть столько привязок SLF4J, сколько реализация SLF4J. И конечно, API реализация может иметь различные «SLF4J привязки», согласно его версии:

Для переключения рамки протоколирования, просто замените SLF4J привязки на вашем класса пути. Например, чтобы переключиться с java.util.logging на log4j, просто замените slf4j-jdk14-1.7.22.jar на slf4j-log4j12-1.7.22.jar.

Связывание с реализацией не выполняется во время выполнения, но во время компиляции: каждая привязка SLF4J жестко связана во время компиляции, чтобы использовать одну и только одну конкретную структуру ведения журнала.
Таким образом, вы должны просто включать SLF4J связывание в пути к классам (например, SLF4J-jdk14-1.7.22.jar), так что SLF4J использует его:

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

Вот почему обычно не рекомендуется размещать более одного связывания SLF4J на пути к классам, поскольку SLF4J не предназначен для выбора реализации во время выполнения.