In-depth explanation of BeanNameGenerator of spring-beans in Chapter 2, Section 1

foreword

BeanNameGenerator is a very important component of the beans system. Its main function is to calculate the name of the bean from certain conditions. If there is a problem, it can be avoided. The same can be rewritten to solve.

/** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

	/** Map of singleton and non-singleton bean names, keyed by dependency type */
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

	/** Map of singleton-only bean names, keyed by dependency type */
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

	/** List of bean definition names, in registration order */
	private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);

	/** List of names of manually registered singletons, in registration order */
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);

	/** Cached array of bean definition names in case of frozen configuration */
	private volatile String[] frozenBeanDefinitionNames;

As can be seen from the above data, bean management is basically based on beanName. So how to get beanName is an important key. So it is very important to have a deep understanding of the BeanNameGenerator system

Source code interpretation

BeanNameGenerator

public interface BeanNameGenerator {
	String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}

BeanNameGenerator declares a method. The declaration of generateBeanName is not complicated. Passing BeanDefinition and BeanDefinitionRegistry returns a beanname of string type. Therefore, the in-depth interpretation of this section is relatively simple.

DefaultBeanNameGenerator

public class DefaultBeanNameGenerator implements BeanNameGenerator {

	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
	}

}
public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
	return generateBeanName(beanDefinition, registry, false);
}

public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException {
	// ((Class<?>) beanClassObject).getName() 返回的是 class的完全限定名
	// 也可能是类名
	String generatedBeanName = definition.getBeanClassName();
	if (generatedBeanName == null) {
		if (definition.getParentName() != null) {
			//当generatedBeanName为null,parentName不为空。命名方式为parentName+"$child"
			generatedBeanName = definition.getParentName() + "$child";
		}else if (definition.getFactoryBeanName() != null) {
			//当generatedBeanName为null,FactoryBeanName不为空。命名方式为FactoryBeanName+"$child"
			generatedBeanName = definition.getFactoryBeanName() + "$created";
		}
	}
	if (!StringUtils.hasText(generatedBeanName)) {
		throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
	}

	String id = generatedBeanName;
	// generatedBeanName + “#” + value
	// isInnerBean 为true.使用系统identityHashCode作为value,false使用自增的方法作为value
	if (isInnerBean) {
		// Inner bean: generate identity hashcode suffix.
		id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
	}else {
		int counter = -1;
		// 到容器里面看看是否存在同样名字的BeanDefinition
		while (counter == -1 || registry.containsBeanDefinition(id)) {
			counter++;
			id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
		}
	}
	return id;
}
beanName generation rules

AnnotationBeanNameGenerator

public class AnnotationBeanNameGenerator implements BeanNameGenerator {

	private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";

	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		// 判断是AnnotatedBeanDefinition的实现,就从annotation获得。
		if (definition instanceof AnnotatedBeanDefinition) {
			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
			// 是文本就返回这个beanName,但是也有可能annotation的value是null,就后从buildDefaultBeanName获得
			if (StringUtils.hasText(beanName)) {
				return beanName;
			}
		}
		return buildDefaultBeanName(definition, registry);
	}

	protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
		// 获得类或者方法上所有的Annotation
		AnnotationMetadata amd = annotatedDef.getMetadata();
		// 得到所有annotation的类名
		Set<String> types = amd.getAnnotationTypes();
		String beanName = null;
		for (String type : types) {
			// 把annotation里面的字段与value,解读出来成map,字段名是key,value为value
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
			// 判断annotation是否有效,是否存在作为beanName的字段有value
			if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
				// 从注解中获得value字段的值,
				Object value = attributes.get("value");
				if (value instanceof String) {
					String strVal = (String) value;
					if (StringUtils.hasLength(strVal)) {
						if (beanName != null && !strVal.equals(beanName)) {
							throw new IllegalStateException("Stereotype annotations suggest inconsistent " +"component names: '" + beanName + "' versus '" + strVal + "'");
						}
						beanName = strVal;
					}
				}
			}
		}
		return beanName;
	}

	
	protected boolean isStereotypeWithNameValue(String annotationType,Set<String> metaAnnotationTypes, Map<String, Object> attributes) {
		// 判断annotation的类型是否是这三种.
		// org.springframework.stereotype.Component
		// javax.annotation.ManagedBean
		// javax.inject.Named
		
		boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
				(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
				annotationType.equals("javax.annotation.ManagedBean") ||
				annotationType.equals("javax.inject.Named");
		// 并且value存在值。才会返回true
		return (isStereotype && attributes != null && attributes.containsKey("value"));
	}

	
	protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		return buildDefaultBeanName(definition);
	}

	
	protected String buildDefaultBeanName(BeanDefinition definition) {
		// 获得类名
		String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
		// 把类名第一个字母大写转小写
		return Introspector.decapitalize(shortClassName);
	}

}

Scanned annotations are

org.springframework.stereotype.Component#value() org.springframework.stereotype.Repository#value() org.springframework.stereotype.Service#value() org.springframework.stereotype.Controller#value() javax.inject.Named#value() javax.annotation.ManagedBean#value()

When there is no value in the value field of the annotation, the class name with the first letter lowercase will be the beanName by default.

Use details

Register the BeanNameGeneratord object with the ApplicationContext

AnnotationConfigApplicationContext
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		this.reader.setBeanNameGenerator(beanNameGenerator);
		this.scanner.setBeanNameGenerator(beanNameGenerator);
		getBeanFactory().registerSingleton(
				AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
	}
AnnotationConfigWebApplicationContext
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		this.beanNameGenerator = beanNameGenerator;
	}

Get object from ApplicationContext by beanName

@Override
public Object getBean(String name) throws BeansException {
	assertBeanFactoryActive();
	return getBeanFactory().getBean(name);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	assertBeanFactoryActive();
	return getBeanFactory().getBean(name, requiredType);
}

Get object from BeanFactory by beanName

@Override
public Object getBean(String name) throws BeansException {
	return getBean(name, Object.class);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	try {
		if (isSingleton(name)) {
			return doGetSingleton(name, requiredType);
		}
		else {
			return lookup(name, requiredType);
		}
	}
	catch (NameNotFoundException ex) {
		throw new NoSuchBeanDefinitionException(name, "not found in JNDI environment");
	}
	catch (TypeMismatchNamingException ex) {
		throw new BeanNotOfRequiredTypeException(name, ex.getRequiredType(), ex.getActualType());
	}
	catch (NamingException ex) {
		throw new BeanDefinitionStoreException("JNDI environment", name, "JNDI lookup failed", ex);
	}
}
private <T> T doGetSingleton(String name, Class<T> requiredType) throws NamingException {
	synchronized (this.singletonObjects) {
		if (this.singletonObjects.containsKey(name)) {
			Object jndiObject = this.singletonObjects.get(name);
			if (requiredType != null && !requiredType.isInstance(jndiObject)) {
				throw new TypeMismatchNamingException(
						convertJndiName(name), requiredType, (jndiObject != null ? jndiObject.getClass() : null));
			}
			return (T) jndiObject;
		}
		T jndiObject = lookup(name, requiredType);
		this.singletonObjects.put(name, jndiObject);
		return jndiObject;
	}
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324983954&siteId=291194637