2020-07-10
spring bean重复定义不报错以及注入失败分析
背景
@Configuration
public class GraySwitch {
@Bean(name = "sellerSupportXconfReader")
public XconfReader sellerSupportXconfReader(XconfClient xconfClient) {
XconfReader sellerSupportXconfReader = new XconfReader();
sellerSupportXconfReader.setXconfClient(xconfClient);
sellerSupportXconfReader.setGroup(SELLER_SUPPORT_GROUP_NAME);
return sellerSupportXconfReader;
}
@Autowired
private XconfReader sellerSupportXconfReader;
}
@Configuration
public class XconfClientConfiguration {
@Bean(name = "sellerSupportXconfReader")
public XconfReader sellerSupportXconfReader(XconfClient xconfClient) {
XconfReader sellerSupportXconfReader = new XconfReader();
sellerSupportXconfReader.setXconfClient(xconfClient);
sellerSupportXconfReader.setGroup(SELLER_SUPPORT_GROUP_NAME);
return sellerSupportXconfReader;
}
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(
@Qualifier("mysqlXconfReader") XconfReader mysqlXconfReader,
@Qualifier("redisXconfReader") XconfReader redisXconfReader,
@Qualifier("sellerSupportXconfReader") XconfReader sellerSupportXconfReader) {
PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();
placeholderConfigurer.setPropertiesArray(mysqlXconfReader.getProperties(), redisXconfReader.getProperties(),
sellerSupportXconfReader.getProperties());
return placeholderConfigurer;
}
}
问题1
现象
定义了两个name为sellerSupportXconfReader的bean,但没有报错
分析
- 现象1是因为DefaultListableBeanFactory中有这么一行代码:
private boolean allowBeanDefinitionOverriding = true;
在registerBeanDefinition方法中:
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
}
}
解决
public static void main(String[] args) {
SpringApplication application = new SpringApplication(SellerSupportApplication.class);
application.addInitializers(ac -> {
GenericApplicationContext gac = (GenericApplicationContext) ac;
gac.setAllowBeanDefinitionOverriding(false);
});
application.run(args);
}
问题2
现象
GraySwitch中的sellerSupportXconfReader为null,但启动能成功
分析
要搞清楚原因,必须先熟悉spring context加载的过程
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
//other codes
public void refresh() throws BeansException, IllegalStateException {
//other codes
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
//other codes
}
//other codes
}
在invokeBeanFactoryPostProcessors
中会加载所有的BeanFactoryPostProcessor
。
final class PostProcessorRegistrationDelegate {
//other codes
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//other codes
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
}
}
而Bean的属性填充在AbstractAutowireCapableBeanFactory#populateBean
中实现
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//other codes
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//other codes
}
Autowired注解的属性是通过AutowiredAnnotationBeanPostProcessor
注入的,依赖检查也是在这个类
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
而BeanPostProcessor
是在registerBeanPostProcessors
方法中初始化。
PropertySourcesPlaceholderConfigurer
恰好实现了BeanFactoryPostProcessor
,所以会在invokeBeanFactoryPostProcessors
这个阶段加载。而PropertySourcesPlaceholderConfigurer
依赖sellerSupportXconfReader
,后者又依赖GraySwitch
,GraySwitch
又通过Autowired
依赖sellerSupportXconfReader
。而此时BeanPostProcessor
还没初始化,所以不会对GraySwitch
赋值,容器也不会初始化失败。
解决
把sellerSupportXconfReader定义移到其他类能解决这个问题。或者propertySourcesPlaceholderConfigurer去掉对sellerSupportXconfReader的依赖。