Can you use @Autowired with static fields?
Asked Answered
S

13

209

Is there some way to use @Autowired with static fields. If not, are there some other ways to do this?

Shriver answered 19/6, 2009 at 16:11 Comment(1)
#10939029 relatedChallenging
P
165

In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.

Pleochroism answered 19/6, 2009 at 17:13 Comment(2)
When you find old code doing this, it's an anti-pattern. Squint, tilt your head, and find a better way to solve the problem. You'll be glad you did.Claudio
this answer is also helpful on Spring's @AutoWiredHyacinthie
D
160
@Component("NewClass")
public class NewClass{
    private static SomeThing someThing;

    @Autowired
    public void setSomeThing(SomeThing someThing){
        NewClass.someThing = someThing;
    }
}
Dialectical answered 13/5, 2011 at 11:33 Comment(7)
any idea how I can use this approach when initializing a repository?Todhunter
The downside : There's no guarantee that someThing has been initialized if accessed statically : NewClass.staticMethodWhichUsesSomething(); might throw an NPE if used before app initializationBarri
Can you avoid the warning of Instance methods should not write to "static" fields (squid:S2696)?Naucratis
@user7294900: disable this warning for this only, very specific case.Hogan
@Hogan still a problem if I choose this solution in broad cases and classesNaucratis
@user7294900 Broad cases? This is the only case when you should disable this warning - initialization of static fields via instance methods annotated with @Autowired annotation. If you are getting warnings in other cases (when method is not annotated with @Autowired), then this warning is valid and you should modify your code to fix this warning.Hogan
do we need the @Autowired if we initialized it in a constructor ?Vickey
J
77

@Autowired can be used with setters so you could have a setter modifying an static field.

Just one final suggestion... DON'T

Jacelynjacenta answered 20/6, 2009 at 1:27 Comment(4)
Why do you suggest not doing this?Mystical
Hmmm.. my feeling about why it's not recommended is, because then the static instance in the class is beyond the control of spring. Once injected the static field is the reference for all instances of objects of the corresponding (surrounding) class. But, this behaviour might be exactly what is expected to happen, thus might be seen as a bug or a feature...Heedful
Yes @matthaeus, it is exactly the feature I expected when needing to access org.springframework.core.env.Environment: @Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }Medullated
@JonLorusso and all Because when the class loader loads the static values, the Spring context is not yet necessary loaded. So the class loader won't properly inject the static class in the bean and will fail. Answer provided by Andrea TMaki
H
34

Init your autowired component in @PostConstruct method

@Component
public class TestClass {
   private static AutowiredTypeComponent component;

   @Autowired
   private AutowiredTypeComponent autowiredComponent;

   @PostConstruct
   private void init() {
      component = this.autowiredComponent;
   }

   public static void testMethod() {
      component.callTestMethod();
   }
}
Halsy answered 26/12, 2017 at 10:38 Comment(5)
Can you avoid the warning of Instance methods should not write to "static" fields (squid:S2696)?Naucratis
You can also do this directly through the constructor.Faro
@user7294900 I guess this warning tells us why this is considered an anti-pattern. When instance methods are writing to a static variable, the static variable becomes a critical resource shared among all the objects of the class, thus creating potential for problems in a multi-threaded environments.Discount
it saved my dayFronnia
This won't work if the field needs also to be final.Detach
H
6

Create a bean which you can autowire which will initialize the static variable as a side effect.

Hypercatalectic answered 20/6, 2009 at 1:21 Comment(0)
N
5

Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:

@Autowired
private static String staticField = "staticValue";
Naucratis answered 24/10, 2019 at 8:15 Comment(0)
B
3

You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.

private static StaticBean staticBean;

public void setStaticBean(StaticBean staticBean) {
   StaticBean.staticBean = staticBean;
}

You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.

Note testing can also be more difficult with this approach.

Bazaar answered 22/6, 2009 at 9:37 Comment(0)
S
1

You can use ApplicationContextAware

@Component
public class AppContext implements ApplicationContextAware{
    public static ApplicationContext applicationContext;

    public AppBeans(){
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

then

static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Sustentation answered 14/6, 2019 at 6:52 Comment(0)
L
0

Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.

I wanted to accomplish three things.

  1. Use spring to "Autowire" (Im using @Value)
  2. Expose a public static value
  3. Prevent modification

My object looks like this

private static String BRANCH = "testBranch";

@Value("${content.client.branch}")
public void finalSetBranch(String branch) {
    BRANCH = branch;
}

public static String BRANCH() {
    return BRANCH;
}

We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.

@Component
@Aspect
public class FinalAutowiredHelper {

@Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
    throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}

@Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}


public class ModifySudoFinalError extends Error {
    private String msg;

    public ModifySudoFinalError(String msg) {
        this.msg = msg;
    }

    @Override
    public String getMessage() {
        return "Attempted modification of a final property: " + msg;
    }
}

This aspect will wrap all methods beginning with final and throw an error if they are called.

I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.

Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.

Loden answered 22/6, 2019 at 1:9 Comment(0)
S
0

Generally, setting static field by object instance is a bad practice.

to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;

@Autowired
public synchronized void setLogger(Logger logger)
{
    if (MyClass.logger == null)
    {
        MyClass.logger = logger;
    }
}

:

Stotinka answered 11/11, 2020 at 14:14 Comment(0)
T
0

Solution 1 : Using Constructor @Autowired For Static Field

@Component
public class MyClass {

    private static MyService service;

    @Autowired
    public MyClass(MyService service) {
        TestClass.service= service;
    }
}

Solution 2 : Using @PostConstruct to set the value to Static Field

@Component
public class MyClass {

    private static MyService service;

    @Autowired
    private MyService srv;

    @PostConstruct
    public void init() {
        this.service= srv;
    }
}

Refer here for more detail

Timbuktu answered 4/4, 2022 at 14:59 Comment(0)
B
0

I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean

public final class MyClass {
    private static MyBean myBean;

    @Component
    private static class FieldSetter extends SelfDestroyBean {
          public FieldSetter(MyBean myBean) {
              MyClass.myBean = myBean;
          }
    }
}
    
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
    @Autowired
    private ApplicationContext context;

    @PostConstruct
    public void destroy() {
        final String[] beanNames = context.getBeanNamesForType(this.getClass());

        final BeanDefinitionRegistry registry =
                ((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
        for (String beanName : beanNames) {
            registry.removeBeanDefinition(beanName);
        }
    }
}
Becquerel answered 5/8, 2022 at 6:11 Comment(0)
C
-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);
Catastrophism answered 26/3, 2019 at 11:19 Comment(2)
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.Natal
I think this answer may not need any explanation at all.Kuban

© 2022 - 2024 — McMap. All rights reserved.