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