@Autowired 在静态类中

Posted

技术标签:

【中文标题】@Autowired 在静态类中【英文标题】:@Autowired in static classes 【发布时间】:2012-07-08 17:05:37 【问题描述】:

这是一个带有 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 不能在静态对象上工作,因为它们是在早期创建的,但尚未创建自动装配机制。

【问题讨论】:

【参考方案1】:

您可以将 DAO 传递给您调用它的StatisticLogger

public static void AddLoginEvent(LogStatisticBean user, DAO dao)
    dao.callMethod();

【讨论】:

【参考方案2】:

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

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

    我将 StatisticLogger 更改为单例类(不再是静态的) 像这样

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

    我创建了一个服务(或组件),它自动连接我想要的服务并将其设置在单例类中 这是安全的,因为在春季,它将在执行任何其他操作之前初始化所有托管 bean,这意味着在任何东西可以访问 StatisticLogger 之前始终调用下面的 PostConstruct 方法 像这样的

    @Component
    public class DaoSetterService 
    
    @Autowired
    private Dao dao0;
    
    @PostConstruct     
    private void setDaoValue () 
        StatisticLogger.getInstance().setDao(dao0);
    
    
    
    

    我没有使用 StatisticLogger 作为静态类,而是将其用作 StatisticLogger.getInstance(),我可以访问其中的所有方法

【讨论】:

这是一个很棒的技巧。但我认为提问者要求将其分配给静态成员(与私有 Dao dao 不同;)也许在类的静态成员中使用。我认为可以通过将其设为 statick(私有静态 Dao dao;)并替换 this.dao = dao 来进行管理,它可以简单地为 dao = dao。这样就可以在静态成员内部访问它。有什么想法吗?? 我猜因为它是一个单例所有成员都可以是非静态的,在这种情况下你的方法效果很好!谢谢。【参考方案3】:

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

@Component
public class StatisticLogger 

  private static Dao dao;

  @Autowired
  private Dao dao0;

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


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

【讨论】:

方法的返回类型必须为空。 docs.oracle.com/javaee/5/api/javax/annotation/… 战斗很久之后,我开始使用这个在大多数情况下都有效的解决方案。但是 Sonar 公司很快就给了我一个警告:Correctly updating a static field from a non-static method is tricky to get right and could easily lead to bugs if there are multiple class instances and/or multiple threads in play. Ideally, static fields are only updated from synchronized static methods. 我觉得值得一提。 @spoko感谢您的评论。 @WeiboLi :- 我尝试实现同样的事情,我想从bootstrap.yml 文件中选择值。所有@values 都配置在CosmosConnection 类中。这是我的代码static CosmosConnection cosmos= new CosmosConnection(); @Autowired private CosmosConnection tcosmos; @PostConstruct public void init() SupplierGetResponseFeed.cosmos = tcosmos; 在同一个类中,我有另一种方法,我从中调用cosmos.connectToDB();【参考方案4】:

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

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

【讨论】:

以上是关于@Autowired 在静态类中的主要内容,如果未能解决你的问题,请参考以下文章

[@ MockBean和@Autowired在一个测试类中使用同一服务

Springboot在Utils类中使用@Autowired注入

如何在spring boot的多个类中使用@Autowired MongoTemplate

Spring Boot:Autowired CRUDRepository null,在某些类中

您可以将@Autowired 与静态字段一起使用吗?

SpringBoot@Autowired注入静态成员变量报空指针异常