2

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?

Drizzt321
  • 993
  • 13
  • 27
  • 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 Feb 02 '12 at 02:11
  • 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 Feb 02 '12 at 17:55

4 Answers4

5

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...

driangle
  • 11,601
  • 5
  • 47
  • 54
  • I have seen this, but does this get called before or after Spring has completed the initialization of the Bean, and gotten out of the DefaultSingletonBeanRegistry class and released the lock that's causing the problem? Maybe my google-fu is failing me, but I haven't been able to find a really good diagram showing the phases and where they take place for Bean initialization. – Drizzt321 Feb 02 '12 at 17:54
  • what are you definining as "initialization of the bean"? This is called after all the bean properties have been set (all \@Autowired and \@Value fields). So yes, this should be called after the bean has been initialized, however I don't know the exact details of whether it has gotten out of the DefaultSingletonBeanRegistry class. It would help if you posted your initialization code which is causing issues. But I would encourage you to try this answer first. – driangle Feb 02 '12 at 18:13
2

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.

Dev
  • 11,919
  • 3
  • 40
  • 53
1

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.

Eric B.
  • 23,425
  • 50
  • 169
  • 316
  • Using XML based, but I don't know all of the bean names I will be trying to access, since the names are determined by an API call to another system, so I can't easily set that up ahead of time. – Drizzt321 Feb 02 '12 at 17:47
  • Have you tried setting lazy-init="false" to your beans to ensure that they are initialized on startup? – Eric B. Feb 02 '12 at 19:15
0

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

ithinkisam
  • 714
  • 8
  • 10