2012-07-09 41 views
17

Este es un proyecto Spring MVC con Hibernate. Estoy tratando de crear una clase Logger que sea responsable de ingresar los registros en la base de datos. Otras clases solo llaman a los métodos adecuados con algunos atributos y esta clase debería hacer toda la magia. Por naturaleza, debería ser una clase con métodos estáticos, pero eso causa problemas con el autoenvío del objeto dao.@autowired en clases estáticas

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

Cómo hacer las cosas bien? ¿Qué debería hacer para no hacer que el objeto dao sea nulo? Sé que podría pasarlo como un parámetro de método, pero eso no es muy bueno. Supongo que el autoenlace no puede funcionar en objetos estáticos, porque se crearon para que el mecanismo de inicio automático no se haya creado todavía.

Respuesta

38

No se puede @Autowired un campo estático. Pero no es una habilidad difícil de tratar con esto:

@Component 
public class StatisticLogger { 

    private static Dao dao; 

    @Autowired 
    private Dao dao0; 

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

} 

En una palabra, @Autowired un campo de instancia, y asignar el valor a la estática presentada cuando se construye su objeto. Por cierto, el objeto StatisticLogger también debe ser administrado por Spring.

+0

Interesante truco. Lo tendré en cuenta para el futuro :) –

+0

El tipo de devolución del método DEBE ser nulo. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html –

+1

Mucho tiempo después de la batalla, he venido a utilizar esta solución que funciona en su mayor parte. Pero la compañía Sonar rápidamente me dio una advertencia al respecto: 'Actualizar correctamente un campo estático desde un método no estático es complicado de corregir y podría dar lugar a errores si hay varias instancias de clases y/o múltiples hilos en juego. Lo ideal es que los campos estáticos solo se actualicen a partir de métodos estáticos sincronizados. Pensé que valía la pena mencionarlo. – MaxouMask

14

El autocableado clásico probablemente no funcionará, porque una clase estática no es un Bean y, por lo tanto, no puede ser administrada por Spring. Hay formas de evitar esto, por ejemplo, usando the factory-method aproach in XML, o cargando los beans desde un contexto Spring en un bloque de inicializador estático, pero lo que sugiero es cambiar su diseño:

No use métodos estáticos, use los servicios que inyecta donde los necesita. Si usa Spring, es mejor que lo use correctamente. Dependency Injection es una técnica orientada a objetos, y solo tiene sentido si realmente adoptas OOP.

+0

Niza, gracias –

0

Sé que esto es una vieja pregunta, pero sólo quería compartir lo que hice, la solución por @Weibo Li está bien, pero el problema que plantea Sonar alerta crítica acerca de la asignación variable no estática a una variable estática

la forma en que lo resolví con ninguna alerta de sonar es el siguiente

  1. cambio la StatisticLogger a singlton clase (ya no estática) como esto

    clase pública estadísti cLogger { static static StatisticLogger instance = null; privado 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. creé un servicio (o componentes) que Autowire el servicio que quiero y lo puse en la clase singlton Esto es seguro ya que en la primavera se va a inicializar todos los beans gestionados antes hacer cualquier otra cosa y que significaría el método PostConstruct a continuación siempre se llama antes de que cualquier cosa puede acceder al StatisticLogger algo como esto

    @Component DaoSetterService public class {

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

    }

  3. En lugar de utilizar StatisticLogger como clase estática sólo tiene que utilizar como StatisticLogger.getInstance() y puedo acceder a todos los métodos en su interior