Sping中@Configuration@Bean如果出现bean的覆盖,会怎么处理?

前言

不建议写这么奇葩的代码!!!
这就有点像考试喜欢出的试题,有一堆overload和override的代码,选择题选择调用的是哪个。
不建议写这种让人看着费劲的代码。

问题引出

言归正传,如果有一个这样的配置类,[@Bean](https://my.oschina.net/bean) 注解了相同name = "cupcake"的bean:

1public class BeanOverrideConfig { 2 @Bean(name = "cupcake") 3 public Cupcake cupcake1() { 4 Cupcake cupcake = new Cupcake(); 5 cupcake.setName("Cupcake1"); 6 return cupcake; 7 } 8 9 @Bean(name = "cupcake") 10 public Cupcake cupcake2() { 11 Cupcake cupcake = new Cupcake(); 12 cupcake.setName("Cupcake2"); 13 return cupcake; 14 } 15 16}

下面这个测试类能通过测试吗?注意最后一行代码Assert.assertEquals("Cupcake1", cupcake.getName());

1public class BeanOverrideTest { 2 private ApplicationContext ctx = null; 3 4 @Before 5 public void setUp() { 6 ctx = new AnnotationConfigApplicationContext(BeanOverrideConfig.class); 7 } 8 9 @Test 10 public void testGetBean() { 11 Cupcake cupcake = ctx.getBean(Cupcake.class); 12 Assert.assertNotNull(cupcake); 13 Assert.assertEquals("Cupcake1", cupcake.getName()); 14 } 15 16}

结果

测试通过!

原因

Spring对configuration class的加载
加载BeanDefinition的过程中有一步:

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(BeanMethod)

在这个方法中会判断现在的beanName在现有的beanDefinitionMap中是否已存在,然后决定是否覆盖。是否覆盖的策略如下org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.isOverriddenByExistingDefinition(BeanMethod, String)

1// Is the existing bean definition one that was created from a configuration class? 2// -> allow the current bean method to override, since both are at second-pass level. 3// However, if the bean method is an overloaded case on the same configuration class, 4// preserve the existing bean definition. 5if (existingBeanDef instanceof ConfigurationClassBeanDefinition) { 6 ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef; 7 return ccbd.getMetadata().getClassName().equals( 8 beanMethod.getConfigurationClass().getMetadata().getClassName()); 9}

源码里说的很清楚了,如果来自不同层级的bean method,允许覆盖,如果是the same configuration class,preserve the existing bean definition(同一configuration class的overload,保留先前的)。
回到我们的测试类,即保留方法public Cupcake cupcake1()对应的bean definition,最后测试的时候getName就返回Cupcake1。

深入

如果是下面这种配置和测试:

1public class BeanOverrideConfig1 { 2 @Bean(name = "cupcake") 3 public Cupcake cupcake1() { 4 Cupcake cupcake = new Cupcake(); 5 cupcake.setName("Cupcake1"); 6 return cupcake; 7 } 8 9} 10 11public class BeanOverrideConfig2 { 12 13 @Bean(name = "cupcake") 14 public Cupcake cupcake2() { 15 Cupcake cupcake = new Cupcake(); 16 cupcake.setName("Cupcake2"); 17 return cupcake; 18 } 19 20} 21 22public class BeanOverrideTest { 23 private ApplicationContext ctx = null; 24 25 @Before 26 public void setUp() { 27 ctx = new AnnotationConfigApplicationContext(BeanOverrideConfig1.class, BeanOverrideConfig2.class); 28 } 29 30 @Test 31 public void testOverride() { 32 Cupcake cupcake = ctx.getBean(Cupcake.class); 33 Assert.assertNotNull(cupcake); 34 Assert.assertEquals("Cupcake2", cupcake.getName()); 35 } 36 37}

很显然测试能通过,即会覆盖。

@Import呢?

如果是这种情况呢?

1@Import(BeanOverrideConfig2.class) 2public class BeanOverrideConfig1 { 3 @Bean(name = "cupcake") 4 public Cupcake cupcake1() { 5 Cupcake cupcake = new Cupcake(); 6 cupcake.setName("Cupcake1"); 7 return cupcake; 8 } 9 10} 11 12public class BeanOverrideConfig2 { 13 14 @Bean(name = "cupcake") 15 public Cupcake cupcake2() { 16 Cupcake cupcake = new Cupcake(); 17 cupcake.setName("Cupcake2"); 18 return cupcake; 19 } 20 21} 22 23public class BeanOverrideTest { 24 private ApplicationContext ctx = null; 25 26 @Before 27 public void setUp() { 28 ctx = new AnnotationConfigApplicationContext(BeanOverrideConfig1.class); 29 } 30 31 @Test 32 public void testOverride() { 33 Cupcake cupcake = ctx.getBean(Cupcake.class); 34 Assert.assertNotNull(cupcake); 35 Assert.assertEquals("Cupcake1", cupcake.getName()); 36 } 37 38}

测试通过,这种@Import的情况也没认为是同一配置类,不会覆盖。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Spring 学习笔记(三):Spring Bean

1Bean配置Spring可以看做是一个管理Bean的工厂,开发者需要将Bean配置在XML或者Properties配置文件中。实际开发中常使用XML的格式,其中<bean中的属性或子元素如下:id:Bean在BeanFactory中的唯一标识,在代码中通过BeanFac