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

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
    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所管理,是容器可以进行依赖注入的基础。


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码分析(2)——Bean 定义的解析与Bean的注册

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏