spring源码分析(2)——Bean 定义的解析与Bean的注册

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses); 
   refresh();
}

        在sprint的源码分析(1)中,我们分析了this()这条语句调用的无参构造方法初始化了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner这两个类,接着我们分析register(annotatedClasses)这个函数。

public void register(Class<?>... annotatedClasses) {
   Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
   this.reader.register(annotatedClasses);
}

        入参Class<?>… annotatedClasses是我们进行初始化的时候传入的类;this.reader就是已经初始化完毕的AnnotatedBeanDefinitionReader。

public void register(Class<?>... annotatedClasses) {
   for (Class<?> annotatedClass : annotatedClasses) {
      registerBean(annotatedClass);
   }
}

        通过for循环轮流对传入的类进行解析,注册为bean。

public void registerBean(Class<?> annotatedClass) {
   doRegisterBean(annotatedClass, null, null, null);
}

        最终调用doRegisterBean方法。下面分别讲解每一句的含义。

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }

   abd.setInstanceSupplier(instanceSupplier);
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }
   for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
      customizer.customize(abd);
   }

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

        首先分析doRegisterBean方法的第4行代码:

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

        doRegisterBean方法第一句就是将类转化为AnnotatedGenericBeanDefinition。

public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
   setBeanClass(beanClass);
   this.metadata = new StandardAnnotationMetadata(beanClass, true);
}

        Spring中使用BeanDefinition描述了一个bean的实例,AnnotatedGenericBeanDefinition实现了接口AnnotatedBeanDefinition,而AnnotatedBeanDefinition继承了BeanDefinition。AnnotatedBeanDefinition比BeanDefinition多出getMetadata()方法,用于获得类上的注解信息。spring4.1.1之后还多出了getFactoryMethodMetadata()方法,也是用于获得类上的注解信息。

public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
   super(introspectedClass);
   this.annotations = introspectedClass.getAnnotations();
   this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}

        AnnotationMetadata的标准实现类StandardAnnotationMetadata,它使用标准的反射来获取制定类的内部注解信息。

        分析doRegisterBean方法的第5-7行代码:

if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }

        conditionEvaluator是在AnotatedBeanDefinitionReader类初始化的时候初始化的,ConditionEvaluator这个类主要用于完成条件注解@Conditional的解析和判断。@Conditional 是Spring 4框架的新特性。此注解使得只有在特定条件满足时才启用一些配置。ConditionEvaluator的shouldSkip就是用于判断@Conditional下的而配置是否被启用。

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
   if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
      return false;
   }
......
   }

        从代码的前两句很容易判断, 如果这个类没有被@Conditional注解所修饰,不会skip。

        分析doRegisterBean方法的第10行代码:

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

        scopeMetadataResolver是AnotatedBeanDefinitionReader的一个成员变量,是类AnnotationScopeMetadataResolver的一个实例。AnnotationScopeMetadataResolver实现了ScopeMetadataResolver接口的resolveScopeMetadata()方法。

@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
   ScopeMetadata metadata = new ScopeMetadata();
   if (definition instanceof AnnotatedBeanDefinition) {
      AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
      AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
            annDef.getMetadata(), this.scopeAnnotationType);
      if (attributes != null) {
         metadata.setScopeName(attributes.getString("value"));
         ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
         if (proxyMode == ScopedProxyMode.DEFAULT) {
            proxyMode = this.defaultProxyMode;
         }
         metadata.setScopedProxyMode(proxyMode);
      }
   }
   return metadata;
}

        第一句新建了一个ScopeMetadata,ScopeMetadata中默认的scope是singleton。重点关注AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType)。this.scopeAnnotationType是AnnotationScopeMetadataResolver成员变量,值为Scope.class。该方法就是从元数据中获得注解scope的值,并将其返回。如果没有配置@scope,那么它的默认值就是singleton,即单例模式。

        分析doRegisterBean方法的第12行代码:

String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        这句代码生成bean的名称,beanNameGenerator是AnnotatedBeanDefinitionReader的一个成员变量,是类AnnotationBeanNameGenerator的一个实例。AnnotationBeanNameGenerator实现了BeanNameGenerator接口的generateBeanName()方法。

@Override
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, registry);
}

        如果不是AnnotationBeanDefinition,buildDefaultBeanName()方法直接将类名(不含包名)作为bean name。如果是的话,执行determineBeanNameFromAnnotation(),从注解上获得bean name。

protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
   AnnotationMetadata amd = annotatedDef.getMetadata();
   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;
}

        首先通过getAnnotationTypes()方法获得所有的注解,遍历这些注解,AnnotationConfigUtils.attributesFor()方法读取注解对应的所有属性。isStereotypeWithNameValue()方法用于判断 这些注解是否是@component注解,是否继承了@component注解,是否是@ManageBean注解,是否是@Named注解,如果满足以上条件中的任何一个并且包含value属性,则返回true。接下来判断vale的值不多于1个且value属性非空(也就是不能同时出现@service和@component且都配置value值),不然会报错。都满足的话,将value属性对应的值作为bean name。

        分析doRegisterBean方法的第14行代码:

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

        这句代码使用AnnotationConfigUtils的processCommonDefinitionAnnotations方法处理注解Bean定义类中通用的注解。

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
   AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
   if (lazy != null) {
      abd.setLazyInit(lazy.getBoolean("value"));
   }
   else if (abd.getMetadata() != metadata) {
      lazy = attributesFor(abd.getMetadata(), Lazy.class);
      if (lazy != null) {
         abd.setLazyInit(lazy.getBoolean("value"));
      }
   }

   if (metadata.isAnnotated(Primary.class.getName())) {
      abd.setPrimary(true);
   }
   AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
   if (dependsOn != null) {
      abd.setDependsOn(dependsOn.getStringArray("value"));
   }

   if (abd instanceof AbstractBeanDefinition) {
      AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
      AnnotationAttributes role = attributesFor(metadata, Role.class);
      if (role != null) {
         absBd.setRole(role.getNumber("value").intValue());
      }
      AnnotationAttributes description = attributesFor(metadata, Description.class);
      if (description != null) {
         absBd.setDescription(description.getString("value"));
      }
   }
}

        从代码中可以看出,processCommonDefinitionAnnotations方法处理了5个注解,分别是:

        @lazy注解:用于指定该Bean是否懒加载,如果该注解的value为true的话,则这个bean在spring容器初始化之后,第一次使用时才初始化。AbstractBeanDefinition中定义该值的默认值是false。

        @primary注解:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常。

        @DependsOn注解:定义Bean初始化顺序。

        如果这个bean是AbstractBeanDefinition的子类的话,还会处理以下两个注解:

        @Role注解:用于用户自定义的bean,value值是int类型,表明该bean在应用中的角色,默认值是0,极少用到。

        @Description注解:用于描述bean,提高代码可读性,极少用到。

        分析doRegisterBean方法的第15-27行代码:

if (qualifiers != null) {
   for (Class<? extends Annotation> qualifier : qualifiers) {
      if (Primary.class == qualifier) {
         abd.setPrimary(true);
      }
      else if (Lazy.class == qualifier) {
         abd.setLazyInit(true);
      }
      else {
         abd.addQualifier(new AutowireCandidateQualifier(qualifier));
      }
   }
}

        这一段代码是针对 @Qualifier注解的,一般情况下,@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个该类型的bean时,就会抛出BeanCreationException异常。@Qualifier可以配置自动依赖注入装配的限定条件,@Qualifier 可以直接指定注入 Bean 的名称,简单来说, @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。本段代码在当前的例子中是不执行的。

        分析doRegisterBean方法的第28-30行代码:

for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
   customizer.customize(abd);
}

        这段代码是spring5.0以后新加入的,Spring 5允许使用lambda 表达式来自定义注册一个 bean,用到的时候再分析。

        分析doRegisterBean方法的第32行:

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

        BeanDefinitionHolder就是一个BeanDefinition的持有者,它有三个成员变量。

private final BeanDefinition beanDefinition;  
  
private final String beanName;  
  
private final String[] aliases;

        所以这行代码就是把BeanDefination简单的封装为BeanDefinitionHolder。

        分析doRegisterBean方法的第33行:

definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

        进入applyScopedProxyMode()方法。

static BeanDefinitionHolder applyScopedProxyMode(
      ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

   ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
   if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
      return definition;
   }
   boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
   return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

        这段代码首先需要获得ScopedProxyMode值,这个值实在@scope注解中使用proxyMode属性设置的,默认为NO,就是没有代理。它还可被设置为ScopedProxyMode. INTERFACES或者是ScopedProxyMode. TARGET_CLASS。这个值具体有什么用呢,我们只带。@scope注解的value可以设置为以下几种:

        单例(singleton):在整个应用中,只创建bean的一个实例。

        原型(prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的实例。

        会话(session):在Web应用中,为每个会话创建一个bean实例。

        请求(request):在Web应用中,为每个请求创建一个bean实例。

        当一个singleton作用域的bean中需要注入一个session作用域的bean的时候,会报错,应为此时应用没有人访问,session作用域bean没有创建,所以出现了问题。spring提供给我们的解决方案就是通过设置proxyMode属性的值来解决,当他设置为ScopedProxyMode. INTERFACES或者是ScopedProxyMode. TARGET_CLASS时,spring会为session作用域bean创建代理对象,而真正调用的bean则在运行时懒加载,两者的区别是一个使用JDK提供的动态代理实现,一个使用CGLIB实现。

这段代码就是通过判断proxyMode的值为注册的Bean创建相应模式的代理对象。默认不创建。

        分析doRegisterBean方法的最后一行代码。

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

        this.registry在spring源码分析(1)中分析过,其实就是AnnotationConfigApplicationContext实例对象,spring的上下文。

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

        第7行的registerBeanDefinition方法是BeanDefinitionRegistry接口方法,他有多个实现类,由于AnnotationConfigApplicationContext继承了GenericApplicationContext,所以这里调用的是GenericApplicationContext的registerBeanDefinition方法。

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

        this.beanFactory是在初始化GenericApplicationContext类时初始化的,是一个DefaultListableBeanFactory。DefaultListableBeanFactory也实现了BeanDefinitionRegistry接口的registerBeanDefinition方法,所以最终调用的是DefaultListableBeanFactory的registerBeanDefinition方法。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition oldBeanDefinition;

   oldBeanDefinition = this.beanDefinitionMap.get(beanName);
   if (oldBeanDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
               "': There is already [" + oldBeanDefinition + "] bound.");
      }
      else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (this.logger.isWarnEnabled()) {
            this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  oldBeanDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(oldBeanDefinition)) {
         if (this.logger.isInfoEnabled()) {
            this.logger.info("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + oldBeanDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (this.logger.isDebugEnabled()) {
            this.logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + oldBeanDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (oldBeanDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

        这一大段代码看起来挺复杂的,但是做的事情很简单。

        7-15行是对BeanDefiniton  的校验,具体来说,是对AbstractBeanDefinition属性中的methodOverrides 效验; 效验methodOverrides 是否与工厂方法并存或者methodOverrides对应的方法根本不存在。

        17-49行是对容器中已经存在了一个同名bean的处理方法。如果对应beanName已经注册 并且beanName不能被覆盖,则抛出异常,否则后注册的覆盖先注册的。

        50-73是正常情况的处理流程,这里会将beanName和beanDefinition放到beanDefinitionMap中,此时的beanDefinitionMap中已经存在了6个beanDefinition,是在Spring源码分析(1)中放进去的6个处理器。

        registerBeanDefinition方法之后,还有registry.registerAlias(beanName, alias)方法,这是给bean注册别名用的。其实就是spring上线文对bean名称和别名之间维护了映射关系,就不具体分析了。

        本文讲解了一个Bean在spring上下文当中的解析与注册流程,通过这个步骤,Bean定义信息被Spring所管理,是容器可以进行依赖注入的基础。

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/shenmaxiang/article/details/79456099
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞