Spring源码之BeanNameGenerator

BeanName

环境:Spring-framework 5.1.x

构建自己的model javaboy-test

引入依赖spring-context

Spring源码之BeanNameGenerator_第1张图片

创建一个类A。并交给Spring容器进行管理。

Spring源码之BeanNameGenerator_第2张图片

告诉Spring扫描的目录在哪。使用@ComponentScan注解。

Spring源码之BeanNameGenerator_第3张图片

编写测试类,因为使用的是注解进行的配置,所以使用AnnotationConfigApplicationContext进行配置解析。

Spring源码之BeanNameGenerator_第4张图片

AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);

这一行代码实现了初始化Spring容器并完成Bean的创建。

对于Bean的命名,Spring提供了BeanNameGenerator接口完成BeanName的命名。

Spring对于Bean的命名,默认使用的是AnnotationBeanNameGenerator。

AnnotationBeanNameGenerator通过通过使用注解的类型和属性完成Bean的命名。它支持以下几种注解:

@Component、@Repository、@Service、@Controller、@Named

Spring源码之BeanNameGenerator_第5张图片

AnnotationBeanNameGenerator通过上面注释中的value值可以直接设置Bean的名字,如果为空,则使用简单类名生成beanName。

Spring源码之BeanNameGenerator_第6张图片

其中重点关注:

String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);

determineBeanNameFromAnnotation方法将返回生成的BeanName。

Spring源码之BeanNameGenerator_第7张图片

protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
    //获取bd注释的元数据
   AnnotationMetadata amd = annotatedDef.getMetadata();
    //获取bd注释的类型
   Set<String> types = amd.getAnnotationTypes();
   String beanName = null;
   for (String type : types) {
      AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
      if (attributes != null && isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
         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;
}

获取bd的注释类型

Spring源码之BeanNameGenerator_第8张图片

这里正是在上面配置类中使用的注解ComponentScans和Configuration,其中我们还使用了Configuration,但是其是作为ComponentScans的value属性而存在。

开始for循环去遍历配置类中使用的注解。从图中可以看到,第一个拿到的是@ComponentScans。

并且通过AnnotationConfigUtils.attributesFor(amd, type);拿到ComponentScans中的属性及其属性值。

Spring源码之BeanNameGenerator_第9张图片

Spring源码之BeanNameGenerator_第10张图片

从图中可以看到,ComponentScans的属性为value,而value又包含了一个长度为4的AnnotationAttributes的数组。而每一个元素包含了扫码的路径、是否是懒加载、beanName生成器等等信息。

Spring源码之BeanNameGenerator_第11张图片

isStereotypeWithNameValue方法是检查给定的注释是否是一个允许通过注释{@code value()}建议组件名称的构造型。

简单说就是检查当前注释是否可以通过value值类指定bean的名称。

因为上面的扫描的第一个注解为ComponentScans,它的value值是不被允许指定为bean的名称的。所以返回false。

第二次for。此时type为configuration。它的value值是可以指定bean的名称的。

Spring源码之BeanNameGenerator_第12张图片

但是在MyConfig中,我没有使用value指定值,所以取出来为空字符串。

Spring源码之BeanNameGenerator_第13张图片

因为是空字符串,所以beanName没有被复制strVal.

Spring源码之BeanNameGenerator_第14张图片

直接返回。此时beanName为null。

Spring源码之BeanNameGenerator_第15张图片

StringUtils.hasText返回false。

Spring源码之BeanNameGenerator_第16张图片

Spring源码之BeanNameGenerator_第17张图片

通过definition获取beanClassName.。此时的definition为MyConfig的bd。

获取到的beanClassName为MyConfig的全限定名。

Spring源码之BeanNameGenerator_第18张图片

通过全限定名再获取简单类名。

Spring源码之BeanNameGenerator_第19张图片

最后通过Introspector.decapitalize方法生成beanName。

Spring源码之BeanNameGenerator_第20张图片

从上图代码逻辑可以看出,命名规则为首字符小写,或者前面两个字符都大写。

最终返回生成的beanName。

Spring源码之BeanNameGenerator_第21张图片

验证:将beanName改为前两个字符都大写。beanName直接返回。

Spring源码之BeanNameGenerator_第22张图片

你可能感兴趣的:(Spring源码系列,spring,java,数据库)