2019独角兽企业重金招聘Python工程师标准>>>
前言
BeanNameGenerator是beans体系非常重要的一个组件,主要功能是从一定的条件中计算出bean的name.如果出现问题,是可以规避的。同样可以重写解决。
/** Map of bean definition objects, keyed by bean name */
private final Map beanDefinitionMap = new ConcurrentHashMap(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type */
private final Map, String[]> allBeanNamesByType = new ConcurrentHashMap, String[]>(64);
/** Map of singleton-only bean names, keyed by dependency type */
private final Map, String[]> singletonBeanNamesByType = new ConcurrentHashMap, String[]>(64);
/** List of bean definition names, in registration order */
private volatile List beanDefinitionNames = new ArrayList(256);
/** List of names of manually registered singletons, in registration order */
private volatile Set manualSingletonNames = new LinkedHashSet(16);
/** Cached array of bean definition names in case of frozen configuration */
private volatile String[] frozenBeanDefinitionNames;
从上面的数据中可以看出,bean的管理基本是基于beanName的。所以如何获得beanName是一个重要的关键。所以深入了解BeanNameGenerator体系是十分重要的
源码解读
BeanNameGenerator
public interface BeanNameGenerator {
String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
BeanNameGenerator就一个方法声明,generateBeanName的声明并不复杂,传递BeanDefinition与BeanDefinitionRegistry 返回一个string类型的beanname。所以本节深入解读还是比较简单的。
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 生成规则
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 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 metaAnnotationTypes, Map 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);
}
}
扫描的注解有
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()
当注解的value字段不存在值的时候,会默认把首字母小写的类名做的beanName
使用详解
往ApplicationContext注册BeanNameGeneratord对象
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;
}
通过beanName从ApplicationContext获得对象
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
@Override
public T getBean(String name, Class requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
通过beanName从BeanFactory获得对象
@Override
public Object getBean(String name) throws BeansException {
return getBean(name, Object.class);
}
@Override
public T getBean(String name, Class 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 doGetSingleton(String name, Class 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;
}
}