Why Static Field Injection Fails in Spring 6 and How to Do It Correctly
This article examines why Spring 6 does not support injecting static fields or methods with @Resource, @Autowired, or @Inject, demonstrates the resulting errors, and presents proper ways to inject static dependencies using instance‑method or constructor injection, backed by source‑code analysis of the relevant bean post‑processors.
1. Static Field & Method Injection
First we verify that Spring does not allow injection into static fields or methods.
1.1 @Resource injection
@Component
public class PersonController {
@Resource
private static PersonService ps;
}When the container starts, an error is logged indicating that @Resource does not support static field injection.
1.2 @Autowired injection
@Component
public class PersonController {
@Autowired
private static PersonService ps ;
public String toString() {
return "PersonController [ps=" + ps + "]";
}
}Running the application prints:
PersonController [ps=null]Although @Autowired does not inject the static field, it does not throw an exception; the silent failure can later cause a NullPointerException.
1.3 @Resource method injection
private static PersonService ps ;
@Resource
public static void setPs(PersonService personService) {
ps = personService ;
}Container startup again throws a clear error that static method injection is not supported.
1.4 @Autowired method injection
// Same as above, replace @Resource with @AutowiredOutput includes a log message stating that static field injection is not supported, and the bean prints PersonController [ps=null] without throwing an exception.
1.5 @Inject injection
First add the Jakarta Inject dependency:
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<version>${version}</version>
</dependency>Usage is identical to @Resource/@Autowired:
@Inject
private static PersonService ps ;Running the program produces the same log as @Autowired and the same null output.
All the above experiments confirm that static fields or methods cannot be injected by any of these annotations.
2. Correctly Injecting a Static Field
2.1 Instance‑method injection
public class PersonController {
private static PersonService ps;
@Resource
public void setPs(PersonService personService) {
ps = personService ;
}
}All three annotations (@Resource, @Autowired, @Inject) work when applied to a non‑static setter method.
2.2 Constructor injection
private static PersonService ps;
public PersonController(PersonService personService) {
ps = personService ;
}Constructor injection does not require any annotation and correctly assigns the static reference.
3. Source Code Analysis
The handling of @Resource is performed by CommonAnnotationBeanPostProcessor , while @Autowired and @Inject are processed by AutowiredAnnotationBeanPostProcessor .
3.1 @Resource processing
During bean definition merging, the processor scans for fields and methods annotated with @Resource. If a static field or method is found, it throws an IllegalStateException indicating that static injection is not supported.
public class CommonAnnotationBeanPostProcessor {
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
}
}
private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
InjectionMetadata metadata = buildResourceMetadata(clazz);
return metadata;
}
private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
// field check
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
});
// method check
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
});
}This check occurs before the actual injection phase.
3.2 @Autowired processing
@Autowired and @Inject share the same processor. It also scans fields and methods, logs a warning for static members, and skips injection.
public class AutowiredAnnotationBeanPostProcessor {
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
findInjectionMetadata(beanName, beanType, beanDefinition);
}
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> beanType, RootBeanDefinition beanDefinition) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
return metadata;
}
private void buildAutowiringMetadata(Class<?> clazz) {
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (Modifier.isStatic(field.getModifiers())) {
logger.info("Autowired annotation is not supported on static fields: " + field);
return;
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (Modifier.isStatic(method.getModifiers())) {
logger.info("Autowired annotation is not supported on static methods: " + method);
return;
}
});
}
}The actual injection happens later in AbstractAutowireCapableBeanFactory#populateBean.
In summary, static field or method injection is not supported by Spring's standard annotations; the proper approaches are instance‑method or constructor injection.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
