2013-02-19 14 views
6

Zazwyczaj zdefiniować rejestrator tak:Jak wstrzykiwać rejestratora za pomocą Google Guice

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

Ale podczas korzystania @Inject musimy użyć pola non-statyczne i non-końcowy, jak:

@Inject 
private Logger logger; 

tj Logger zostanie utworzony w każdej instancji tej klasy, także rejestrator jest zmienny. Może istnieć jakiś sposób, aby rejestr był statyczny? Również w jaki sposób mogę powiązać rejestrator z pewną klasą (używam wysłać obiekt klasy podczas tworzenia obiektu rejestratora z fabryki LoggerFactory.getLogger(MyClass.class);, jak utworzyć rejestrator w taki sam sposób, używając wstrzykiwania?)?

+2

Jaki jest powód, dla którego rejestrator jest wstrzykiwany? Czy chcesz tylko uniknąć pisania? –

Odpowiedz

7

Proszę sprawdzić Custom Injections na wiki Guice, istnieje kompletny przykład Log4J.

EDYCJA: Można użyć pola static lub pola final dla rejestratora, ale nie dla static final. To jest Java limitation.

również uważać that:

Wstrzykiwanie obszary końcowe nie jest zalecane, ponieważ wstrzykiwane wartości nie mogą być widoczne dla innych nici.

Nie testowałem tego, ale kod w artykule powinien działać poprawnie dla pól statycznych, chociaż można go poprawić, pozbywając się elementu MembersInjector i robiąc to wszystko w TypeListener (ponieważ pole statyczne musi być ustawić tylko raz).

Używanie requestStaticInjection() zmusi Cię do wypisania wszystkich twoich klas w pliku modułu - nie jest to dobry pomysł, ponieważ wkrótce zapomnisz go dodać.

OTOH, jeśli chcesz tylko wspierać JUL, być może lepiej użyjesz built-in support (jak wspomniał Jeff, założyłem, że nie chcesz ogólnej odpowiedzi, ponieważ nie wspomniałeś o JUL w swoim pytaniu).

+0

Uważam, że linkowany artykuł nie zawiera kilku aspektów: 1) Wymagana jest nowa adnotacja.Dla JUL możesz użyć @Inject (zarówno java.inject.Inject, jak i Guice). 2) Bez iniekcji konstruktora, 3) bez iniekcji metody jest obsługiwana 4) Superklasy są obsługiwane tylko przez hacki w komentarzach. Podsumowanie do tej pory: wsparcie JUL jest wyjątkowe i nie może być przeniesione do innych struktur logowania w taki sam sposób i jakości. –

+0

Przykro mi, ale uważam, że nie jest to istotne ani istotne dla mojego anwsera. 1) Nie, nie można po prostu upuścić czeku i wstrzyknąć wszystkie pola Logger 2) Tak, ale jak można się spodziewać, że będzie działać z Guice? 3) Jest obsługiwany, możesz sprawdzić klasę w dowolny sposób (np. Poszukać metod). –

+0

Moja uwaga, która jest istotna dla twojej odpowiedzi, jest następująca: linkowany artykuł ma swoje wady. Proponowane rozwiązanie nie obsługuje wstrzykiwania w ten sam sposób, w jaki Guice wspiera iniekcję w innym miejscu. Różnice te powinny być jasne, a nie po fakcie. Szczególnie, że ostatnia część pytania ("jak stworzyć ...") i użycie "@ Inject" wydaje się odnosić dokładnie do tej IMO.
Nazwałam trzy problemy, które miałem w podobnej sprawie. To nie jest przeciwko tobie, ale tylko dla wszystkich, którzy chcą odkryć to rozwiązanie - jeśli powiedzą: "Mogę z tym żyć". OK - bądźcie mile widziani. –

2

Podczas projektowania wniosku o wstrzyknięcie zależności zazwyczaj najlepszą metodą jest unikanie pól i metod statycznych w jak największym stopniu. Jest tak, aby twoje zależności były bardziej przejrzyste, a więc łatwiej jest zastąpić rzeczywiste zależności innymi instancjami podczas testów i gdy twoja aplikacja ewoluuje. Idealnym zachowaniem jest zatem unikanie metod statycznych i pól (w tym rejestratorów) w jak największym stopniu.

Guice jednak pozwala na zaznaczanie pól statycznych i requesting injection of static fields when the Injector is created. Pola będą musiały pozostać zmienne - final nie oznacza "końcowego z wyjątkiem 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 automatycznie zapewnia java.util.logger.Logger instances dla ciebie z nazwą klasy wbudowanego w nią, ale to tylko ze względu a special case coded into Guice. Jeśli potrzebujesz specjalnego rejestratora, jak w this SO question, musisz zbadać iniekcje niestandardowe, z którymi łączył się Jakub - ale jeśli cały cel polega na scentralizowaniu tworzenia loggera, aby móc go kontrolować w jednym miejscu, możesz po prostu do statycznej fabryki poza 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(); 
    } 
    } 
} 
+0

Twoje rozwiązanie ma tę wadę, że nazwa klasy "Yourclass.class" w twoim przykładzie musi być dostarczona w spójny sposób dla wszystkich aplikacji. To może być właśnie jeden z powodów, dla których scentralizowany zastrzyk jest uważany i pomocny - problem ten nie istniałby przy odpowiednim wsparciu iniekcyjnym. –

+0

@ A.H. Należy zauważyć, że zdolność dostawcy lub zależności do określenia miejsca wstrzyknięcia została [wyraźnie i celowo odrzucona jako funkcja] (https://code.google.com/p/google-guice/issues/detail?id=27). W polu instancji możesz użyć 'this', ale w kontekście statycznym Java niestety nie ma żadnej składni krótszej niż sama nazwa klasy. Kiedy znajdziesz lub utworzysz "właściwe wsparcie wstrzyknięcia", przekaż je dalej - Byłbym bardzo szczęśliwy, gdy zobaczyłem, jak to działa! –

+0

Zauważ, że Guice * nie * umożliwia wstrzyknięcie końcowych pól, zobacz moją odpowiedź powyżej dla łącza. –

Powiązane problemy