Java 用于静态字段的 @Autowire 的替代方案
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20878221/
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
Alternatives to @Autowire for static fields
提问by Anubha
What are alternatives to @Autowire
for static fields?
@Autowire
静态字段的替代方法是什么?
I went through many questions and understood why @Autowired
can't be used with static fields. The accepted answer of thisquestion mentions
我经历了很多问题并理解为什么@Autowired
不能与静态字段一起使用。这个问题的公认答案提到
You'll have to write your own logic to do this., as @Autowired cannot be used.
您必须编写自己的逻辑来执行此操作,因为不能使用 @Autowired。
As I am new to dependency injection, I did not get what steps would have to be followed to write our own logic to do this.
由于我是依赖注入的新手,我不知道必须遵循哪些步骤来编写我们自己的逻辑来执行此操作。
What I got is that new
cannot be used to create the object as it would tightly couple the 2 classes and DI is meant to be a solution for it. Also using @autowired
with setters is not recommended in the second answer of the same question. So what are the alternatives to achieve same effect without using @Autowire
?
我得到的是它new
不能用于创建对象,因为它会将 2 个类紧密耦合,而 DI 旨在成为它的解决方案。@autowired
在同一问题的第二个答案中也不建议使用setter。那么在不使用的情况下实现相同效果的替代方法是@Autowire
什么?
采纳答案by vertti
Well there is the "solution" for that: don't do it. Without seeing code sample from you I would say, why do you create something "static" if it depends on something dynamic (injected)?
那么有一个“解决方案”:不要这样做。如果没有看到您的代码示例,我会说,如果它依赖于动态(注入)的东西,为什么要创建“静态”的东西?
Normally I would reconsider the responsibilities. Relocate the possible static part to a static util class. For the part that needs injections, create a normal service instead.
通常我会重新考虑责任。将可能的静态部分重新定位到静态 util 类。对于需要注入的部分,改为创建普通服务。
(And yes, there are always workarounds, but when you need workarounds you often should think for a better solution instead).
(是的,总有变通方法,但是当您需要变通方法时,您通常应该考虑更好的解决方案)。
回答by Andreas Wederbrand
You can create a bean that triggers a method everytime the context is refreshed (ie completed). In that method you'll set any static fields you like, as an example this would inject two beans into each other, even if they are static.
您可以创建一个每次刷新(即完成)上下文时触发方法的 bean。在该方法中,您将设置您喜欢的任何静态字段,例如,这会将两个 bean 相互注入,即使它们是静态的。
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ApplicationListenerBean implements ApplicationListener {
@Autowired
SomeBean one;
@Autowired
SomeOtherBeab two;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
one.setTwo(two);
two.setOne(one);
}
}
}
回答by emanciperingsivraren
I will give you two alternatives. The first one are currently in a production environment. The second alternative is something that I came up with after thinking about this problem once more.
我会给你两个选择。第一个目前在生产环境中。第二种选择是我再次思考这个问题后想到的。
Still, this should be avoided, but if you have code that currently does not know about Spring, this can be used.
尽管如此,这应该避免,但如果您的代码目前不了解 Spring,则可以使用它。
Alternative 1
备选方案 1
Implement ApplicationContextAware
I had a situation where we needed to autowire a static field. I am working with legacy code where we want to use spring and jpa (hibernate) in our new code. In general it is bad practice to autowire static fields, but I belive that it can be motivated when considering the greater good for the application.
实现 ApplicationContextAware
我遇到过需要自动装配静态字段的情况。我正在处理遗留代码,我们希望在新代码中使用 spring 和 jpa(休眠)。一般来说,自动装配静态字段是不好的做法,但我相信在考虑对应用程序更大的好处时可以激发它。
We solved this situation by implementing ApplicationContextAware. Se blelow:
我们通过实现 ApplicationContextAware 解决了这种情况。吹:
public class DbHandler implements ApplicationContextAware {
private static DataSource dataSource;
protected DbHandler(){
//Needs to be protected (not private) for Spring
}
//This method is used in many places in the code, and we can not change how it is
//used. We wanted to use a datasource from Spring
public static Connection getConnection() throws java.sql.SQLException {
return dataSource.getConnection();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
DbHandler.dataSource = applicationContext.getBean("dataSource", javax.sql.DataSource.class);
}
}
}
And since the class is not in a package that is scanned by spring we added it to the context.xml
由于该类不在 spring 扫描的包中,我们将其添加到 context.xml
<bean id="dbHandler" class="se.ucr.db.DbHandler" depends-on="dataSource"/>
This is not as easy as easy as writing @Autowired, but it works.
这不像编写@Autowired 那样容易,但它确实有效。
Alternative 2
备选方案 2
Create a singelton
创建单例
A bean that can be injected:
一个可以注入的bean:
@Component
public class BeanToInject {
private static final Logger LOGGER = LoggerFactory.getLogger(BeanToInject.class);
public String getValue() {
return "Value from SpringBean";
}
}
A simple Singelton that will inject the bean that is defined above:
一个简单的 Singelton 将注入上面定义的 bean:
public class NeedStaticFieldInjected {
private static final Logger LOGGER = LoggerFactory.getLogger(NeedStaticFieldInjected.class);
private static NeedStaticFieldInjected INSTANCE;
private NeedStaticFieldInjected() {
//private constructor
}
@Autowired
private BeanToInject beanToInject;
public static NeedStaticFieldInjected getInstance() {
if (INSTANCE == null) {
INSTANCE = new NeedStaticFieldInjected();
}
return INSTANCE;
}
public static String getValueFromSpringBean() {
if (INSTANCE.beanToInject == null)
return "Not initialized correctly";
return INSTANCE.beanToInject.getValue();
}
}
And finally, the spring-context:
最后,弹簧上下文:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.emancipering.components"/>
<bean id="needStaticFieldInjected" class="org.emancipering.components.NeedStaticFieldInjected" factory-method="getInstance" />
</beans>
You will access the autowired properties via the static variable INSTANCE
, as shown in NeedStaticFieldInjected .getValueFromSpringBean()
. This is very close to the aim of injecting a static field. Of course, it is possible to have many more Autowired properties, but I just added one in this example.
您将通过静态变量访问自动装配的属性INSTANCE
,如 中所示NeedStaticFieldInjected .getValueFromSpringBean()
。这非常接近注入静态场的目的。当然,可以有更多的 Autowired 属性,但我只是在这个例子中添加了一个。
It is important that factory-method="getInstance"
is specified, otherwise this will fail.
重要的factory-method="getInstance"
是指定,否则这将失败。
I hope this is useful for someone.
我希望这对某人有用。
回答by sivakadi
I need to integrate with an existing class's functionality(obfuscation) in a logging class which has all static methods. This logging class's static methods were used from 1000's of places. So the only way I can implement this is to create an instance of obfuscating class and assign the reference to the static variable and refer the static variable. It worked!
我需要在具有所有静态方法的日志记录类中与现有类的功能(混淆)集成。这个日志类的静态方法在 1000 多个地方使用过。所以我可以实现的唯一方法是创建一个混淆类的实例并将引用分配给静态变量并引用静态变量。有效!
private static LogObfuscator staticObfuscator;
@Resource(name = "domain.logging.Obfuscator")
private LogObfuscator obfuscatorInstance;
@PostConstruct
public void init() {
staticObfuscator= obfuscatorInstance;
}