diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java index 4e9c176994..d013cc55bd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java @@ -77,7 +77,7 @@ final class BeanTypeRegistry implements SmartInitializingSingleton { private final Map> beanTypes = new HashMap<>(); - private int lastBeanDefinitionCount = 0; + private final Map beanDefinitions = new HashMap<>(); private BeanTypeRegistry(DefaultListableBeanFactory beanFactory) { this.beanFactory = beanFactory; @@ -142,7 +142,7 @@ final class BeanTypeRegistry implements SmartInitializingSingleton { public void afterSingletonsInstantiated() { // We're done at this point, free up some memory this.beanTypes.clear(); - this.lastBeanDefinitionCount = 0; + this.beanDefinitions.clear(); } private void addBeanType(String name) { @@ -155,9 +155,22 @@ final class BeanTypeRegistry implements SmartInitializingSingleton { } private void addBeanTypeForNonAliasDefinition(String name) { + addBeanTypeForNonAliasDefinition(name, getBeanDefinition(name)); + } + + private RootBeanDefinition getBeanDefinition(String name) { + try { + return (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(name); + } + catch (BeanDefinitionStoreException ex) { + logIgnoredError("unresolvable metadata in bean definition", name, ex); + return null; + } + } + + private void addBeanTypeForNonAliasDefinition(String name, + RootBeanDefinition beanDefinition) { try { - RootBeanDefinition beanDefinition = (RootBeanDefinition) this.beanFactory - .getMergedBeanDefinition(name); if (!beanDefinition.isAbstract() && !requiresEagerInit(beanDefinition.getFactoryBeanName())) { String factoryName = BeanFactory.FACTORY_BEAN_PREFIX + name; @@ -172,15 +185,12 @@ final class BeanTypeRegistry implements SmartInitializingSingleton { this.beanTypes.put(name, this.beanFactory.getType(name)); } } + this.beanDefinitions.put(name, beanDefinition); } catch (CannotLoadBeanClassException ex) { // Probably contains a placeholder logIgnoredError("bean class loading failure for bean", name, ex); } - catch (BeanDefinitionStoreException ex) { - // Probably contains a placeholder - logIgnoredError("unresolvable metadata in bean definition", name, ex); - } } private void logIgnoredError(String message, String name, Exception ex) { @@ -195,15 +205,24 @@ final class BeanTypeRegistry implements SmartInitializingSingleton { } private void updateTypesIfNecessary() { - if (this.lastBeanDefinitionCount != this.beanFactory.getBeanDefinitionCount()) { - Iterator names = this.beanFactory.getBeanNamesIterator(); - while (names.hasNext()) { - String name = names.next(); - if (!this.beanTypes.containsKey(name)) { - addBeanType(name); + Iterator names = this.beanFactory.getBeanNamesIterator(); + while (names.hasNext()) { + String name = names.next(); + if (!this.beanTypes.containsKey(name)) { + addBeanType(name); + } + else { + if (!this.beanFactory.isAlias(name) + && !this.beanFactory.containsSingleton(name)) { + RootBeanDefinition beanDefinition = getBeanDefinition(name); + RootBeanDefinition existingDefinition = this.beanDefinitions.put(name, + beanDefinition); + if (existingDefinition != null + && !beanDefinition.equals(existingDefinition)) { + addBeanTypeForNonAliasDefinition(name, beanDefinition); + } } } - this.lastBeanDefinitionCount = this.beanFactory.getBeanDefinitionCount(); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java index 546b5f4836..5d6cfcc1ab 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -137,6 +137,16 @@ public class ConditionalOnBeanTests { assertThat(context.getBean("bar")).isEqualTo("bar"); } + @Test + public void conditionEvaluationConsidersChangeInTypeWhenBeanIsOverridden() { + this.context.register(OriginalDefinition.class, OverridingDefinition.class, + ConsumingConfiguration.class); + this.context.refresh(); + assertThat(this.context.containsBean("testBean")).isTrue(); + assertThat(this.context.getBean(Integer.class)).isEqualTo(1); + assertThat(this.context.getBeansOfType(ConsumingConfiguration.class)).isEmpty(); + } + @Configuration @ConditionalOnBean(name = "foo") protected static class OnBeanNameConfiguration { @@ -309,4 +319,35 @@ public class ConditionalOnBeanTests { } + @Configuration + public static class OriginalDefinition { + + @Bean + public String testBean() { + return "test"; + } + + } + + @Configuration + @ConditionalOnBean(String.class) + public static class OverridingDefinition { + + @Bean + public Integer testBean() { + return 1; + } + + } + + @Configuration + @ConditionalOnBean(String.class) + public static class ConsumingConfiguration { + + ConsumingConfiguration(String testBean) { + + } + + } + }