初始化 Spring Bean 时的竞争条件
Race condition when initialized Spring Bean
我正在使用 Java Spring 配置,很少有 bean 引用一个 bean。似乎所有 bean 都试图同时初始化 properties() bean,因为在服务启动时出现 ConcurrentModificationException(并非总是如此。1000 次中有 1 次出现此错误)-
ERR [main ] - org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericTaskExecutor' defined in class path resource [com/test/SpringConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.concurrent.Executor]: Factory method 'threadPoolTaskExecutor' threw exception; nested exception is java.util.ConcurrentModificationException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:483)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=11=](AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:893)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:142)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:95)
at Main.start(Main.java:27)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.concurrent.Executor]: Factory method 'threadPoolTaskExecutor' threw exception; nested exception is java.util.ConcurrentModificationException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:650)
... 16 more
Caused by: java.util.ConcurrentModificationException
at java.util.Hashtable$Enumerator.next(Hashtable.java:1387)
at java.util.Hashtable.putAll(Hashtable.java:523)
at com.test.SpringConfiguration.properties(DependencySpringConfiguration.java:43)
at com.test.SpringConfiguration.threadPoolTaskExecutor(DependencySpringConfiguration.java:69)
at com.test.SpringConfiguration$$EnhancerBySpringCGLIB$$c6bbb94b.CGLIB$threadPoolTaskExecutor[=11=](<generated>)
at com.test.SpringConfiguration$$EnhancerBySpringCGLIB$$c6bbb94b$$FastClassBySpringCGLIB$cff70.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
at com.test.SpringConfiguration$$EnhancerBySpringCGLIB$$c6bbb94b.threadPoolTaskExecutor(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 17 more
以下是 bean 定义。我的代码在调用“properties.putAll(System.getProperties())”时出错。我无法在 Spring 配置中找到我缺少的东西,因为异常很少出现所以必须是 bean 初始化之间的竞争条件 -
@Configuration
@EnableScheduling
public class DependencySpringConfiguration {
@Bean
public static Properties properties() {
Properties properties = new Properties();
properties.putAll(System.getProperties());
//do some formatting on properties data
return properties;
}
@Bean(name = "genericTaskExecutor")
@Primary
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = NumberUtils.toInt(properties().getProperty("generic-executor.core-pool.size"), 10);
log.info("Initial pool size for 'genericTaskExecutor' is {}", corePoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(50);
executor.setThreadNamePrefix("GenericTaskExecutor-");
executor.initialize();
return executor;
}
@Bean(name = "legacy")
public Executor legacyThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = NumberUtils.toInt(properties().getProperty("legacy-executor.core-pool.size"), 1);
log.info("Initial pool size for 'legacyTaskExecutor' is {}", corePoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("LegacyTaskExecutor-");
executor.initialize();
return executor;
}
@Bean(name = "reconTaskExecutor")
public Executor reconPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = NumberUtils.toInt(properties().getProperty("recon-executor.core-pool.size"), 2);
log.info("Initial pool size for 'reconTaskExecutor' is {}", corePoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("ReconTaskExecutor-");
executor.initialize();
return executor;
}
}
系统属性可以随时更改,因此您对 properties.putAll(System.getProperties())
的尝试会抛出 ConcurrentModificationException。那是因为 putAll 方法使用了一个迭代器。尝试 clone()
系统属性并改用克隆的实例。
properties.putAll(System.getProperties().clone());
我正在使用 Java Spring 配置,很少有 bean 引用一个 bean。似乎所有 bean 都试图同时初始化 properties() bean,因为在服务启动时出现 ConcurrentModificationException(并非总是如此。1000 次中有 1 次出现此错误)-
ERR [main ] - org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericTaskExecutor' defined in class path resource [com/test/SpringConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.concurrent.Executor]: Factory method 'threadPoolTaskExecutor' threw exception; nested exception is java.util.ConcurrentModificationException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:483)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=11=](AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:893)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:142)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:95)
at Main.start(Main.java:27)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.concurrent.Executor]: Factory method 'threadPoolTaskExecutor' threw exception; nested exception is java.util.ConcurrentModificationException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:650)
... 16 more
Caused by: java.util.ConcurrentModificationException
at java.util.Hashtable$Enumerator.next(Hashtable.java:1387)
at java.util.Hashtable.putAll(Hashtable.java:523)
at com.test.SpringConfiguration.properties(DependencySpringConfiguration.java:43)
at com.test.SpringConfiguration.threadPoolTaskExecutor(DependencySpringConfiguration.java:69)
at com.test.SpringConfiguration$$EnhancerBySpringCGLIB$$c6bbb94b.CGLIB$threadPoolTaskExecutor[=11=](<generated>)
at com.test.SpringConfiguration$$EnhancerBySpringCGLIB$$c6bbb94b$$FastClassBySpringCGLIB$cff70.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
at com.test.SpringConfiguration$$EnhancerBySpringCGLIB$$c6bbb94b.threadPoolTaskExecutor(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 17 more
以下是 bean 定义。我的代码在调用“properties.putAll(System.getProperties())”时出错。我无法在 Spring 配置中找到我缺少的东西,因为异常很少出现所以必须是 bean 初始化之间的竞争条件 -
@Configuration
@EnableScheduling
public class DependencySpringConfiguration {
@Bean
public static Properties properties() {
Properties properties = new Properties();
properties.putAll(System.getProperties());
//do some formatting on properties data
return properties;
}
@Bean(name = "genericTaskExecutor")
@Primary
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = NumberUtils.toInt(properties().getProperty("generic-executor.core-pool.size"), 10);
log.info("Initial pool size for 'genericTaskExecutor' is {}", corePoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(50);
executor.setThreadNamePrefix("GenericTaskExecutor-");
executor.initialize();
return executor;
}
@Bean(name = "legacy")
public Executor legacyThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = NumberUtils.toInt(properties().getProperty("legacy-executor.core-pool.size"), 1);
log.info("Initial pool size for 'legacyTaskExecutor' is {}", corePoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("LegacyTaskExecutor-");
executor.initialize();
return executor;
}
@Bean(name = "reconTaskExecutor")
public Executor reconPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = NumberUtils.toInt(properties().getProperty("recon-executor.core-pool.size"), 2);
log.info("Initial pool size for 'reconTaskExecutor' is {}", corePoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("ReconTaskExecutor-");
executor.initialize();
return executor;
}
}
系统属性可以随时更改,因此您对 properties.putAll(System.getProperties())
的尝试会抛出 ConcurrentModificationException。那是因为 putAll 方法使用了一个迭代器。尝试 clone()
系统属性并改用克隆的实例。
properties.putAll(System.getProperties().clone());