What are alternatives to @Autowire
for static fields?
I went through many questions and understood why @Autowired
can't be used with static fields. The accepted answer of this question mentions
You'll have to write your own logic to do this., as @Autowired cannot be used.
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
?
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.
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.
We solved this situation by implementing ApplicationContextAware. Se blelow:
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
<bean id="dbHandler" class="se.ucr.db.DbHandler" depends-on="dataSource"/>
This is not as easy as easy as writing @Autowired, but it works.
Create a singelton
A bean that can be injected:
@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:
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.
It is important that factory-method="getInstance"
is specified, otherwise this will fail.
I hope this is useful for someone.
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.
(And yes, there are always workarounds, but when you need workarounds you often should think for a better solution instead).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With