Search code examples
javaspringspring-beanspring-ioc

Spring bean creation flow: how to know when it is finished?


I have a spring application and there is a scheduled logic which produces prototype beans at fixed rate.

Everything works fine on my laptop but after deploying it to server my app fails to start due to:

2016-12-13 04:13:01.885 ERROR 4688 --- [TaskScheduler-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task.
...
BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'metaDataSourceAdvisor': Singleton bean creation not allowed
 while the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
...

This is the first scheduled call. Looks like a timing issue. On my laptop application initializes much faster and nothing wrong happens for the first scheduled call (which produces prototype beans).

Is there a way to get to know the current state of Spring bean creation flow so I can check it in scheduled logic and produce nothing when app creation is not finished?

Thanks!


Solution

  • Looking at the Spring source (4.3.3 and 4.2.2) this only happens in one location DefaultSingletonBeanRegistry.getSingleton(), and only when the initialisation of the spring context has failed, or you have explicitly closed it. Spring uses a single thread (the calling thread) for creating your beans and invoking the start lifecycle methods, so the exception you found should only be possible if you violate this principle.

    • When you say scheduled task, do you mean scheduled by Spring (using @Scheduled), or do you have your own scheduling logic?
    • Do you start any threads in you application, and if so, does the bean owning the thread implement Spring's Lifecycle or SmartLifecycle interfaces?

    I have seen a lot of developers that start threads in a bean constructor, this is a very bad idea. If you have a bean with lifecycle (thread, resource pool), you should always use the LifeCycle interface, and create your resource in start(), and clean it up in stop(). This is a good idea because start() is called after every eager singleton has been instantiated and the context completely wired, so no threads gets created unless every bean can be constructed.