本系列所有基於 Spring 5.2.2.BUILD-SNAPSHOT
版本。由於 Spring 整個體系太過於龐大,因此只會進行關鍵部分的源碼解析。html
本篇文章主要分析 context:componment-scan
標籤 Spring 是如何解析的。java
其實 context
開頭的標籤也是 Spring 自定義的標籤,前面介紹過自定義標籤的解析,沒看過的小夥伴能夠看下Spring IoC 自定義標籤解析;其中比較重要的就是 spring.handlers
和 spring.schemas
文件的定義,前者定義了標籤與命名空間處理器的對應關係,後者定義了命名空間與 XML Schema文件的對應關係。咱們能夠查找 Spring 中 context 模塊的源碼中查看這2個文件,並查看其命名空間的定義:git
上面2張圖分別對應了 spring.handlers
和 spring.schemas
文件的定義,只顯示了與 context
命名空間相關的定義。github
下面開始具體的代碼分析,直接從 parseCustomElement()
方法開始,不知道前面的流程的能夠查看Spring IoC BeanDefinition 的加載和註冊。spring
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // 獲取自定義標籤的命名空間 String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 獲取自定義標籤的處理器,這裏解析的是context:component-scan,因此獲取的是上圖中的ContextNamespaceHandler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 進行標籤的解析,見下文詳解 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
上面方法中獲取的 NamespaceHandler
就是 ContextNamespaceHandler
,咱們看下該類中註冊的元素及其對應的解析器:app
public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }
由上面代碼能夠看出 component-scan
元素由 ComponentScanBeanDefinitionParser
類去解析。ide
public BeanDefinition parse(Element element, ParserContext parserContext) { // 獲取屬性basePacket的值 String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); // 解析佔位符,例如${basePackage} basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); // 解析base-package(容許經過 ",; \t\n" 中的任一符號填寫多個),例如: com.leisurexi.one;com.leisurexi.two String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // 構建和配置ClassPathBeanDefinitionScanner,見下文詳解 ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); // 使用scanner在指定的包路徑進行掃描,返回註冊後的BeanDefinition,見下文詳解 Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); // 註冊組件(包括一些內部註解的後置處理器),見下文詳解 registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) { // 是否使用默認的過濾器,默認爲true boolean useDefaultFilters = true; // 若是設置了use-default-filters屬性,則使用設置的值 if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) { useDefaultFilters = Boolean.parseBoolean(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)); } // 構建ClassPathBeanDefinitionScanner,將bean定義註冊委託給scanner類,見下文詳解 ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters); scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults()); scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns()); // 解析resource-pattern屬性 if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) { scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE)); } try { // 解析name-generator屬性 parseBeanNameGenerator(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } try { // 解析scope-resolver、scoped-proxy屬性 parseScope(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } // 解析類型過濾器 parseTypeFilters(element, scanner, parserContext); return scanner; }
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) { return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,readerContext.getEnvironment(), readerContext.getResourceLoader()); } // ClassPathBeanDefinitionScanner.java public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); this.registry = registry; // 若是使用默認的過濾器,註冊默認的過濾器,見下文詳解 if (useDefaultFilters) { registerDefaultFilters(); } setEnvironment(environment); setResourceLoader(resourceLoader); }
protected void registerDefaultFilters() { // 將註解@Component添加到includeFilters中,這將隱式的註冊全部@Component的派生註解,例如@Repository、@Service、@Controller this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { // 若是當前環境中有@ManagedBean,添加到includeFilters中,不然會catch未找到類的異常並忽略 this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); } catch (ClassNotFoundException ex) { // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip. } try { // 若是當前環境中有@Named,添加到includeFilters中,不然會catch未找到類的異常並忽略 this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false)); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } }
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) { // 尋找包路徑下符合要求的bean定義(最多見的就是使用@Component標註的類) Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { // 解析@Scope註解,沒有標註默認爲singleton做用域 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 生成bean的名稱,見下文詳解 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { // beanDefinition的後置處理,就是設置beanDefinition的一些默認屬性,如autowireMode、initMethod等,而且設置AutowireCandidate, // 通常爲true表明能夠自動裝配到其餘bean中 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { // 處理公共註解,見下文詳解 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 若是beanDefinition經過檢查(大多時候是檢查是否是第一次註冊) // 則將definitionHolder添加進註冊中心中,若是有同名的bean在這裏會直接拋出異常 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; }
上面方法中的 registerBeanDefinition()
方法在Spring IoC 默認標籤解析一文中介紹過,這裏再也不贅述。post
public Set<BeanDefinition> findCandidateComponents(String basePackage) { 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 { // 將要掃描的包的路徑拼成完整的,例如:com.leisurexi.ioc.context // 會被拼成 classpath*:com/leisurexi/ioc/context/**/*.class String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; // 獲取路徑下的全部類的資源 Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); for (Resource resource : resources) { // 若是資源是可讀的 if (resource.isReadable()) { try { // 使用metadataReader讀取資源,MetadataReader是專門用來訪問元數據的類 // 包括: 類元數據ClassMetadata、註解元數據AnnotationMetadata等 MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); // 判斷該類是否是候選的組件 if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); // 判斷是不是候選組件,默認條件是class不是接口而且不依賴於內部類 if (isCandidateComponent(sbd)) { candidates.add(sbd); } } } // 省略異常處理... } } } // 省略異常處理... return candidates; }
上面代碼中判斷該類是否是候選的組件的方法 isCandidateComponent(metadataReader)
通常狀況下 是判斷該類是否標註了上文中 ClassPathScanningCandidateComponentProvider#registerDefaultFilters()
中的註解 @Component
、@ManagedBean
、@Named
;@Component
註解是確定會存在與當前環境中的,因此標註了 @Component
或者其派生的註解如:@Repository
、@Service
、@Controller
都會被當作候選組件。ui
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { // 若是BeanDefinition是AnnotatedBeanDefinition類型 if (definition instanceof AnnotatedBeanDefinition) { // 獲取自定義的beanName,如 @Component註解的value值 String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition); // 若是不爲空,而且不是空字符串 if (StringUtils.hasText(beanName)) { // 返回明確的beanName return beanName; } } // 沒有手動指定beanName,默認生成一個,是當前類名的首字母小寫,如User類的beanName是user return buildDefaultBeanName(definition, registry); }
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { // 若是bean標註了@Lazy註解,進行解析 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")); } } // 解析@Primary註解,自動裝配時當出現多個Bean都匹配時,標註了@Primary註解的Bean將做爲首選者 if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } // 解析@DependsOn註解,代表當前bean須要依賴的bean,會保證依賴的bean會在當前bean前實例化 AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class); if (dependsOn != null) { abd.setDependsOn(dependsOn.getStringArray("value")); } // 解析@Role註解,用於標識bean的分類,實際用的比較少 AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } // 解析@Description註解,bean的描述,實際用的比較少 AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); } }
protected void registerComponents(XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) { Object source = readerContext.extractSource(element); CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source); // 將掃描的全部BeanDefinition添加到compositeDef中 for (BeanDefinitionHolder beanDefHolder : beanDefinitions) { compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder)); } boolean annotationConfig = true; // 獲取annotation-config屬性,默認爲true if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) { annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE)); } if (annotationConfig) { // 向註冊中心中註冊用於註解的後置處理器,如AutowireAnnotationProcessor、CommonAnnotationProcessor Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source); // 將註冊的註解後置處理器的BeanDefinition添加到compositeDef的nestedComponents屬性中 for (BeanDefinitionHolder processorDefinition : processorDefinitions) { compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition)); } } // 觸發註冊事件,默認實現爲EmptyReaderEventListener(空實現,沒有具體操做) readerContext.fireComponentRegistered(compositeDef); }
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) { // 獲取beanFactory DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { // 設置dependencyComparator屬性 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { // 設置autowireCandidateResolver屬性(設置自動注入候選對象的解析器 // 用於判斷BeanDefinition是否爲候選對象) beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); // 註冊用於處理@Configuration註解的後置處理器 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { // 建立一個ConfigurationClassPostProcessor的BeanDefinition RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); // 將def添加進註冊中心 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 註冊用於處理@Autowired、@Value、@Inject註解的後置處理器 if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 註冊用於處理@Resource、@PostConstructor、@PostDestroy註解的後置處理器 if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 註冊用於處理JPA註解的後置處理器,如@PersistenceContext、@PersistenceUnit if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); try { def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader())); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex); } def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)); } // 註冊用於處理@EventListener註解的後置處理器 if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } // 註冊內部管理用於生產ApplicationListener對象的EventListenerFactory對象 if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }
本文主要介紹了 Spring 解析 context:component-scan
標籤的解析流程,咱們能夠從新整理一下思路:this
@Component
註解以及它的派生註解當作組件註冊。BeanDefinition
;解析 @Scope
註解,沒有默認爲 singleton
;生成 bean
的名稱,首先會用 @Component
的 value
屬性,若是爲空或空字符串則默認使用類名,並把首字母轉成小寫;而後對一些註解的解析,如 @Lazy
、@Primary
、@DependsOn
等;最後檢查註冊中心中是否包含當前 beanName
,若是沒有直接添加進註冊中心,不然若是不是同一個類會拋出異常。好比 com.leisurexi.a.User
和 com.leisurexi.b.User
同時添加 @Component
註解而且不手動指定不一樣的 beanName
在啓動時就會拋出異常。@Configuration
註解的 ConfigurationClassPostProcessor
。@Autowired
、@Value
、@Inject
註解的 AutowiredAnnotationBeanPostProcessor
。@Resource
、@PostConstructor
、@PostDestroy
註解的 CommonAnnotationBeanPostProcessor
。PersistenceAnnotationBeanPostProcessor
。@EventListener
註解的 EventListenerMethodProcessor
。最後,我模仿 Spring 寫了一個精簡版,代碼會持續更新。地址:https://github.com/leisurexi/tiny-spring。