Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject logger using Google Guice

Usually I define logger like this:

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

But when using @Inject we must use non-static and non-final field, like:

@Inject
private Logger logger;

i.e. logger will be created in each instance of this class, also logger is mutable. May be exist some way to make logger static? Also how I can bind logger to certain class (I use send the class object when creating logger object from factory LoggerFactory.getLogger(MyClass.class);, how to create logger in same way using injecting ? )?

like image 400
WelcomeTo Avatar asked Feb 19 '13 09:02

WelcomeTo


People also ask

How does @inject work Guice?

Using GuiceIn each of your constructors that need to have something injected in them, you just add an @Inject annotation and that tells Guice to do it's thing. Guice figures out how to give you an Emailer based on the type. If it's a simple object, it'll instantiate it and pass it in.

What does @inject mean Guice?

In Guice, the @Inject annotation will be used to define setter-based as well as constructor-based dependency injection. An instance of this class is utilized to send notifications by means of the accessible correspondence services.

What is @named annotation in Guice?

Guice comes with a built-in binding annotation @Named that takes a string: public class RealBillingService implements BillingService { @Inject public RealBillingService(@Named("Checkout") CreditCardProcessor processor, TransactionLog transactionLog) { ... }


2 Answers

Please check the Custom Injections on Guice wiki, there is a complete Log4J example.

EDIT: You can use either a static field or a final field for your logger, but not a static final one. This is a Java limitation.

Also be wary that:

Injecting final fields is not recommended because the injected value may not be visible to other threads.

Haven't tested that but the code in the article should work fine for static fields, although you could improve it by getting rid of MembersInjector and doing all of it in the TypeListener (since a static field needs to be set only once).

Using requestStaticInjection() will force you to list all your classes in a module file - not a good idea, as you will soon forget to add one.

OTOH if you just want to support JUL you might be better of using the built-in support (as mentioned by Jeff, I assumed you didn't want a general answer, since you didn't mention JUL specifically in your question).

like image 194
Jakub Bochenski Avatar answered Sep 21 '22 14:09

Jakub Bochenski


When designing your application for dependency injection, typically the best practice is to avoid static fields and methods as much as possible. This is so that your dependencies are clearer, and so it's easier to replace your real dependencies with other instances during tests and as your application evolves. The ideal behavior, therefore, is to avoid static methods and fields (including loggers) as much as possible.

Guice, however, does allow for marking fields static, and requesting injection of static fields when the Injector is created. The fields will need to remain mutable--final doesn't mean "final except for 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 automatically provides java.util.logger.Logger instances for you with the class name embedded into it, but that's only because of a special case coded into Guice. If you want a special logger, as in this SO question, you'll need to investigate the Custom Injections to which Jakub linked--but if the whole goal is to centralize logger creation so you can control it in one place, you can just refactor that into a static factory outside of Guice too.

@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();
    }
  }
}
like image 26
Jeff Bowman Avatar answered Sep 18 '22 14:09

Jeff Bowman