Resolve a wired problem (static variable is not set) related to spring-dev-tools

Got a wired problem (NPE). Only happens at dev env.

The detail is , we have a class which implements the ApplicationContextAware, and set the context to a static variable, to be used in none-Spring classes:

@Component
public class SpringContext implements ApplicationContextAware {

private static ApplicationContext context;

/**
* Returns the Spring Service instance of the given (@Service) class type if it exists. Returns null otherwise.
*/
public static <T extends Object> T getService(Class<T> serviceClass) {
return context.getBean(serviceClass);
}

@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {

// store ApplicationContext reference to access required beans later on
SpringContext.context = context;
}
}

Very simple code. The problem is that, when the app is running, the context is null.

By debugging, I found that the setApplicationContext is called indeed before the get method. Quite wired.

I thought it was a multiple threading problem (Race condition). Add volatile does not help.

Finally I add some code to print the current ClassLoader for setApplicationContext and getService. Then I found the reason:

The setApplicationContext is called with the RestartClassLoader, and the getService is called with the AppClassLoader.

That’s why the NPE happens: For JVM the code are calling 2 different classes. And that’s why it happens only at dev environment: SpringBoot will disable dev-tools automatically when running as a packed jar.

To fix, I just added

-Dspring.devtools.restart.enabled=false

When I debug the app (I do not need dev-tools).

And the issue is resolved.

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store