spring @Autowired 在静态类中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11392692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
@Autowired in static classes
提问by T.G
This is an Spring MVC project with Hibernate. I'm, trying to make a Logger class that, is responsible for inputting logs into database. Other classes just call proper methods with some attributes and this class should do all magic. By nature it should be a class with static methods, but that causes problems with autowiring dao object.
这是一个带有 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);
}
}
How to make it right? What should I do not to make dao object null? I know that I could pass it as a method parameter, but that isn't very good. I'm guessing that autowired can't work on static objects, because they are created to early to autowiring mechanism isn't created yet.
如何做对?我应该怎么做才能使 dao 对象为空?我知道我可以将它作为方法参数传递,但这不是很好。我猜自动装配不能在静态对象上工作,因为它们很早就被创建,自动装配机制还没有被创建。
回答by Weibo Li
You can't @Autowireda static field. But there is a tricky skill to deal with this:
你不能@Autowired是静态字段。但是有一个棘手的技巧可以解决这个问题:
@Component
public class StatisticLogger {
private static Dao dao;
@Autowired
private Dao dao0;
@PostConstruct
private void initStaticDao () {
dao = this.dao0;
}
}
In one word, @Autowireda instance field, and assign the value to the static filed when your object is constructed. BTW, the StatisticLoggerobject must be managed by Spring as well.
一言以蔽之,@Autowired实例字段,并在构造对象时将值分配给静态字段。顺便说一句,该StatisticLogger对象也必须由 Spring 管理。
回答by Sean Patrick Floyd
Classical autowiring probably won't work, because a static class is not a Bean and hence can't be managed by Spring. There are ways around this, for example by using the factory-methodaproach in XML, or by loading the beans from a Spring context in a static initializer block, but what I'd suggest is to change your design:
经典的自动装配可能不起作用,因为静态类不是 Bean,因此不能由 Spring 管理。这种情况有解决办法,例如通过使用了factory-method以XML的形式给出,或通过加载从Spring上下文豆静态初始化块,但我会建议是要改变你的设计:
Don't use static methods, use services that you inject where you need them. If you use Spring, you might as well use it correctly. Dependency Injection is an Object Oriented technique, and it only makes sense if you actually embrace OOP.
不要使用静态方法,使用您在需要的地方注入的服务。如果您使用Spring,您不妨正确使用它。依赖注入是一种面向对象的技术,只有当您真正接受 OOP 时它才有意义。
回答by Hani
I know this is an old question but just wanted to share what I did, the solution by @Weibo Li is ok but the problem it raises Sonar Critical alert about assigning non static variable to a static variable
我知道这是一个老问题,但只是想分享我所做的,@Weibo Li 的解决方案没问题,但它引发了关于将非静态变量分配给静态变量的声纳严重警报
the way i resolved it with no sonar alerts is the following
我在没有声纳警报的情况下解决它的方法如下
I change the StatisticLogger to singlton class (no longer static) like this
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); } }I created a service(or Component) that autowire the service that i want and set it in the singlton class This is safe since in spring it will initialize all the managed beans before doing anything else and that mean the PostConstruct method below is always called before anything can access the StatisticLogger something like this
@Component public class DaoSetterService { @Autowired private Dao dao0; @PostConstruct private void setDaoValue () { StatisticLogger.getInstance().setDao(dao0); } }Instead of using StatisticLogger as static class I just use it as StatisticLogger.getInstance() and i can access all the methods inside it
我像这样将 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); } }我创建了一个服务(或组件),它自动装配我想要的服务并将其设置在 singlton 类中 这是安全的,因为在春天它会在做任何其他事情之前初始化所有托管 bean,这意味着下面的 PostConstruct 方法总是在之前调用任何东西都可以访问 StatisticLogger 像这样
@Component public class DaoSetterService { @Autowired private Dao dao0; @PostConstruct private void setDaoValue () { StatisticLogger.getInstance().setDao(dao0); } }我没有使用 StatisticLogger 作为静态类,而是将其用作 StatisticLogger.getInstance() 并且我可以访问其中的所有方法

