9

通常我这样定义记录器:

private static final Logger logger = LoggerFactory.getLogger(MyClass.class); 

但是在使用时@Inject我们必须使用非静态和非最终字段,例如:

@Inject
private Logger logger;

即记录器将在此类的每个实例中创建,记录器也是可变的。可能存在某种方式使记录器静态?另外我如何将记录器绑定到某个类(我在从工厂创建记录器对象时使用发送类对象LoggerFactory.getLogger(MyClass.class);,如何使用注入以相同的方式创建记录器?)?

4

2 回答 2

7

请查看 Guice wiki 上的自定义注入,有一个完整的 Log4J 示例。

编辑:您可以为记录器使用static字段或final字段,但不能使用字段static final。这是 Java限制

还要小心

不推荐注入 final 字段,因为注入的值可能对其他线程不可见。

尚未对此进行测试,但文章中的代码应该适用于静态字段,尽管您可以通过摆脱 MembersInjector 并在 TypeListener 中完成所有操作来改进它(因为静态字段只需要设置一次)。

使用requestStaticInjection()将迫使您在模块文件中列出所有类 - 这不是一个好主意,因为您很快就会忘记添加一个。

OTOH,如果您只想支持 JUL,您可能会更好地使用内置支持(正如 Jeff 所提到的,我假设您不想要一个一般性的答案,因为您没有在问题中特别提到 JUL)。

于 2013-02-19T09:43:39.620 回答
4

在为依赖注入设计应用程序时,通常最佳实践是尽可能避免使用静态字段和方法。这样可以使您的依赖关系更加清晰,并且在测试期间和随着应用程序的发展,更容易用其他实例替换您的真实依赖关系。因此,理想的行为是尽可能避免使用静态方法和字段(包括记录器)。

然而,Guice 确实允许将字段标记为静态,并在创建 Injector 时请求注入静态字段。这些字段需要保持可变——final并不意味着“除了 Guice 之外的最终结果”。

public class YourClass {
  @Inject static Logger logger;

  /* ... */
}

public class YourModule extends AbstractModule {
  @Override public void configure() {
    /* YourClass.logger will work once you create your Injector. */
    requestStaticInjection(YourClass.class);
  }
}

Guice 会自动为您提供嵌入了类名的java.util.logger.Logger实例,但这只是因为Guice 中编码了一个特殊情况。如果你想要一个特殊的记录器,就像在这个 SO question中一样,你需要调查 Jakub 链接到的自定义注入——但如果整个目标是集中记录器的创建以便你可以在一个地方控制它,你可以也将其重构为 Guice 之外的静态工厂。

@LogToFile
public class YourClass {
  private static final Logger logger = YourLoggerFactory.create(YourClass.class);

  /* ... */
}

public class YourLoggerFactory {
  private YourLoggerFactory { /* do not instantiate */ }

  public Logger create(Class<?> clazz) {
    if (clazz.getAnnotation(LogToFile.class) != null) {
      return someImplementation(new File(...));
    } else {
      return someOtherImplementation();
    }
  }
}
于 2013-02-20T06:00:24.723 回答