diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java
index 1e57dd3f74..fc6ee6d46c 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2016 the original author or authors.
+ * Copyright 2012-2017 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.
@@ -29,7 +29,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
@@ -43,13 +42,14 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.ResolvableType;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.StandardMethodMetadata;
+import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
- * A registry of the bean types that are contained in a {@link ListableBeanFactory}.
- * Provides similar functionality to
+ * A registry of the bean types that are contained in a
+ * {@link DefaultListableBeanFactory}. Provides similar functionality to
* {@link ListableBeanFactory#getBeanNamesForType(Class, boolean, boolean)} but is
* optimized for use by {@link OnBeanCondition} based on the following assumptions:
*
@@ -62,12 +62,43 @@ import org.springframework.util.StringUtils;
* @author Andy Wilkinson
* @since 1.2.0
*/
-abstract class BeanTypeRegistry {
+final class BeanTypeRegistry implements SmartInitializingSingleton {
private static final Log logger = LogFactory.getLog(BeanTypeRegistry.class);
static final String FACTORY_BEAN_OBJECT_TYPE = "factoryBeanObjectType";
+ private static final String BEAN_NAME = BeanTypeRegistry.class.getName();
+
+ private final DefaultListableBeanFactory beanFactory;
+
+ private final Map> beanTypes = new HashMap>();
+
+ private int lastBeanDefinitionCount = 0;
+
+ private BeanTypeRegistry(DefaultListableBeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+ /**
+ * Factory method to get the {@link BeanTypeRegistry} for a given {@link BeanFactory}.
+ * @param beanFactory the source bean factory
+ * @return the {@link BeanTypeRegistry} for the given bean factory
+ */
+ public static BeanTypeRegistry create(ListableBeanFactory beanFactory) {
+ Assert.isInstanceOf(DefaultListableBeanFactory.class, beanFactory);
+ DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
+ Assert.isTrue(listableBeanFactory.isAllowEagerClassLoading(),
+ "Bean factory must allow eager class loading");
+ if (!listableBeanFactory.containsLocalBean(BEAN_NAME)) {
+ BeanDefinition bd = new RootBeanDefinition(BeanTypeRegistry.class);
+ bd.getConstructorArgumentValues().addIndexedArgumentValue(0, beanFactory);
+ listableBeanFactory.registerBeanDefinition(BEAN_NAME, bd);
+
+ }
+ return listableBeanFactory.getBean(BEAN_NAME, BeanTypeRegistry.class);
+ }
+
/**
* Return the names of beans matching the given type (including subclasses), judging
* from either bean definitions or the value of {@code getObjectType} in the case of
@@ -76,7 +107,81 @@ abstract class BeanTypeRegistry {
* @return the names of beans (or objects created by FactoryBeans) matching the given
* object type (including subclasses), or an empty set if none
*/
- public abstract Set getNamesForType(Class> type);
+ Set getNamesForType(Class> type) {
+ 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);
+ }
+ }
+ this.lastBeanDefinitionCount = this.beanFactory.getBeanDefinitionCount();
+ }
+ Set matches = new LinkedHashSet();
+ for (Map.Entry> entry : this.beanTypes.entrySet()) {
+ if (entry.getValue() != null && type.isAssignableFrom(entry.getValue())) {
+ matches.add(entry.getKey());
+ }
+ }
+ return matches;
+ }
+
+ @Override
+ public void afterSingletonsInstantiated() {
+ // We're done at this point, free up some memory
+ this.beanTypes.clear();
+ this.lastBeanDefinitionCount = 0;
+ }
+
+ private void addBeanType(String name) {
+ if (this.beanFactory.containsSingleton(name)) {
+ this.beanTypes.put(name, this.beanFactory.getType(name));
+ }
+ else if (!this.beanFactory.isAlias(name)) {
+ addBeanTypeForNonAliasDefinition(name);
+ }
+ }
+
+ private void addBeanTypeForNonAliasDefinition(String name) {
+ try {
+ String factoryName = BeanFactory.FACTORY_BEAN_PREFIX + name;
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) this.beanFactory
+ .getMergedBeanDefinition(name);
+ if (!beanDefinition.isAbstract()
+ && !requiresEagerInit(beanDefinition.getFactoryBeanName())) {
+ if (this.beanFactory.isFactoryBean(factoryName)) {
+ Class> factoryBeanGeneric = getFactoryBeanGeneric(this.beanFactory,
+ beanDefinition, name);
+ this.beanTypes.put(name, factoryBeanGeneric);
+ this.beanTypes.put(factoryName,
+ this.beanFactory.getType(factoryName));
+ }
+ else {
+ this.beanTypes.put(name, this.beanFactory.getType(name));
+ }
+ }
+ }
+ 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) {
+ if (BeanTypeRegistry.logger.isDebugEnabled()) {
+ BeanTypeRegistry.logger.debug("Ignoring " + message + " '" + name + "'", ex);
+ }
+ }
+
+ private boolean requiresEagerInit(String factoryBeanName) {
+ return (factoryBeanName != null && this.beanFactory.isFactoryBean(factoryBeanName)
+ && !this.beanFactory.containsSingleton(factoryBeanName));
+ }
/**
* Attempt to guess the type that a {@link FactoryBean} will return based on the
@@ -86,9 +191,8 @@ abstract class BeanTypeRegistry {
* @param name the name of the bean
* @return the generic type of the {@link FactoryBean} or {@code null}
*/
- protected final Class> getFactoryBeanGeneric(
- ConfigurableListableBeanFactory beanFactory, BeanDefinition definition,
- String name) {
+ private Class> getFactoryBeanGeneric(ConfigurableListableBeanFactory beanFactory,
+ BeanDefinition definition, String name) {
try {
return doGetFactoryBeanGeneric(beanFactory, definition, name);
}
@@ -198,177 +302,4 @@ abstract class BeanTypeRegistry {
return null;
}
- /**
- * Factory method to get the {@link BeanTypeRegistry} for a given {@link BeanFactory}.
- * @param beanFactory the source bean factory
- * @return the {@link BeanTypeRegistry} for the given bean factory
- */
- public static BeanTypeRegistry get(ListableBeanFactory beanFactory) {
- if (beanFactory instanceof DefaultListableBeanFactory) {
- DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
- if (listableBeanFactory.isAllowEagerClassLoading()) {
- return OptimizedBeanTypeRegistry.getFromFactory(listableBeanFactory);
- }
- }
- return new DefaultBeanTypeRegistry(beanFactory);
- }
-
- /**
- * Default (non-optimized) {@link BeanTypeRegistry} implementation.
- */
- static class DefaultBeanTypeRegistry extends BeanTypeRegistry {
-
- private final ListableBeanFactory beanFactory;
-
- DefaultBeanTypeRegistry(ListableBeanFactory beanFactory) {
- this.beanFactory = beanFactory;
- }
-
- @Override
- public Set getNamesForType(Class> type) {
- Set result = new LinkedHashSet();
- result.addAll(Arrays
- .asList(this.beanFactory.getBeanNamesForType(type, true, false)));
- if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
- collectBeanNamesForTypeFromFactoryBeans(result,
- (ConfigurableListableBeanFactory) this.beanFactory, type);
- }
- return result;
- }
-
- private void collectBeanNamesForTypeFromFactoryBeans(Set result,
- ConfigurableListableBeanFactory beanFactory, Class> type) {
- String[] names = beanFactory.getBeanNamesForType(FactoryBean.class, true,
- false);
- for (String name : names) {
- name = BeanFactoryUtils.transformedBeanName(name);
- BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
- Class> generic = getFactoryBeanGeneric(beanFactory, beanDefinition,
- name);
- if (generic != null && ClassUtils.isAssignable(type, generic)) {
- result.add(name);
- }
- }
- }
-
- }
-
- /**
- * {@link BeanTypeRegistry} optimized for {@link DefaultListableBeanFactory}
- * implementations that allow eager class loading.
- */
- static class OptimizedBeanTypeRegistry extends BeanTypeRegistry
- implements SmartInitializingSingleton {
-
- private static final String BEAN_NAME = BeanTypeRegistry.class.getName();
-
- private final DefaultListableBeanFactory beanFactory;
-
- private final Map> beanTypes = new HashMap>();
-
- private int lastBeanDefinitionCount = 0;
-
- OptimizedBeanTypeRegistry(DefaultListableBeanFactory beanFactory) {
- this.beanFactory = beanFactory;
- }
-
- @Override
- public void afterSingletonsInstantiated() {
- // We're done at this point, free up some memory
- this.beanTypes.clear();
- this.lastBeanDefinitionCount = 0;
- }
-
- @Override
- public Set getNamesForType(Class> type) {
- 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);
- }
- }
- this.lastBeanDefinitionCount = this.beanFactory.getBeanDefinitionCount();
- }
- Set matches = new LinkedHashSet();
- for (Map.Entry> entry : this.beanTypes.entrySet()) {
- if (entry.getValue() != null && type.isAssignableFrom(entry.getValue())) {
- matches.add(entry.getKey());
- }
- }
- return matches;
- }
-
- private void addBeanType(String name) {
- if (this.beanFactory.containsSingleton(name)) {
- this.beanTypes.put(name, this.beanFactory.getType(name));
- }
- else if (!this.beanFactory.isAlias(name)) {
- addBeanTypeForNonAliasDefinition(name);
- }
- }
-
- private void addBeanTypeForNonAliasDefinition(String name) {
- try {
- String factoryName = BeanFactory.FACTORY_BEAN_PREFIX + name;
- RootBeanDefinition beanDefinition = (RootBeanDefinition) this.beanFactory
- .getMergedBeanDefinition(name);
- if (!beanDefinition.isAbstract()
- && !requiresEagerInit(beanDefinition.getFactoryBeanName())) {
- if (this.beanFactory.isFactoryBean(factoryName)) {
- Class> factoryBeanGeneric = getFactoryBeanGeneric(
- this.beanFactory, beanDefinition, name);
- this.beanTypes.put(name, factoryBeanGeneric);
- this.beanTypes.put(factoryName,
- this.beanFactory.getType(factoryName));
- }
- else {
- this.beanTypes.put(name, this.beanFactory.getType(name));
- }
- }
- }
- 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) {
- if (BeanTypeRegistry.logger.isDebugEnabled()) {
- BeanTypeRegistry.logger.debug("Ignoring " + message + " '" + name + "'",
- ex);
- }
- }
-
- private boolean requiresEagerInit(String factoryBeanName) {
- return (factoryBeanName != null
- && this.beanFactory.isFactoryBean(factoryBeanName)
- && !this.beanFactory.containsSingleton(factoryBeanName));
- }
-
- /**
- * Returns the {@link OptimizedBeanTypeRegistry} for the given bean factory.
- * @param factory the source {@link BeanFactory}
- * @return the {@link OptimizedBeanTypeRegistry}
- */
- public static OptimizedBeanTypeRegistry getFromFactory(
- DefaultListableBeanFactory factory) {
- if (!factory.containsLocalBean(BEAN_NAME)) {
- BeanDefinition bd = new RootBeanDefinition(
- OptimizedBeanTypeRegistry.class);
- bd.getConstructorArgumentValues().addIndexedArgumentValue(0, factory);
- factory.registerBeanDefinition(BEAN_NAME, bd);
-
- }
- return factory.getBean(BEAN_NAME, OptimizedBeanTypeRegistry.class);
- }
-
- }
-
}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java
index 99c828412a..33a90b440d 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java
@@ -184,7 +184,7 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
private void collectBeanNamesForType(Set result,
ListableBeanFactory beanFactory, Class> type, boolean considerHierarchy) {
- result.addAll(BeanTypeRegistry.get(beanFactory).getNamesForType(type));
+ result.addAll(BeanTypeRegistry.create(beanFactory).getNamesForType(type));
if (considerHierarchy && beanFactory instanceof HierarchicalBeanFactory) {
BeanFactory parent = ((HierarchicalBeanFactory) beanFactory)
.getParentBeanFactory();