001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory; 018 019import java.lang.annotation.Annotation; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.LinkedHashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.concurrent.ConcurrentHashMap; 026 027import org.springframework.beans.BeansException; 028import org.springframework.core.ResolvableType; 029import org.springframework.lang.Nullable; 030import org.springframework.util.Assert; 031import org.springframework.util.StringUtils; 032 033/** 034 * Convenience methods operating on bean factories, in particular 035 * on the {@link ListableBeanFactory} interface. 036 * 037 * <p>Returns bean counts, bean names or bean instances, 038 * taking into account the nesting hierarchy of a bean factory 039 * (which the methods defined on the ListableBeanFactory interface don't, 040 * in contrast to the methods defined on the BeanFactory interface). 041 * 042 * @author Rod Johnson 043 * @author Juergen Hoeller 044 * @author Chris Beams 045 * @since 04.07.2003 046 */ 047public abstract class BeanFactoryUtils { 048 049 /** 050 * Separator for generated bean names. If a class name or parent name is not 051 * unique, "#1", "#2" etc will be appended, until the name becomes unique. 052 */ 053 public static final String GENERATED_BEAN_NAME_SEPARATOR = "#"; 054 055 /** 056 * Cache from name with factory bean prefix to stripped name without dereference. 057 * @since 5.1 058 * @see BeanFactory#FACTORY_BEAN_PREFIX 059 */ 060 private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>(); 061 062 063 /** 064 * Return whether the given name is a factory dereference 065 * (beginning with the factory dereference prefix). 066 * @param name the name of the bean 067 * @return whether the given name is a factory dereference 068 * @see BeanFactory#FACTORY_BEAN_PREFIX 069 */ 070 public static boolean isFactoryDereference(@Nullable String name) { 071 return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); 072 } 073 074 /** 075 * Return the actual bean name, stripping out the factory dereference 076 * prefix (if any, also stripping repeated factory prefixes if found). 077 * @param name the name of the bean 078 * @return the transformed name 079 * @see BeanFactory#FACTORY_BEAN_PREFIX 080 */ 081 public static String transformedBeanName(String name) { 082 Assert.notNull(name, "'name' must not be null"); 083 if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { 084 return name; 085 } 086 return transformedBeanNameCache.computeIfAbsent(name, beanName -> { 087 do { 088 beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); 089 } 090 while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); 091 return beanName; 092 }); 093 } 094 095 /** 096 * Return whether the given name is a bean name which has been generated 097 * by the default naming strategy (containing a "#..." part). 098 * @param name the name of the bean 099 * @return whether the given name is a generated bean name 100 * @see #GENERATED_BEAN_NAME_SEPARATOR 101 * @see org.springframework.beans.factory.support.BeanDefinitionReaderUtils#generateBeanName 102 * @see org.springframework.beans.factory.support.DefaultBeanNameGenerator 103 */ 104 public static boolean isGeneratedBeanName(@Nullable String name) { 105 return (name != null && name.contains(GENERATED_BEAN_NAME_SEPARATOR)); 106 } 107 108 /** 109 * Extract the "raw" bean name from the given (potentially generated) bean name, 110 * excluding any "#..." suffixes which might have been added for uniqueness. 111 * @param name the potentially generated bean name 112 * @return the raw bean name 113 * @see #GENERATED_BEAN_NAME_SEPARATOR 114 */ 115 public static String originalBeanName(String name) { 116 Assert.notNull(name, "'name' must not be null"); 117 int separatorIndex = name.indexOf(GENERATED_BEAN_NAME_SEPARATOR); 118 return (separatorIndex != -1 ? name.substring(0, separatorIndex) : name); 119 } 120 121 122 // Retrieval of bean names 123 124 /** 125 * Count all beans in any hierarchy in which this factory participates. 126 * Includes counts of ancestor bean factories. 127 * <p>Beans that are "overridden" (specified in a descendant factory 128 * with the same name) are only counted once. 129 * @param lbf the bean factory 130 * @return count of beans including those defined in ancestor factories 131 * @see #beanNamesIncludingAncestors 132 */ 133 public static int countBeansIncludingAncestors(ListableBeanFactory lbf) { 134 return beanNamesIncludingAncestors(lbf).length; 135 } 136 137 /** 138 * Return all bean names in the factory, including ancestor factories. 139 * @param lbf the bean factory 140 * @return the array of matching bean names, or an empty array if none 141 * @see #beanNamesForTypeIncludingAncestors 142 */ 143 public static String[] beanNamesIncludingAncestors(ListableBeanFactory lbf) { 144 return beanNamesForTypeIncludingAncestors(lbf, Object.class); 145 } 146 147 /** 148 * Get all bean names for the given type, including those defined in ancestor 149 * factories. Will return unique names in case of overridden bean definitions. 150 * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans 151 * will get initialized. If the object created by the FactoryBean doesn't match, 152 * the raw FactoryBean itself will be matched against the type. 153 * <p>This version of {@code beanNamesForTypeIncludingAncestors} automatically 154 * includes prototypes and FactoryBeans. 155 * @param lbf the bean factory 156 * @param type the type that beans must match (as a {@code ResolvableType}) 157 * @return the array of matching bean names, or an empty array if none 158 * @since 4.2 159 * @see ListableBeanFactory#getBeanNamesForType(ResolvableType) 160 */ 161 public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, ResolvableType type) { 162 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 163 String[] result = lbf.getBeanNamesForType(type); 164 if (lbf instanceof HierarchicalBeanFactory) { 165 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 166 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 167 String[] parentResult = beanNamesForTypeIncludingAncestors( 168 (ListableBeanFactory) hbf.getParentBeanFactory(), type); 169 result = mergeNamesWithParent(result, parentResult, hbf); 170 } 171 } 172 return result; 173 } 174 175 /** 176 * Get all bean names for the given type, including those defined in ancestor 177 * factories. Will return unique names in case of overridden bean definitions. 178 * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" 179 * flag is set, which means that FactoryBeans will get initialized. If the 180 * object created by the FactoryBean doesn't match, the raw FactoryBean itself 181 * will be matched against the type. If "allowEagerInit" is not set, 182 * only raw FactoryBeans will be checked (which doesn't require initialization 183 * of each FactoryBean). 184 * @param lbf the bean factory 185 * @param type the type that beans must match (as a {@code ResolvableType}) 186 * @param includeNonSingletons whether to include prototype or scoped beans too 187 * or just singletons (also applies to FactoryBeans) 188 * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and 189 * <i>objects created by FactoryBeans</i> (or by factory methods with a 190 * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 191 * eagerly initialized to determine their type: So be aware that passing in "true" 192 * for this flag will initialize FactoryBeans and "factory-bean" references. 193 * @return the array of matching bean names, or an empty array if none 194 * @since 5.2 195 * @see ListableBeanFactory#getBeanNamesForType(ResolvableType, boolean, boolean) 196 */ 197 public static String[] beanNamesForTypeIncludingAncestors( 198 ListableBeanFactory lbf, ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { 199 200 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 201 String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit); 202 if (lbf instanceof HierarchicalBeanFactory) { 203 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 204 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 205 String[] parentResult = beanNamesForTypeIncludingAncestors( 206 (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit); 207 result = mergeNamesWithParent(result, parentResult, hbf); 208 } 209 } 210 return result; 211 } 212 213 /** 214 * Get all bean names for the given type, including those defined in ancestor 215 * factories. Will return unique names in case of overridden bean definitions. 216 * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans 217 * will get initialized. If the object created by the FactoryBean doesn't match, 218 * the raw FactoryBean itself will be matched against the type. 219 * <p>This version of {@code beanNamesForTypeIncludingAncestors} automatically 220 * includes prototypes and FactoryBeans. 221 * @param lbf the bean factory 222 * @param type the type that beans must match (as a {@code Class}) 223 * @return the array of matching bean names, or an empty array if none 224 * @see ListableBeanFactory#getBeanNamesForType(Class) 225 */ 226 public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type) { 227 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 228 String[] result = lbf.getBeanNamesForType(type); 229 if (lbf instanceof HierarchicalBeanFactory) { 230 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 231 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 232 String[] parentResult = beanNamesForTypeIncludingAncestors( 233 (ListableBeanFactory) hbf.getParentBeanFactory(), type); 234 result = mergeNamesWithParent(result, parentResult, hbf); 235 } 236 } 237 return result; 238 } 239 240 /** 241 * Get all bean names for the given type, including those defined in ancestor 242 * factories. Will return unique names in case of overridden bean definitions. 243 * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" 244 * flag is set, which means that FactoryBeans will get initialized. If the 245 * object created by the FactoryBean doesn't match, the raw FactoryBean itself 246 * will be matched against the type. If "allowEagerInit" is not set, 247 * only raw FactoryBeans will be checked (which doesn't require initialization 248 * of each FactoryBean). 249 * @param lbf the bean factory 250 * @param includeNonSingletons whether to include prototype or scoped beans too 251 * or just singletons (also applies to FactoryBeans) 252 * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and 253 * <i>objects created by FactoryBeans</i> (or by factory methods with a 254 * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 255 * eagerly initialized to determine their type: So be aware that passing in "true" 256 * for this flag will initialize FactoryBeans and "factory-bean" references. 257 * @param type the type that beans must match 258 * @return the array of matching bean names, or an empty array if none 259 * @see ListableBeanFactory#getBeanNamesForType(Class, boolean, boolean) 260 */ 261 public static String[] beanNamesForTypeIncludingAncestors( 262 ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) { 263 264 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 265 String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit); 266 if (lbf instanceof HierarchicalBeanFactory) { 267 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 268 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 269 String[] parentResult = beanNamesForTypeIncludingAncestors( 270 (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit); 271 result = mergeNamesWithParent(result, parentResult, hbf); 272 } 273 } 274 return result; 275 } 276 277 /** 278 * Get all bean names whose {@code Class} has the supplied {@link Annotation} 279 * type, including those defined in ancestor factories, without creating any bean 280 * instances yet. Will return unique names in case of overridden bean definitions. 281 * @param lbf the bean factory 282 * @param annotationType the type of annotation to look for 283 * @return the array of matching bean names, or an empty array if none 284 * @since 5.0 285 * @see ListableBeanFactory#getBeanNamesForAnnotation(Class) 286 */ 287 public static String[] beanNamesForAnnotationIncludingAncestors( 288 ListableBeanFactory lbf, Class<? extends Annotation> annotationType) { 289 290 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 291 String[] result = lbf.getBeanNamesForAnnotation(annotationType); 292 if (lbf instanceof HierarchicalBeanFactory) { 293 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 294 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 295 String[] parentResult = beanNamesForAnnotationIncludingAncestors( 296 (ListableBeanFactory) hbf.getParentBeanFactory(), annotationType); 297 result = mergeNamesWithParent(result, parentResult, hbf); 298 } 299 } 300 return result; 301 } 302 303 304 // Retrieval of bean instances 305 306 /** 307 * Return all beans of the given type or subtypes, also picking up beans defined in 308 * ancestor bean factories if the current bean factory is a HierarchicalBeanFactory. 309 * The returned Map will only contain beans of this type. 310 * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans 311 * will get initialized. If the object created by the FactoryBean doesn't match, 312 * the raw FactoryBean itself will be matched against the type. 313 * <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level, 314 * i.e. such beans will be returned from the lowest factory that they are being found in, 315 * hiding corresponding beans in ancestor factories.</b> This feature allows for 316 * 'replacing' beans by explicitly choosing the same bean name in a child factory; 317 * the bean in the ancestor factory won't be visible then, not even for by-type lookups. 318 * @param lbf the bean factory 319 * @param type type of bean to match 320 * @return the Map of matching bean instances, or an empty Map if none 321 * @throws BeansException if a bean could not be created 322 * @see ListableBeanFactory#getBeansOfType(Class) 323 */ 324 public static <T> Map<String, T> beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type) 325 throws BeansException { 326 327 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 328 Map<String, T> result = new LinkedHashMap<>(4); 329 result.putAll(lbf.getBeansOfType(type)); 330 if (lbf instanceof HierarchicalBeanFactory) { 331 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 332 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 333 Map<String, T> parentResult = beansOfTypeIncludingAncestors( 334 (ListableBeanFactory) hbf.getParentBeanFactory(), type); 335 parentResult.forEach((beanName, beanInstance) -> { 336 if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) { 337 result.put(beanName, beanInstance); 338 } 339 }); 340 } 341 } 342 return result; 343 } 344 345 /** 346 * Return all beans of the given type or subtypes, also picking up beans defined in 347 * ancestor bean factories if the current bean factory is a HierarchicalBeanFactory. 348 * The returned Map will only contain beans of this type. 349 * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set, 350 * which means that FactoryBeans will get initialized. If the object created by the 351 * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the 352 * type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked 353 * (which doesn't require initialization of each FactoryBean). 354 * <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level, 355 * i.e. such beans will be returned from the lowest factory that they are being found in, 356 * hiding corresponding beans in ancestor factories.</b> This feature allows for 357 * 'replacing' beans by explicitly choosing the same bean name in a child factory; 358 * the bean in the ancestor factory won't be visible then, not even for by-type lookups. 359 * @param lbf the bean factory 360 * @param type type of bean to match 361 * @param includeNonSingletons whether to include prototype or scoped beans too 362 * or just singletons (also applies to FactoryBeans) 363 * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and 364 * <i>objects created by FactoryBeans</i> (or by factory methods with a 365 * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 366 * eagerly initialized to determine their type: So be aware that passing in "true" 367 * for this flag will initialize FactoryBeans and "factory-bean" references. 368 * @return the Map of matching bean instances, or an empty Map if none 369 * @throws BeansException if a bean could not be created 370 * @see ListableBeanFactory#getBeansOfType(Class, boolean, boolean) 371 */ 372 public static <T> Map<String, T> beansOfTypeIncludingAncestors( 373 ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) 374 throws BeansException { 375 376 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 377 Map<String, T> result = new LinkedHashMap<>(4); 378 result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit)); 379 if (lbf instanceof HierarchicalBeanFactory) { 380 HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; 381 if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { 382 Map<String, T> parentResult = beansOfTypeIncludingAncestors( 383 (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit); 384 parentResult.forEach((beanName, beanInstance) -> { 385 if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) { 386 result.put(beanName, beanInstance); 387 } 388 }); 389 } 390 } 391 return result; 392 } 393 394 /** 395 * Return a single bean of the given type or subtypes, also picking up beans 396 * defined in ancestor bean factories if the current bean factory is a 397 * HierarchicalBeanFactory. Useful convenience method when we expect a 398 * single bean and don't care about the bean name. 399 * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans 400 * will get initialized. If the object created by the FactoryBean doesn't match, 401 * the raw FactoryBean itself will be matched against the type. 402 * <p>This version of {@code beanOfTypeIncludingAncestors} automatically includes 403 * prototypes and FactoryBeans. 404 * <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level, 405 * i.e. such beans will be returned from the lowest factory that they are being found in, 406 * hiding corresponding beans in ancestor factories.</b> This feature allows for 407 * 'replacing' beans by explicitly choosing the same bean name in a child factory; 408 * the bean in the ancestor factory won't be visible then, not even for by-type lookups. 409 * @param lbf the bean factory 410 * @param type type of bean to match 411 * @return the matching bean instance 412 * @throws NoSuchBeanDefinitionException if no bean of the given type was found 413 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found 414 * @throws BeansException if the bean could not be created 415 * @see #beansOfTypeIncludingAncestors(ListableBeanFactory, Class) 416 */ 417 public static <T> T beanOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type) 418 throws BeansException { 419 420 Map<String, T> beansOfType = beansOfTypeIncludingAncestors(lbf, type); 421 return uniqueBean(type, beansOfType); 422 } 423 424 /** 425 * Return a single bean of the given type or subtypes, also picking up beans 426 * defined in ancestor bean factories if the current bean factory is a 427 * HierarchicalBeanFactory. Useful convenience method when we expect a 428 * single bean and don't care about the bean name. 429 * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set, 430 * which means that FactoryBeans will get initialized. If the object created by the 431 * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the 432 * type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked 433 * (which doesn't require initialization of each FactoryBean). 434 * <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level, 435 * i.e. such beans will be returned from the lowest factory that they are being found in, 436 * hiding corresponding beans in ancestor factories.</b> This feature allows for 437 * 'replacing' beans by explicitly choosing the same bean name in a child factory; 438 * the bean in the ancestor factory won't be visible then, not even for by-type lookups. 439 * @param lbf the bean factory 440 * @param type type of bean to match 441 * @param includeNonSingletons whether to include prototype or scoped beans too 442 * or just singletons (also applies to FactoryBeans) 443 * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and 444 * <i>objects created by FactoryBeans</i> (or by factory methods with a 445 * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 446 * eagerly initialized to determine their type: So be aware that passing in "true" 447 * for this flag will initialize FactoryBeans and "factory-bean" references. 448 * @return the matching bean instance 449 * @throws NoSuchBeanDefinitionException if no bean of the given type was found 450 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found 451 * @throws BeansException if the bean could not be created 452 * @see #beansOfTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) 453 */ 454 public static <T> T beanOfTypeIncludingAncestors( 455 ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) 456 throws BeansException { 457 458 Map<String, T> beansOfType = beansOfTypeIncludingAncestors(lbf, type, includeNonSingletons, allowEagerInit); 459 return uniqueBean(type, beansOfType); 460 } 461 462 /** 463 * Return a single bean of the given type or subtypes, not looking in ancestor 464 * factories. Useful convenience method when we expect a single bean and 465 * don't care about the bean name. 466 * <p>Does consider objects created by FactoryBeans, which means that FactoryBeans 467 * will get initialized. If the object created by the FactoryBean doesn't match, 468 * the raw FactoryBean itself will be matched against the type. 469 * <p>This version of {@code beanOfType} automatically includes 470 * prototypes and FactoryBeans. 471 * @param lbf the bean factory 472 * @param type type of bean to match 473 * @return the matching bean instance 474 * @throws NoSuchBeanDefinitionException if no bean of the given type was found 475 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found 476 * @throws BeansException if the bean could not be created 477 * @see ListableBeanFactory#getBeansOfType(Class) 478 */ 479 public static <T> T beanOfType(ListableBeanFactory lbf, Class<T> type) throws BeansException { 480 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 481 Map<String, T> beansOfType = lbf.getBeansOfType(type); 482 return uniqueBean(type, beansOfType); 483 } 484 485 /** 486 * Return a single bean of the given type or subtypes, not looking in ancestor 487 * factories. Useful convenience method when we expect a single bean and 488 * don't care about the bean name. 489 * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" 490 * flag is set, which means that FactoryBeans will get initialized. If the 491 * object created by the FactoryBean doesn't match, the raw FactoryBean itself 492 * will be matched against the type. If "allowEagerInit" is not set, 493 * only raw FactoryBeans will be checked (which doesn't require initialization 494 * of each FactoryBean). 495 * @param lbf the bean factory 496 * @param type type of bean to match 497 * @param includeNonSingletons whether to include prototype or scoped beans too 498 * or just singletons (also applies to FactoryBeans) 499 * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and 500 * <i>objects created by FactoryBeans</i> (or by factory methods with a 501 * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 502 * eagerly initialized to determine their type: So be aware that passing in "true" 503 * for this flag will initialize FactoryBeans and "factory-bean" references. 504 * @return the matching bean instance 505 * @throws NoSuchBeanDefinitionException if no bean of the given type was found 506 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found 507 * @throws BeansException if the bean could not be created 508 * @see ListableBeanFactory#getBeansOfType(Class, boolean, boolean) 509 */ 510 public static <T> T beanOfType( 511 ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) 512 throws BeansException { 513 514 Assert.notNull(lbf, "ListableBeanFactory must not be null"); 515 Map<String, T> beansOfType = lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit); 516 return uniqueBean(type, beansOfType); 517 } 518 519 520 /** 521 * Merge the given bean names result with the given parent result. 522 * @param result the local bean name result 523 * @param parentResult the parent bean name result (possibly empty) 524 * @param hbf the local bean factory 525 * @return the merged result (possibly the local result as-is) 526 * @since 4.3.15 527 */ 528 private static String[] mergeNamesWithParent(String[] result, String[] parentResult, HierarchicalBeanFactory hbf) { 529 if (parentResult.length == 0) { 530 return result; 531 } 532 List<String> merged = new ArrayList<>(result.length + parentResult.length); 533 merged.addAll(Arrays.asList(result)); 534 for (String beanName : parentResult) { 535 if (!merged.contains(beanName) && !hbf.containsLocalBean(beanName)) { 536 merged.add(beanName); 537 } 538 } 539 return StringUtils.toStringArray(merged); 540 } 541 542 /** 543 * Extract a unique bean for the given type from the given Map of matching beans. 544 * @param type type of bean to match 545 * @param matchingBeans all matching beans found 546 * @return the unique bean instance 547 * @throws NoSuchBeanDefinitionException if no bean of the given type was found 548 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found 549 */ 550 private static <T> T uniqueBean(Class<T> type, Map<String, T> matchingBeans) { 551 int count = matchingBeans.size(); 552 if (count == 1) { 553 return matchingBeans.values().iterator().next(); 554 } 555 else if (count > 1) { 556 throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet()); 557 } 558 else { 559 throw new NoSuchBeanDefinitionException(type); 560 } 561 } 562 563}