From 718d46adacd4a0d5ee43fc5a82a18b61af40d2fb Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 22 Jul 2020 18:42:53 +0200 Subject: [PATCH] Check for alias overriding bean definition of same name Closes gh-25430 --- .../support/DefaultListableBeanFactory.java | 15 ++++++-- .../ConfigurationClassPostProcessorTests.java | 34 ++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 12b4b46f47..178cb2a0f6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -95,8 +95,7 @@ import org.springframework.util.StringUtils; * operating on pre-resolved bean definition metadata objects. * *

Note that readers for specific bean definition formats are typically - * implemented separately rather than as bean factory subclasses: - * see for example {@link PropertiesBeanDefinitionReader} and + * implemented separately rather than as bean factory subclasses: see for example * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}. * *

For an alternative implementation of the @@ -1106,6 +1105,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto return isAllowBeanDefinitionOverriding(); } + /** + * Also checks for an alias overriding a bean definition of the same name. + */ + @Override + protected void checkForAliasCircle(String name, String alias) { + super.checkForAliasCircle(name, alias); + if (!isAllowBeanDefinitionOverriding() && containsBeanDefinition(alias)) { + throw new IllegalStateException("Cannot register alias '" + alias + + "' for name '" + name + "': Alias would override bean definition '" + alias + "'"); + } + } + @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { super.registerSingleton(beanName, singletonObject); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index a99e16e530..caf1063f1a 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,8 @@ import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DescriptiveResource; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.SyncTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -375,6 +377,18 @@ public class ConfigurationClassPostProcessorTests { .withMessageContaining(TestBean.class.getName()); } + @Test // gh-25430 + public void detectAliasOverride() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory(); + beanFactory.setAllowBeanDefinitionOverriding(false); + context.register(FirstConfiguration.class, SecondConfiguration.class); + assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessageContaining("alias 'taskExecutor'") + .withMessageContaining("name 'applicationTaskExecutor'") + .withMessageContaining("bean definition 'taskExecutor'"); + } + @Test public void configurationClassesProcessedInCorrectOrder() { beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(OverridingSingletonBeanConfig.class)); @@ -1266,6 +1280,24 @@ public class ConfigurationClassPostProcessorTests { } } + @Configuration + static class FirstConfiguration { + + @Bean + SyncTaskExecutor taskExecutor() { + return new SyncTaskExecutor(); + } + } + + @Configuration + static class SecondConfiguration { + + @Bean(name = {"applicationTaskExecutor", "taskExecutor"}) + SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() { + return new SimpleAsyncTaskExecutor(); + } + } + public static class ScopedProxyConsumer { @Autowired