Spring原始碼之Bean元件掃描解析類ClassPathBeanDefinitionScanner
阿新 • • 發佈:2022-03-03
1.前言
在Spring的使用中,我沒會通過@Controller、@Service、@Repository、@Component元件標註在一個類上,告訴Spring此類為一個Bean元件類,交由Spring為我們建立類的例項和管理Bean元件相關的生命週期。
Spring管理Bean元件大致分為兩大階段。
第一階段(解析):是將我們通過元件註解標註的類解析成Bean元件的定義物件,也就是對應的BeanDefinition物件,該物件用來描述每個元件的一些基本資訊
第二階段(建立):獲取所有解析後的BeanDefinition物件,根據其相關屬性建立成最終的一個個例項物件,例項的建立過程也會出發元件生命週期相關的勾子函式
2.準備工作
Spring版本:2.2.13.RELEASE
說明:文中統一將被@Controller、@Service、@Repository、@Component標註的類稱為元件類
原始碼中涉及的類
- ClassPathBeanDefinitionScanner
- ClassPathScanningCandidateComponentProvider
3.原始碼流程分析
3.1流程入口方法ClassPathBeanDefinitionScanner.scan
public int scan(String... basePackages) { // 獲取此次元件掃描之前Spring容器中元件定義的數量int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); // 根據包路徑開始掃描包下的所有元件 doScan(basePackages); // 是否開啟註解驅動,主要針對@Autowird、@Configuration、@PostConstruct、@PreDestroy等註解的支援 if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } // 返回此次掃描新增的元件數量 return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart); }
3.2ClassPathBeanDefinitionScanner.doScan
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { // 掃描包不能為空 Assert.notEmpty(basePackages, "At least one base package must be specified"); // 掃描後的元件集合 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); // 迴圈所有包路徑,依次進行掃描 for (String basePackage : basePackages) { // 查詢候選的元件集合 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); // 迴圈所有候選的元件定義資訊 for (BeanDefinition candidate : candidates) { /* 解析元件的作用域 singleton、prototype、request、session、global */ ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 生成元件的名稱 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); // 如果為一個非註解標註的元件 if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } // 如果為一個註解標註的元件 if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 檢查是否為候選的元件,如果是則將該元件的定義資訊註冊到Spring容器中 if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
3.3ClassPathScanningCandidateComponentProvider.findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) { // 針對元件上的@Index註解的處理邏輯 if (this.componentsIndex != null && indexSupportsIncludeFilters()) { return addCandidateComponentsFromIndex(this.componentsIndex, basePackage); } else { return scanCandidateComponents(basePackage); } } private Set<BeanDefinition> scanCandidateComponents(String basePackage) { // 元件定義集合,也是該方法的返回值 Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { // 根據包路勁封裝成Ant風格的全路徑名稱 org.spring -> classpath*:org/spring/**/*.class String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; // 呼叫資源模式解析器解析該路徑下的所有類資源,這裡的資源模式解析器用的是PathMatchingResourcePatternResolver,支援Ant路徑模式 Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); // 迴圈每一個類資源處理 for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } try { // 獲取類資源上的元資料讀取者 MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); // 是否為候選的元件,通過TypeFilter進行包含和排除過濾 if (isCandidateComponent(metadataReader)) { // 封裝成元件定義類BeanDefinition ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); // 判斷元件類是否是一個頂層類(非內部類)、靜態內部類,非抽象類,包含@Lookup註解方法的抽象類 if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } // 加入集合 candidates.add(sbd); } else { if (debugEnabled) { logger.debug("Ignored because not a concrete top-level class: " + resource); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (FileNotFoundException ex) { if (traceEnabled) { logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage()); } } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; }
3.4AnnotationConfigUtils.processCommonDefinitionAnnotations
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { /* 處理@Lazy、@Primary、@DependsOn、@Role、@Description註解 */ 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")); } AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); } }