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