2012-07-09 22 views
17

To jest projekt Spring MVC z Hibernate. Próbuję utworzyć klasę Logger, która jest odpowiedzialna za wprowadzanie dzienników do bazy danych. Inne klasy po prostu wywołuj właściwe metody z pewnymi atrybutami i ta klasa powinna robić całą magię. Z natury rzeczy powinna być klasą ze statycznymi metodami, ale powoduje to problemy z autowirowaniem obiektu dao.@autowired w klasach statycznych

public class StatisticLogger { 
    @Autowired 
    static Dao dao; 
    public static void AddLoginEvent(LogStatisticBean user){ 
     //TODO code it god damn it 
    } 
    public static void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){ 
     //TODO code it god damn it 
    } 
    public static void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){ 
     ExceptionLogBean elb=new ExceptionLogBean(); 
     elb.setStuntDescription(e); 
     elb.setSourcePage(page); 
     elb.setParameters(parameters); 
     if(dao!=null){ //BUT DAO IS NULL 
      dao.saveOrUpdateEntity(elb); 
    } 
} 

Jak to naprawić? Co mam zrobić, aby obiekt dao nie był pusty? Wiem, że mogę przekazać go jako parametr metody, ale to nie jest bardzo dobrze. Zgaduję, że autowired nie może działać na statycznych obiektach, ponieważ są one tworzone na wczesnym etapie, do mechanizmu automatycznego dodawania nie jest jeszcze stworzony.

Odpowiedz

38

Nie można uzyskać statycznego pola @Autowired. Ale jest to trudne umiejętność radzenia sobie z tym:

@Component 
public class StatisticLogger { 

    private static Dao dao; 

    @Autowired 
    private Dao dao0; 

    @PostConstruct  
    private void initStaticDao() { 
    dao = this.dao0; 
    } 

} 

Jednym słowem, @Autowired polu instancji i przypisać wartość do statycznej złożony, gdy obiekt jest zbudowany. BTW, obiekt StatisticLogger musi być również zarządzany przez Spring.

+0

Ciekawe sztuczka. Będę o tym pamiętać na przyszłość :) –

+0

Typ zwrotu metody MUSI być nieważny. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html –

+1

Długo po bitwie, skorzystałem z tego rozwiązania, które działa w większości przypadków. Ale firma Sonar szybko dała mi ostrzeżenie: "Prawidłowe uaktualnienie pola statycznego z metody niestatycznej jest trudne do uzyskania i może prowadzić do błędów, jeśli istnieje wiele instancji klasy i/lub wiele wątków w grze. Najlepiej byłoby, gdyby pola statyczne były aktualizowane tylko ze zsynchronizowanych metod statycznych. "Myślałem, że warto o tym wspomnieć. – MaxouMask

14

Klasyczne autowiring prawdopodobnie nie zadziała, ponieważ klasa statyczna nie jest fasolą i dlatego nie można nią zarządzać wiosną. Istnieją sposoby obejścia tego problemu, na przykład przez użycie the factory-method aproach in XML lub ładowanie ziaren z kontekstu Spring w statycznym bloku inicjalizatora, ale sugeruję zmianę projektu:

Nie używaj metod statycznych, korzystaj z usług, które wstrzykujesz tam, gdzie ich potrzebujesz. Jeśli używasz Springa, równie dobrze możesz go używać poprawnie. Injection Dependency Injection to technika zorientowana obiektowo i ma sens tylko wtedy, gdy faktycznie wykorzystasz OOP.

+0

Nicea, dziękuję –

0

wiem, jest to stara sprawa, ale po prostu chciałem podzielić to, co zrobiłem, rozwiązanie przez @Weibo Li jest ok, ale problem podnosi Sonar krytyczny alert o przypisanie zmiennej non statyczne do statycznej zmiennej

sposób postanowiłem go bez alarmów sonaru jest następujący

  1. mogę zmienić StatisticLogger do singlton klasę (nie statyczne) jak ten

    public class Statisti cLogger { statyczna instancja StatisticLogger = null; prywatny Dao dao;

    public static StatisticLogger getInstance() { 
        if (instance == null) { 
         instance = new StatisticLogger(); 
        } 
        return instance; 
    } 
    
    protected StatisticLogger() { 
    } 
    
    public void setDao(Dao dao) { 
        this.dao = dao; 
    } 
    public void AddLoginEvent(LogStatisticBean user){ 
        //TODO code it god damn it 
    } 
    public void AddDocumentEvent(LogStatisticBean user, Document document, DocumentActionFlags actionPerformed){ 
        //TODO code it god damn it 
    } 
    public void addErrorLog(Exception e, String page, HashMap<String, Object> parameters){ 
        ExceptionLogBean elb=new ExceptionLogBean(); 
        elb.setStuntDescription(e); 
        elb.setSourcePage(page); 
        elb.setParameters(parameters); 
        if(dao!=null){ 
         dao.saveOrUpdateEntity(elb); 
    } 
    

    }

  2. I stworzył usługę (lub jego element), który autowire usługę, że chcę i ustawić go w klasie singlton Jest to bezpieczne, ponieważ na wiosnę będzie zainicjować wszystkie zarządzanych fasoli przed cokolwiek innego, a to oznacza, że ​​metoda PostConstruct poniżej jest zawsze nazywany zanim cokolwiek może uzyskać dostęp do StatisticLogger coś w tym

    @Component public class DaoSetterService {

    @Autowired 
    private Dao dao0; 
    
    @PostConstruct  
    private void setDaoValue() { 
        StatisticLogger.getInstance().setDao(dao0); 
    } 
    

    }

  3. Zamiast StatisticLogger jako klasy statycznej po prostu użyć go jako StatisticLogger.getInstance() i mogę uzyskać dostęp do wszystkich metod wewnątrz niego

Powiązane problemy