@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