问题的术语非常简单:希望将应用程序的日志显示在Swing表中, 即 Logback附加程序必须写在表中。 该表是用CDI管理的,但附加程序却不是:这并不奇怪,因为许多老一代框架都具有自己的生命周期管理。 在JEE6之前的Servlet,Log4J附加程序,Struts操作都有其自己的生命周期管理,与CDI完全无关。 更糟糕的是,依赖注入框架在很大程度上彼此不兼容(想到了Spring),并且需要一个适配器来在它们的上下文之间架起桥梁,因此这种用例是常见的。
我的第一个线索是自己引导Logback,但由于Weld在后台使用SLF4J,所以我找不到办法。 一段时间后,得出的结论是CDI无法提供将我的托管表注入Logback附加程序的方法。 那是一个可悲的结论,但我并没有就此止步:当规范不能满足您的需求时,请跳到实施(但要re悔...)。
Weld有一个很好的补充模块,称为Weld Extensions ,提供了JSR中未提及的其他功能。 请注意,Weld Extensions似乎已被Seam Solder代替,但逻辑保持不变:获取对BeanManager
的引用,并通过它强制将表插入到附加器中。
在扩展中,通过Extension
标记接口进行回调。 此类扩展由Weld使用服务提供商机制查找。 如果您不熟悉它,请看一下它,它在许多用例中都是优雅而有用的。 因此,我创建了META-INF / services / javax.enterprise.inject.spi.Extension文件。
现在,让我们看一下扩展本身:
importjava.util.List;
importjavax.annotation.PostConstruct;
importjavax.enterprise.context.spi.CreationalContext;
importjavax.enterprise.event.Observes;
importjavax.enterprise.inject.spi.AnnotatedType;
importjavax.enterprise.inject.spi.BeanManager;
importjavax.enterprise.inject.spi.Extension;
importjavax.enterprise.inject.spi.InjectionTarget;
importorg.jboss.weld.environment.se.events.ContainerInitialized;
importorg.slf4j.impl.StaticLoggerBinder;
importch.qos.logback.classic.Logger;
importch.qos.logback.classic.LoggerContext;
importch.qos.logback.classic.spi.ILoggingEvent;
importch.qos.logback.core.Appender;
publicclassLogbackWeldExtensionimplementsExtension{ (1)
publicvoidbind(@ObservesContainerInitializedevent,BeanManagermanager){ (2)
LoggerContextloggerContext=(LoggerContext)StaticLoggerBinder.getSingleton().getLoggerFactory();
Listloggers=loggerContext.getLoggerList();
for(Loggerlogger:loggers){
Appenderappender=logger.getAppender("Table"); (3)
if(appender!=null){
AnnotatedTypetype=manager.createAnnotatedType(appender.getClass());
InjectionTargettarget=manager.createInjectionTarget(type);
CreationalContextcreationalContext=manager.createCreationalContext(null); (4)
target.inject(appender,creationalContext);
}
}
}
}
- 我们继承自Extension
- 我们观察到容器初始化事件,这意味着在初始化Weld上下文时调用该方法。 注意,
BeanManager
是第二个参数,并由框架自动注入! - 我们使用Logback的API来获取非托管附加程序的句柄。 请注意,我们得到的是名称的引用,之所以这么做是因为当时我很懒...将来的版本将浏览所有的附加程序,并按类名获取正确的引用。
- 我们使用Weld的API将非托管记录器注入需要它的bean。 注意,这里没有对注入的表bean的引用,如果对托管bean进行了正确的注释,则只是标准DI。 如果您使用此代码,还请注意编译器会警告您有关未使用的泛型(使用它们会很麻烦!)。
而已!
翻译自: https://blog.frankel.ch/managing-unmanaged-beans-in-cdi/