Hi. I am getting a ConcurrentModificationException exception in the Spring's InjectionMetadata class (located in the org.springframework.beans.factory.annotation package) when creating an instance of prototype bean in a multithreaded environment.

Here's the stack of the exception (only Spring portion of it):

Code:
Thread [MaintenanceTasksJob] (Suspended (exception ConcurrentModificationException))                  
LinkedHashMap$KeyIterator(LinkedHashMap$LinkedHashIterator<T>).remove() line: 364
InjectionMetadata.checkConfigMembers(RootBeanDefinition) line: 72
AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(RootBeanDefinition, Class, String) line: 216
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).applyMergedBeanDefinitionPostProcessors(RootBeanDefinition, Class, String) line: 789
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[]) line: 487
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBean(String, RootBeanDefinition, Object[]) line: 450
DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class<T>, Object[], boolean) line: 309
DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 189
ClassPathXmlApplicationContext(AbstractApplicationContext).getBean(String) line: 1044
I think I know what's going on here. The AbstractAutowireCapableBeanFactory.doCreateBean() method (5th from the top of the stack) synchronizes on the bean definition object:

Code:
synchronized (mbd.postProcessingLock) {
  if (!mbd.postProcessed) {
    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    mbd.postProcessed = true;
  }
}
However, two methods later, in the AutowiredAnnotationBeanPostProcessor.postProcessMe rgedBeanDefinition(), an instance of the InjectionMetadata class for the bean is fetched based on the bean class and not bean definition object, which means that instances of InjectionMetadata are cached per bean class. Therefore despite the fact that two threads cannot enter the same post processing section for the same bean instance, they can enter it for the same bean class and therefore will share the same InjectionMetadata instance. Thus in the next method:

Code:
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
  for (Iterator<InjectedElement> it = this.injectedElements.iterator(); it.hasNext();) {
    if (!beanDefinition.isExternallyManagedConfigMember(member))
      beanDefinition.registerExternallyManagedConfigMember(member);
    } else {
      it.remove();
    }
  }
}
The it.remove() will potentially throw the exception.

To summarize the problem: when defining two or more prototype beans based on the same class in a multithreaded environment, a ConcurrentModificationException may be thrown in the InjectionMetadata class.

Am I right in my analysis?

Thanks.