2012-07-09 16 views
17

Questo è un progetto Spring MVC con Hibernate. Sto cercando di fare una classe Logger che è responsabile per l'inserimento dei log nel database. Altre classi chiamano solo i metodi corretti con alcuni attributi e questa classe dovrebbe fare tutta la magia. Per sua natura dovrebbe essere una classe con metodi statici, ma che causa problemi con l'oggetto dao di autowiering.@autowired nelle classi statiche

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); 
    } 
} 

Come fare bene? Cosa devo fare per non rendere nullo l'oggetto dao? So che potrei passarlo come parametro di metodo, ma non è molto buono. Suppongo che il lavoro automatico non possa funzionare su oggetti statici, perché sono stati creati per il meccanismo di autowiering non ancora creato.

risposta

38

Non è possibile @Autowired un campo statico. Ma v'è una capacità difficile da affrontare questo:

@Component 
public class StatisticLogger { 

    private static Dao dao; 

    @Autowired 
    private Dao dao0; 

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

} 

In una parola, un campo @Autowired esempio, e assegnare il valore alla statica presentato quando l'oggetto viene costruito. A proposito, l'oggetto StatisticLogger deve essere gestito anche da Spring.

+0

Interessante trucco. Lo terrò a mente per il futuro :) –

+0

Il tipo di reso del metodo DEVE essere annullato. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html –

+1

Molto tempo dopo la battaglia, sono arrivato a utilizzare questa soluzione che funziona per la maggior parte. Ma la compagnia Sonar mi ha subito avvertito: "L'aggiornamento corretto di un campo statico da un metodo non statico è difficile da ottenere e potrebbe facilmente portare a bug se ci sono più istanze di classe e/o più thread in gioco. Idealmente, i campi statici vengono aggiornati solo da metodi statici sincronizzati. Ho pensato che sarebbe stato degno di menzione. – MaxouMask

14

L'autowiring classico probabilmente non funzionerà, perché una classe statica non è un bean e quindi non può essere gestita da Spring. Esistono modi per aggirare questo problema, ad esempio utilizzando the factory-method aproach in XML o caricando i bean da un contesto Spring in un blocco di inizializzazione statico, ma quello che suggerirei è di modificare il progetto:

Non utilizzare metodi statici, utilizzare i servizi che iniettate dove ne avete bisogno. Se usi Spring, potresti anche usarlo correttamente. Dipendenza L'iniezione è una tecnica orientata agli oggetti, e ha senso solo se in realtà abbracci l'OOP.

+0

bello, grazie –

0

So che questa è una vecchia questione, ma solo voluto condividere quello che ho fatto, la soluzione @Weibo Li è ok, ma il problema si pone Sonar avviso Critical sull'assegnazione di variabili non statica ad una variabile statica

il modo in cui ho risolto con nessun allarme sonar è la seguente

  1. cambio la StatisticLogger a singlton classe (non più statica) come questo

    public class Statisti cLogger { statisticLogger statico privato instance = null; dao privato 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. ho creato un servizio (o componente) che autowire il servizio che voglio e lo mise nella classe singlton Questo è sicuro dato che in primavera sarà inizializzare tutti i fagioli gestite prima fare qualsiasi altra cosa e che significa il metodo PostConstruct di seguito è sempre chiamato prima che qualcosa possa accedere al StatisticLogger qualcosa di simile

    @Component public class DaoSetterService {

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

    }

  3. Invece di utilizzare StatisticLogger come classe statica mi basta usare come StatisticLogger.getInstance() e posso accedere a tutti i metodi al suo interno

Problemi correlati