Alexey Buistov
Alexey Buistov

Reputation: 209

Accessing Spring context from non-spring component that is loaded at the same time with Spring

The cool enterprise app I'm working on is in the process of going Spring. That's very cool and exciting exercise to all the team, but also a huge source of stress. What we do is we gradually move legacy components to Spring context. Now what we have is a huuuge, I mean it, huuuuge component that is not piece of cake to spring-ify, and at the same time it needs to get access to some of the Spring beans.

Now here comes the problem: this component is being loaded at application startup (or bootstrap, whatever you prefer!). That means that there is a race condition between this guy and a Spring itself, so sometimes when I access the context from within that non-spring monstrosity, I get sweet and nice NPE. Which basically means that at the time we need that context, it's not yet initialized!

You might be curious how exactly we're accessing the context: and the answer is - it's a standard AppContextProvider pattern.

public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext ctx;


    public void setApplicationContext(ApplicationContext applicationContext) {
        ctx = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return ctx;
    }

}

The ideal workaround for me in this case would be to tell Spring to notify that non-spring component "Okay, I'm up!", and perform all actions that require the context only after that. Is this actually possible?

Thanks in advance!

Upvotes: 3

Views: 2588

Answers (2)

axtavt
axtavt

Reputation: 242726

Take a look at the mechanism of context events.

Perhaps you can block getApplicationConext() until receiving of ContextRefreshedEvent (if it wouldn't create deadlocks):

public class ApplicationContextProvider implements ApplicationListener<ContextRefreshedEvent> {

    private static ApplicationContext ctx;
    private static Object lock = new Object();

    public void onApplicationEvent(ContextRefreshedEvent e) {
        synchronized (lock) {
            ctx = e.getApplicationContext();
            lock.notifyAll();
        }
    }

    public static ApplicationContext getApplicationContext() {
        synchronized (lock) {
            while (ctx == null) lock.wait();
            return ctx;
        }
    }
}

Upvotes: 1

gkamal
gkamal

Reputation: 21000

The correct way to make the application context available to non-spring beans is to use the ContextSingletonBeanFactoryLocator.

Take a look at this answer for more details.

Upvotes: 2

Related Questions