spring如何生成beanName的
用了一年的spring,该系列的博文会有点偏总结吧
这篇文章主要讲的是spring 里的bean名称是如何产生的
通过Spring配置你的bean的几种方式
- 第一种:配置文件
<bean class="com.zw.aop.test.MyAdvice" id="myAdvice"></bean>
- 第二种:注解@Component,或者是带@Component的注解@Service等
@Service
//@Component
public class CacheLockProcessor {
@Autowired
private ShardedJedisPool shardedJedisPool;
}
- 第三种:基于java的注解
@Configurable
public class Factory {
@Bean
public SayHello SayHello() {
return new SayHelloImpl();
}
}
- 第四种/other 有基于jsr250/jsr330。具体不写了
本片文章主要是针对第一第二种场景:直接看spring源码是如何处理的:首先是看spring是如何读配置文件xml配置文件的bean的
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
- 源码中可以看到aliases别名,一个bean可以有多个别名,用逗号分隔就好了。
- 在xml文件里面配置bean的时候,如果自己配置了name和id属性,则就是自己所指定的名称。若只配置了id属性,则生成 的beanName就是id
- 若id和name都没有配置,则会进以下方法来进行生成
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
else if (definition.getFactoryBeanName() != null) {
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;
if (isInnerBean) {
// Inner bean: generate identity hashcode suffix.
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// Top-level bean: use plain class name.
// Increase counter until the id is unique.
int counter = -1;
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
}
return id;
}
- 判断是否有父类,如果有父类,则名称为:definition.getParentName() + “$child”;
- 判断是否有指定的工厂类,如果有,则为:definition.getFactoryBeanName() + “$created”;
- 判断是否是innerBean:如果是,则名称为:
className+GENERATED_BEAN_NAME_SEPARATO+ ObjectUtils.getIdentityHexString(definition);
* @param isInnerBean whether the given bean definition will be registered
* as inner bean or as top-level bean (allowing for special name generation
* for inner beans versus top-level beans)
String org.springframework.beans.factory.support.BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR = "#"
- 如果都不是,则是:
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
- 第一个配置文件里的如果我配置name和id属性则生成的是:com.zw.aop.test.MyAdvice#0
若以注解的方式来进行生成。可以看以下代码
*/
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition);
}
- 若在@Component里面配置了对应名称属性,则为配置的,若没有配置,则:
protected String buildDefaultBeanName(BeanDefinition definition) {
String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
return Introspector.decapitalize(shortClassName);
}
直接由spring来进行创建,也就是类的名称,第一个字母该为小写