Статьи

Управление неуправляемыми компонентами в CDI

Во время этих (очень заслуженных) отпусков я работал над моим любимым проектом, который использует CDI с реализацией Weld и SLF4J с реализацией Logback .

Условия проблемы были очень просты: я хотел, чтобы журналы моего приложения отображались в таблице Swing, то есть приложение Logback должно было записывать в таблицу. Управление таблицей осуществлялось в CDI, но не было приложения: это не было неожиданностью, поскольку во многих средах старшего поколения управление жизненным циклом осуществляется самостоятельно. До сервлетов JEE6, приложений Log4J и действий Struts все имели собственное управление жизненным циклом, полностью не связанное с CDI. Хуже того, структуры внедрения зависимостей в значительной степени несовместимы друг с другом (приходит на ум Spring) и нуждаются в адаптере для связи между их контекстами, поэтому этот вариант использования является распространенным.

Моим первым шагом было начать самозагрузку Logback, но поскольку Weld использует SLF4J под крышкой, я не нашел пути. Через некоторое время был сделан вывод, что CDI не предоставляет средств для внедрения моей управляемой таблицы в приложение Logback. Это был печальный вывод, но я на этом не остановился: когда спецификация не отвечает вашим потребностям, переходите к реализации (но с раскаянием…).

В Weld есть хороший дополнительный модуль под названием Weld Extensions , который предоставляет дополнительные функции, не упомянутые в JSR. Обратите внимание, что Weld Extensions, по-видимому, был заменен Seam Solder , но логика осталась прежней: получить ссылку на BeanManager и принудительно внедрить таблицу в appender через нее.

В расширении обратный вызов выполняется через интерфейс маркера расширения. Такие расширения проверяются Weld с использованием механизма поставщика услуг . Если вы не знакомы с ним, посмотрите на него, он элегантен и полезен во многих случаях использования. Итак, я создал свой файл META-INF / services / javax.enterprise.inject.spi.Extension.

Теперь давайте посмотрим на само расширение:

import java.util.List;
 
import javax.annotation.PostConstruct;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionTarget;
 
import org.jboss.weld.environment.se.events.ContainerInitialized;
import org.slf4j.impl.StaticLoggerBinder;
 
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
 
public class LogbackWeldExtension implements Extension {
 
  public void bind(@Observes ContainerInitialized event, BeanManager manager) {
 
    LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
 
    List loggers = loggerContext.getLoggerList();
 
    for (Logger logger : loggers) {
 
      Appender appender = logger.getAppender("Table");
 
      if (appender != null) {
 
        AnnotatedType type = manager.createAnnotatedType(appender.getClass());
 
        InjectionTarget target = manager.createInjectionTarget(type);
 
        CreationalContext creationalContext = manager.createCreationalContext(null);
 
        target.inject(appender, creationalContext);
      }
    }
  }
}
  • В строке 19 мы наследуем от Extension
  • В строке 21 мы наблюдаем событие инициализации контейнера, то есть метод вызывается при инициализации контекста Weld. Обратите внимание, что BeanManager является вторым параметром и автоматически внедряется платформой!
  • В строке 23–31 мы используем API-интерфейс Logback для управления неуправляемым аппендером. Обратите внимание, что мы получаем ссылку по имени, что я и сделал, потому что в то время мне было лень … В будущей версии будут просматриваться все приложения, и мы получим правильный по имени класса.
  • От 33 до 39 мы используем API Weld, чтобы внедрить неуправляемый регистратор в компоненты, которым он нужен. Обратите внимание, что нет ссылки на внедренный табличный компонент, это просто стандартный DI, если управляемые компоненты правильно аннотированы. Если вы используете этот код, также обратите внимание, что компилятор предупредит вас о неиспользуемых обобщениях (с ними трудно работать!).

Это оно!

Чтобы идти дальше:

 

От http://blog.frankel.ch/managing-unmanaged-beans-in-cdi