001/* 002 * Copyright 2002-2016 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.support; 018 019import org.springframework.beans.factory.BeanDefinitionStoreException; 020import org.springframework.beans.factory.BeanFactoryUtils; 021import org.springframework.beans.factory.config.BeanDefinition; 022import org.springframework.beans.factory.config.BeanDefinitionHolder; 023import org.springframework.util.ClassUtils; 024import org.springframework.util.ObjectUtils; 025import org.springframework.util.StringUtils; 026 027/** 028 * Utility methods that are useful for bean definition reader implementations. 029 * Mainly intended for internal use. 030 * 031 * @author Juergen Hoeller 032 * @author Rob Harrop 033 * @since 1.1 034 * @see PropertiesBeanDefinitionReader 035 * @see org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader 036 */ 037public class BeanDefinitionReaderUtils { 038 039 /** 040 * Separator for generated bean names. If a class name or parent name is not 041 * unique, "#1", "#2" etc will be appended, until the name becomes unique. 042 */ 043 public static final String GENERATED_BEAN_NAME_SEPARATOR = BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR; 044 045 046 /** 047 * Create a new GenericBeanDefinition for the given parent name and class name, 048 * eagerly loading the bean class if a ClassLoader has been specified. 049 * @param parentName the name of the parent bean, if any 050 * @param className the name of the bean class, if any 051 * @param classLoader the ClassLoader to use for loading bean classes 052 * (can be {@code null} to just register bean classes by name) 053 * @return the bean definition 054 * @throws ClassNotFoundException if the bean class could not be loaded 055 */ 056 public static AbstractBeanDefinition createBeanDefinition( 057 String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { 058 059 GenericBeanDefinition bd = new GenericBeanDefinition(); 060 bd.setParentName(parentName); 061 if (className != null) { 062 if (classLoader != null) { 063 bd.setBeanClass(ClassUtils.forName(className, classLoader)); 064 } 065 else { 066 bd.setBeanClassName(className); 067 } 068 } 069 return bd; 070 } 071 072 /** 073 * Generate a bean name for the given top-level bean definition, 074 * unique within the given bean factory. 075 * @param beanDefinition the bean definition to generate a bean name for 076 * @param registry the bean factory that the definition is going to be 077 * registered with (to check for existing bean names) 078 * @return the generated bean name 079 * @throws BeanDefinitionStoreException if no unique name can be generated 080 * for the given bean definition 081 * @see #generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean) 082 */ 083 public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry) 084 throws BeanDefinitionStoreException { 085 086 return generateBeanName(beanDefinition, registry, false); 087 } 088 089 /** 090 * Generate a bean name for the given bean definition, unique within the 091 * given bean factory. 092 * @param definition the bean definition to generate a bean name for 093 * @param registry the bean factory that the definition is going to be 094 * registered with (to check for existing bean names) 095 * @param isInnerBean whether the given bean definition will be registered 096 * as inner bean or as top-level bean (allowing for special name generation 097 * for inner beans versus top-level beans) 098 * @return the generated bean name 099 * @throws BeanDefinitionStoreException if no unique name can be generated 100 * for the given bean definition 101 */ 102 public static String generateBeanName( 103 BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) 104 throws BeanDefinitionStoreException { 105 106 String generatedBeanName = definition.getBeanClassName(); 107 if (generatedBeanName == null) { 108 if (definition.getParentName() != null) { 109 generatedBeanName = definition.getParentName() + "$child"; 110 } 111 else if (definition.getFactoryBeanName() != null) { 112 generatedBeanName = definition.getFactoryBeanName() + "$created"; 113 } 114 } 115 if (!StringUtils.hasText(generatedBeanName)) { 116 throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " + 117 "'class' nor 'parent' nor 'factory-bean' - can't generate bean name"); 118 } 119 120 String id = generatedBeanName; 121 if (isInnerBean) { 122 // Inner bean: generate identity hashcode suffix. 123 id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); 124 } 125 else { 126 // Top-level bean: use plain class name. 127 // Increase counter until the id is unique. 128 int counter = -1; 129 while (counter == -1 || registry.containsBeanDefinition(id)) { 130 counter++; 131 id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter; 132 } 133 } 134 return id; 135 } 136 137 /** 138 * Register the given bean definition with the given bean factory. 139 * @param definitionHolder the bean definition including name and aliases 140 * @param registry the bean factory to register with 141 * @throws BeanDefinitionStoreException if registration failed 142 */ 143 public static void registerBeanDefinition( 144 BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 145 throws BeanDefinitionStoreException { 146 147 // Register bean definition under primary name. 148 String beanName = definitionHolder.getBeanName(); 149 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); 150 151 // Register aliases for bean name, if any. 152 String[] aliases = definitionHolder.getAliases(); 153 if (aliases != null) { 154 for (String alias : aliases) { 155 registry.registerAlias(beanName, alias); 156 } 157 } 158 } 159 160 /** 161 * Register the given bean definition with a generated name, 162 * unique within the given bean factory. 163 * @param definition the bean definition to generate a bean name for 164 * @param registry the bean factory to register with 165 * @return the generated bean name 166 * @throws BeanDefinitionStoreException if no unique name can be generated 167 * for the given bean definition or the definition cannot be registered 168 */ 169 public static String registerWithGeneratedName( 170 AbstractBeanDefinition definition, BeanDefinitionRegistry registry) 171 throws BeanDefinitionStoreException { 172 173 String generatedName = generateBeanName(definition, registry, false); 174 registry.registerBeanDefinition(generatedName, definition); 175 return generatedName; 176 } 177 178}