分享自己在Java方面的所思所想,希望你看完之后能有更多更深入的了解
本人微信公众号(jwfy的学习分享),欢迎关注~
在开发中可能会约定一个bean使用一个不同的name,可是随着引入的第三方库越来越多,就有可能就会出现名字相同的bean。那么问题来了,多个name相同的bean,spring是如何处理的呢?是只保留第一个还是覆盖保留最后一个又或者是抛出异常明确名称不能重复,又或者业务的因素明确了不能一致的情况?接下来我们看看这个同名bean的问题。
说起同名bean,肯定要提到allowBeanDefinitionOverriding,这个关键字官方介绍是
Whether to allow re-registration of a different definition with the same name,当遇到同样的名字的时候,是否允许覆盖注册。
把代码定位到具体的位置 DefaultLiatableBeanFactory 文件
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { .... BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { // 当发现了重名的bean之后,而且不允许出现重名bean则抛出异常 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } // 用新的bean替换之前旧的bean this.beanDefinitionMap.put(beanName, beanDefinition);....
发现几个疑问,可以实践下
- 什么叫新的bean、如何界定
- 如何修改allowBeanDefinitionOverriding值
如何界定新的bean
已经设置好了两个xml,各自包含了一个同名的bean,只是参数不一致而已
- 情况1
context1.xml 在前, context.xml 在后
- 情况2
context.xml 在前, context1.xml 在后
看在读取xml解析的时候同样可以知道,答案已经很明显了,spring是按照文件列表一个一个扫描注册的,所以最后保留的是后一个文件的bean
如何修改allowBeanDefinitionOverriding值
解决的思路肯定是要在真正的解析bean之前修改该值,而且要在defaultlistablebeanfactory生成之后。
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); // 已经存在bean工厂,现在清空 } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); // 创建bean工厂 beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); // 自定义设入bean工厂的 loadBeanDefinitions(beanFactory); // 开始加载xml进行解析操作,无法修改bean工厂 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }}protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) {beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); // 把Application本身的是否可覆盖bean值赋值给bean工厂 } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); // 赋值是否允许循环引用 }}
那么我们能够动刀的地方只能是customizeBeanFactory了,代码如下
public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[]{"context.xml