32

这是一个带有 Hibernate 的 Spring MVC 项目。我正在尝试创建一个 Logger 类,该类负责将日志输入数据库。其他类只是调用具有某些属性的正确方法,而这个类应该做所有的魔法。从本质上讲,它应该是一个具有静态方法的类,但这会导致自动装配 dao 对象出现问题。

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

如何使它正确?我应该怎么做才能使 dao 对象为空?我知道我可以将它作为方法参数传递,但这不是很好。我猜 autowired 不能在静态对象上工作,因为它们是在早期创建的,但尚未创建自动装配机制。

4

4 回答 4

69

您不能@Autowired使用静态字段。但是有一个棘手的技巧来处理这个问题:

@Component
public class StatisticLogger {

  private static Dao dao;

  @Autowired
  private Dao dao0;

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

}

总之,@Autowired一个实例字段,并在构造对象时将值分配给静态字段。顺便说一句,该StatisticLogger对象也必须由 Spring 管理。

于 2014-02-18T11:14:27.453 回答
22

经典的自动装配可能不起作用,因为静态类不是 Bean,因此不能由 Spring 管理。有一些方法可以解决这个问题,例如通过使用XML 中factory-method方法,或者通过在静态初始化程序块中从 Spring 上下文加载 bean,但我建议更改您的设计:

不要使用静态方法,使用您在需要的地方注入的服务。如果你使用Spring,你还不如正确使用它。依赖注入是一种面向对象的技术,只有当你真正接受 OOP 时它才有意义。

于 2012-07-09T09:57:44.103 回答
2

我知道这是一个老问题,但只是想分享我所做的,@Weibo Li 的解决方案还可以,但它引发了关于将非静态变量分配给静态变量的声纳严重警报

我在没有声纳警报的情况下解决它的方法如下

  1. 我像这样将 StatisticLogger 更改为 singlton 类(不再是静态的)

    public class StatisticLogger {
    private static StatisticLogger instance = null;
    private 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. 我创建了一个服务(或组件),它自动连接我想要的服务并将其设置在单例类中这是安全的,因为在春天它会在做任何其他事情之前初始化所有托管 bean,这意味着下面的 PostConstruct 方法总是在之前被调用任何东西都可以像这样访问 StatisticLogger

    @Component
    public class DaoSetterService {
    
    @Autowired
    private Dao dao0;
    
    @PostConstruct     
    private void setDaoValue () {
        StatisticLogger.getInstance().setDao(dao0);
    }
    
    }
    
  3. 我没有将 StatisticLogger 用作静态类,而是将其用作 StatisticLogger.getInstance() 并且我可以访问其中的所有方法

于 2017-11-01T20:59:00.400 回答
0

您可以将 DAO 传递到StatisticLogger您调用它的位置。

public static void AddLoginEvent(LogStatisticBean user, DAO dao){
    dao.callMethod();
}
于 2020-06-08T14:22:52.723 回答