How to Fix Spring Static Injection NPE: Real-World Demo & Solutions
This article explains why static fields injected with @Autowired in Spring can become null, causing NPEs in production, and presents six practical solutions—including removing static fields, using @PostConstruct, static setters, ApplicationContext, singleton patterns, and @Lazy loading—to ensure reliable static dependency injection.
Spring Static Injection Real-World Demo
Sometimes we wrap a bean into a utility class and expose it as a default method, but the static field ends up null, causing a NullPointerException in production.
Why does RemoteEBRpcInvoker.getEbFormIdUtil sometimes return NULL?
@Component
public class RemoteEBRpcInvoker {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private static PublishKitRuntimeUtil publishKitRuntimeUtil;
private static GetEbFormIdUtil getEbFormIdUtil;
@Autowired
public RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,
PublishKitRuntimeUtil publishKitRuntimeUtil) {
RemoteEBRpcInvoker.getEbFormIdUtil = getEbFormIdUtil;
RemoteEBRpcInvoker.publishKitRuntimeUtil = publishKitRuntimeUtil;
}
/**
* Build RPC service instance by appId.
*/
public static <T> T newInstance(Class<T> tClass, Long appId) {
Long appId = getEbFormIdUtil.getAppId(TagConstant.CS_APPID_TAG, tenantKey);
return publishKitRuntimeUtil.buildRpcService(tClass, DEFAULT_RPC_GROUP, String.valueOf(appId));
}
}When calling newInstance(), getEbFormIdUtil is null because static injection failed.
Reason 1: Static variable initialization order
Static fields are initialized before instance fields; @Autowired works on instance creation, so static fields may remain null.
Reason 2: Spring lifecycle and static fields
Spring injects dependencies into instance fields; static fields are not tied to the bean lifecycle, leading to possible null values.
Solutions:
Solution
Method 1: Remove static fields (breaks original intent)
@Component
public class RemoteEBRpcInvoker {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private PublishKitRuntimeUtil publishKitRuntimeUtil;
private GetEbFormIdUtil getEbFormIdUtil;
@Autowired
public RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,
PublishKitRuntimeUtil publishKitRuntimeUtil) {
this.getEbFormIdUtil = getEbFormIdUtil;
this.publishKitRuntimeUtil = publishKitRuntimeUtil;
}
}This works but defeats the goal of a static utility.
Method 2: Use @PostConstruct
Initialize static variables after injection.
@Component
public class RemoteEBRpcInvoker {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private static PublishKitRuntimeUtil publishKitRuntimeUtil;
private static GetEbFormIdUtil getEbFormIdUtil;
@Autowired
public RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,
PublishKitRuntimeUtil publishKitRuntimeUtil) {
this.getEbFormIdUtil = getEbFormIdUtil;
this.publishKitRuntimeUtil = publishKitRuntimeUtil;
}
@PostConstruct
public void init() {
RemoteEBRpcInvoker.getEbFormIdUtil = this.getEbFormIdUtil;
RemoteEBRpcInvoker.publishKitRuntimeUtil = this.publishKitRuntimeUtil;
}
}This ensures static variables are assigned after dependencies are injected.
Method 3: Use static @Autowired setter
@Component
public class RemoteEBRpcInvoker {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private static PublishKitRuntimeUtil publishKitRuntimeUtil;
private static GetEbFormIdUtil getEbFormIdUtil;
@Autowired
public static void setPublishKitRuntimeUtil(PublishKitRuntimeUtil publishKitRuntimeUtil) {
RemoteEBRpcInvoker.publishKitRuntimeUtil = publishKitRuntimeUtil;
}
@Autowired
public static void setGetEbFormIdUtil(GetEbFormIdUtil getEbFormIdUtil) {
RemoteEBRpcInvoker.getEbFormIdUtil = getEbFormIdUtil;
}
}Static setter methods let Spring inject dependencies without relying on an instance.
Method 4: Use ApplicationContext to fetch beans
@Component
public class RemoteEBRpcInvoker implements ApplicationContextAware {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RemoteEBRpcInvoker.applicationContext = applicationContext;
}
public static GetEbFormIdUtil getGetEbFormIdUtil() {
return applicationContext.getBean(GetEbFormIdUtil.class);
}
public static PublishKitRuntimeUtil getPublishKitRuntimeUtil() {
return applicationContext.getBean(PublishKitRuntimeUtil.class);
}
}Manually retrieve beans from the context in static methods.
Method 5: Singleton pattern with manual injection
@Component
public class RemoteEBRpcInvoker {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private static RemoteEBRpcInvoker instance;
private PublishKitRuntimeUtil publishKitRuntimeUtil;
private GetEbFormIdUtil getEbFormIdUtil;
@Autowired
public RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,
PublishKitRuntimeUtil publishKitRuntimeUtil) {
this.getEbFormIdUtil = getEbFormIdUtil;
this.publishKitRuntimeUtil = publishKitRuntimeUtil;
instance = this;
}
public static RemoteEBRpcInvoker getInstance() {
return instance;
}
public GetEbFormIdUtil getGetEbFormIdUtil() {
return this.getEbFormIdUtil;
}
public PublishKitRuntimeUtil getPublishKitRuntimeUtil() {
return this.publishKitRuntimeUtil;
}
}The singleton stores the bean instance in a static field, allowing static access to non‑static members.
Method 6: Use @Lazy for lazy loading
@Component
public class RemoteEBRpcInvoker {
private static final String DEFAULT_RPC_GROUP = "ebuilderform";
private static PublishKitRuntimeUtil publishKitRuntimeUtil;
private static GetEbFormIdUtil getEbFormIdUtil;
@Autowired
@Lazy
public RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,
PublishKitRuntimeUtil publishKitRuntimeUtil) {
RemoteEBRpcInvoker.getEbFormIdUtil = getEbFormIdUtil;
RemoteEBRpcInvoker.publishKitRuntimeUtil = publishKitRuntimeUtil;
}
}@Lazy defers dependency initialization until the first actual use, preventing premature static initialization.
Summary
Avoid static fields; prefer instance fields (recommended).
Initialize static variables with @PostConstruct.
Inject static dependencies via static setter methods.
Manually obtain beans using ApplicationContext.
Apply a singleton pattern to access non‑static dependencies.
Use @Lazy to lazily load dependencies.
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.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.
