Spring IoC源碼之配置類的處理

Spring IoC 源碼解析之註冊配置類

入口代碼展現

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    /**
     * 調用默認的構造方法,因爲該類有父類,
     * 故而先調用父類的構造方法,在調用本身的構造方法
     * 在本身的構造方法中初始一個讀取器和一個掃描器,
     * 第①部分!!!
     */
    this();
    /**
     * 向spring 的容器中註冊bean
     * 第②部分!!!
     */
    register(componentClasses);
    /**
     * 初始化spring的環境
     * 第③部分!!!
     */
    refresh();
}
複製代碼

  這裏將要解析上述代碼中的register(componentClasses)這一部分的代碼。。。web

註冊配置類

/**  * 註冊單個bean給容器  * 好比有新加的類能夠用這個方法  * 可是註冊以後須要手動調用refresh()方法觸發容器解釋註釋  *  * 能夠註冊一個配置類  * 也能夠註冊一個bean  */ @Override public void register(Class<?>... componentClasses) {  Assert.notEmpty(componentClasses, "At least one component class must be specified");  this.reader.register(componentClasses); } 複製代碼

   上述代碼中經過 this.reader.register(componentClasses) 完成了配置類的註冊,這裏的 reader 對象就是上一篇文章中提到的 bean的讀取器 AnnotatedBeanDefinitionReaderspring

public void register(Class<?>... componentClasses) {
 for (Class<?> componentClass : componentClasses) {  registerBean(componentClass);  } } 複製代碼

初識 Spring 的 doXXX方法

  在Spring當中真正的作事情的方法都是經過 do 來開頭完成的。在後續的方法中,會看到不少這類的方法。這裏首先看看 doRegisterBean() 方法實現:api

<T> void doRegisterBean(Class<T> beanClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,  @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {  /*  * 根據指定的bean建立一個AnnotatedGenericBeanDefinition  * 這個AnnotatedGenericBeanDefinition能夠理解爲一個數據結構,  * 該結構中包含了類的一些描述信息。好比scope,lazy等等  */  AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);  if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {  return;  }   abd.setInstanceSupplier(instanceSupplier);  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);  /*  * 設置類的做用域  */  abd.setScope(scopeMetadata.getScopeName());  /*  * 經過beanNameGenerator生成一個beanName  */  String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));   /*  * 處理類當中的通用註解  * 處理完的數據 存放在 abd 中  */  AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);   /*  * 當 qualifiers 不爲null 時,處理qualifiers  */  if (qualifiers != null) {  for (Class<? extends Annotation> qualifier : qualifiers) {  /** 若是設置了 @Primary 則將其值設置爲true */  if (Primary.class == qualifier) {  abd.setPrimary(true);  }  else if (Lazy.class == qualifier) {  /** 若是設置了 @Lazy 則將其值設置爲true */  abd.setLazyInit(true);  }  else {  /**  * 使用了其餘註解,則爲該bean添加一個根據名字自動裝配的限定符  */  abd.addQualifier(new AutowireCandidateQualifier(qualifier));  }  }  }  for (BeanDefinitionCustomizer customizer : definitionCustomizers) {  customizer.customize(abd);  }   /*  * BeanDefinitionHolder 也是一種數據結構  * 將beanName 與 abd 關聯  */  BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);   /*  * ScopedProxyMode 結合web去理解  */  definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);  /*  * 將definitionHolder 註冊給 registry  * registry 是 AnnotationConfigApplicationContext  * AnnotationConfigApplicationContext 在初始化的時候經過調用父類的構造方法實例化一個 DefaultListableBeanFactory  *  * registerBeanDefinition 就是將 definitionHolder 註冊到 DefaultListableBeanFactory中  */  BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } 複製代碼

註冊配置類時序圖

時序圖
時序圖

  上述改方法的調用過程,最終就是將定義的MyConfig類對應的BeanDefinition放入到beanDefinitionMap中, 至此beanDefinitionMap中對象又增長了一個,變成6個了。 容器中的對象數據結構

1.處理通用註解

/** * 處理類的通用註解 * @param abd spring中bean的描述類 * @param metadata 經過spring中bean的描述類獲取 bean的元數據信息 * * 處理完通用註解後的信息 放回到 spring中bean的描述類(AnnotatedBeanDefinition) */ static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {  /**  * 處理 @Lazy 註解  */  AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);  if (lazy != null) {  /** 設置bean的懶加載信息*/  abd.setLazyInit(lazy.getBoolean("value"));  }  else if (abd.getMetadata() != metadata) {  lazy = attributesFor(abd.getMetadata(), Lazy.class);  if (lazy != null) {  abd.setLazyInit(lazy.getBoolean("value"));  }  }   /**  * 處理 @Primary 註解  */  if (metadata.isAnnotated(Primary.class.getName())) {  abd.setPrimary(true);  }   /**  * 處理 @DependsOn 註解  */  AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);  if (dependsOn != null) {  abd.setDependsOn(dependsOn.getStringArray("value"));  }   /**  * 處理 @Role 註解  */  AnnotationAttributes role = attributesFor(metadata, Role.class);  if (role != null) {  abd.setRole(role.getNumber("value").intValue());  }   /**  * 處理 @Description註解  */  AnnotationAttributes description = attributesFor(metadata, Description.class);  if (description != null) {  abd.setDescription(description.getString("value"));  } } 複製代碼

2.將 definitionHolder 註冊給 registry

  registryAnnotationConfigApplicationContext,由於 AnnotationConfigApplicationContextBeanDefinitionRegistry 的實現類。app

public static void registerBeanDefinition(  BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  throws BeanDefinitionStoreException {   // Register bean definition under primary name.  /** 獲取beanName */  String beanName = definitionHolder.getBeanName();  /**  * 註冊 beanDefinition, beanName 與 BeanDefinition 放入Map 中  */  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);  }  } } 複製代碼

容器造成圖

Ioc容器構成
Ioc容器構成

  經過上述過程發現,定義的配置類被加載到了容器之中,這樣一來容器中的對象又多了一個。這裏對容器中對象的名稱, 即 BeanDefinitionMap 中的 key 作一個簡要的說明。編輯器

  • Spring 內部的 BeanDefinitionname 是在Spring 內部寫死的,對應的 BeanDefinition 的實現是 RootBeanDefinition
  • 注入的配置類,若是有指定的名稱,則使用指定的名稱,若是沒有指定,則使用類名。對應的代碼以下:
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
 if (definition instanceof AnnotatedBeanDefinition) {  // 經過注接肯定 bean 的名稱  String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);  if (StringUtils.hasText(beanName)) {  // Explicit bean name found.  return beanName;  }  }  // 生成一個默認的惟一的beanName  return buildDefaultBeanName(definition, registry); } 複製代碼

  determineBeanNameFromAnnotation()是經過註解生成一個beanName。好比,在註解中經過屬性value指定的名稱的類,最終在容器中的beanName就是這個。ide

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)) {  // 獲取value屬性  Object value = attributes.get("value");  // 若是是 字符串 則beanName 就是指定的,不然爲 null  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; } 複製代碼

  下面是生成一個默認的 beanName:ui

protected String buildDefaultBeanName(BeanDefinition definition) {
 String beanClassName = definition.getBeanClassName();  Assert.state(beanClassName != null, "No bean class name set");  String shortClassName = ClassUtils.getShortName(beanClassName);  return Introspector.decapitalize(shortClassName); } 複製代碼

  在上述圖中有兩個對象, beanNameGeneratorscopeMetadataResolver 分別爲 beanName 生成器和 bean 定義範圍解析器。 在Spring中這兩個對象對應兩個 BeanNameGeneratorScopeMetadataResolver 策略接口。真正的處理邏輯在實現類中完成,這裏對應策略的獲取, 都是經過 new 實現類的方式來完成的。在 AnnotatedBeanDefinitionReader 中對應的代碼以下:this

private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
 private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); 複製代碼

本文使用 mdnice 排版lua

相關文章
相關標籤/搜索