如何在枚举中注入Logger



当我试图在枚举中注入Logger生产者时,我会得到一个NPE。如何在枚举中注入Logger?

示例:

public enum MyEnum {
HI("Hi there!"),
HELLO("Hello mister!");
@Inject
private Logger log;
private final String greeting;
private MyEnum(String greeting) {
this.greeting = greeting;
//        this.log = LoggerFactory.getLogger(this.getClass());
}
public String getGreeting() {
log.debug("Method getGreeting called");
return this.greeting;
}
}

这个类在log.debug()线上给我一个NPE。当我删除@Inject并取消对this.log行的注释时,它就起作用了。

测试用例如下:

@RunWith(Arquillian.class)
public class CoverKindTest {
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, "test.war")
.addClass(MyEnum.class)
.addClass(LoggerProducer.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
@Test
public void testEnum() {
MyEnum myEnum = MyEnum.HI;
String greeting = myEnum.getGreeting();
assertThat("Should give the greeting.", greeting, is("Hi there!"));
}
}

这个问题的完整可测试项目可以在这里找到,MyEnum.class是原始问题,MyEnum1.class是没有注入的解决方案(有效,但不是我想要的),MyEnum2.class是建议的答案。

编辑:用一个有效的解决方案更新了GitHub回购。https://github.com/martijnburger/how-to-inject-a-logger-in-an-enum

由于枚举是静态的,因此此直接注入将不起作用。您可以在枚举类中创建一个新的记录器

private static final Logger log = Logger.getLogger(Myenum.class.getName());

找到了一个有效的解决方案!

我创建了一个助手类,如下所示:

public class LoggerHelper {
private static Logger logger;
private void injectLogger(@Observes @Initialized(ApplicationScoped.class) Object context, 
Logger logger) {
LoggerHelper.logger = logger;
}
public static Logger getLogger() {
return logger;
}
}

现在我可以使用在Enum中注入记录器

private final Logger log = LoggerHelper.getLogger();
不能注入枚举,因为它们是静态的。

如果您仍然想要注入(而不仅仅是创建Logger),那么您需要在枚举中创建一个静态类,该类具有setter或构造函数注入。当DI框架调用setter或构造函数时,获取它给您的值,并将其自己分配给枚举中的静态值。

枚举现在可以根据需要访问它。但是要注意,如果您的类还没有被注入,那么该值将为null。

类似这样的东西:

public enum MyEnum {
HI("Hi there!"),
HELLO("Hello mister!");
private static Logger log;
private final String greeting;
private MyEnum(String greeting) {
this.greeting = greeting;
}
public String getGreeting() {
log.debug("Method getGreeting called");
return this.greeting;
}
@Component
public static class InjectionHelper {
@Inject
public InjectionHelper(Logger log) {
MyEnum.log = log;
}
}
}

您可以创建一个Singleton Service类(由您各自的DI Framework(比如Spring)创建),在该类中注入此日志并在枚举中使用它。

下面是一个有效的示例代码。(如果你使用XML的方式,用XML中这个类的bean标记替换Service注释。你也可以忽略lombok@Getter注释,用静态getter替换它)

// Service which is actually a Utility class but have DI Managed Beans.
@Service("staticService")
public class StaticService {
@Getter
private static Logger log;
@Inject
StaticService(Logger log) {
StaticService.log = log;
}
}

现在在您对应的枚举中:

public String getGreeting() {
StaticService.getLog().debug("Method getGreeting called");
return this.greeting;
}

我在我的一个类(In Spring)中使用了类似的模式,注入成功了。

逻辑:

  1. 我们首先创建一个类的实例(singleton实例),并在构造函数中注入所需的变量
  2. 由于这是在春季初始化期间(在应用程序启动期间)调用的,因此日志被初始化,我们在构造函数中手动为日志的静态变量分配注入的对象

注意:

  1. 不要忘记构造函数Args中的Inject注释
  2. 最好不要为此日志对象提供setter方法。由于它是静态的和共享的,我们不希望人们在构建后取代这种价值观。(使其成为最终版本并不是一种选择,因为它是静态的)

最新更新