2
votes

Using Spring 3.0.x, I'm running into an issue where a Bean init-method is running, and as part of it fetches some information, and then in another thread (original init() thread waits on the other threads to complete) tries to get one or more Beans based on that information retrieve. Problem is, these other Beans are singleton as well and haven't been initialized yet. There's a synchronized() block down in DefaultSingletonBeanRegistry in the getSingleton() methods.

The problem arises that I'm trying to get/initialize a Bean while I'm currently initializing a Bean, so I get stuck with the main thread in the init() method, and another thread trying to get another singleton Bean, and is blocked because the 1st thread has the lock.

So, the way I see it, I have 2 options:

1) Get Spring to run a method AFTER the singleton has been fully created that performs the actual data fetch and processing 2) Come up with message passing to which will give the data back to the main thread to then process them all within it since it already has the monitor lock

Thoughts? Ideas? How would I get #1 to work?

4
Are the singletons lazy loaded or not? Do you know these dependecies before hand, or are they derived in the init method based on some computation? - nicholas.hauschild
No, they are not set to lazily load, and I don't know what the dependencies are at compile time because they come from an API call that is made during the init() call. - Drizzt321

4 Answers

5
votes

Have you tried implementing the InitializingBean interface

class MyBean implements InitializingBean{

    @Override
    public void afterPropertiesSet(){
       // fetch information, etc
    }
}

According to the docs:

Interface to be implemented by beans that need to react once all their properties have been > set by a BeanFactory: for example, to perform custom initialization...

2
votes

You could implement the Lifecycle interface. The lifecycle callbacks happen when start()/stop() is called on the enclosing subclass of AbstractApplicationContext, which happens after all singleton beans of have been initialized (dependencies injected, and init methods called). The lifecycle callbacks also follow dependency order just like initialization does.

1
votes

You don't mention what kind of configuration you are using (annotation based or XML based), but in XML bean configuration, you can use a depends-on attribute to ensure that the sequence of beans that you need instantiated are done in the proper order.

For example, if you have two beans:

<bean id="bean1" class="my.package.class" />
<bean id="bean2" class="my.package.class2" />
<bean id="bean3" class="my.package.class3" depends-on"bean1, bean2" />

In this case, bean1 and bean2 will be instantiated in unconfirmed order. Spring attempts to instantiate based on the order of the XML file, but there is no guarantee to that. However, bean3 is guaranteed not to be instantiated prior to bean1 and bean2 being instantiated.

I do not know if this will rectify your race condition, but hopefully it should help.

Worst case scenario, you can always instantiate all the beans, and once instantiated, you can use FactoryMethodInvokingBean to call a static method once the bean is instantiated. Once again, make sure you use depends-on to ensure that the FactoryMethodInvokingBean is called once the singleton bean is instantiated.

0
votes

If anyone is looking for a more current answer that is not tied to a specific framework (like Spring), Java provides the @PostConstruct annotation that accomplishes the same thing. Using annotation-based config with Spring will recognize this annotation and execute a method annotated with @PostConstruct after the managed bean is initialized.

Perks include:

  • You're removing the Spring dependency from your class
  • You can name the method whatever you want

Why use @PostConstruct?

Some practical examples