ScannedGenericBeanDefinition的初始化使用过程主要是在ConfigurationClassParser类中进行对应处理的。这里我们先通过一个demo查看其流程:
@Test public void testComponents() throws Exception { ConfigurationClassParser configurationClassParser = new ConfigurationClassParser( new CachingMetadataReaderFactory(), new FailFastProblemReporter(), new StandardEnvironment(), new DefaultResourceLoader(), new AnnotationBeanNameGenerator(), new DefaultListableBeanFactory()); configurationClassParser.parse(loadAsConfigurationSource(ComponentObj.class), "componentObj"); }
protected String loadAsConfigurationSource(Class<?> clazz) throws Exception { return clazz.getName(); }
@ComponentScan(basePackages = {"fev"}) class ComponentObj { }
protected final void parse(@Nullable String className, String beanName) throws IOException { Assert.notNull(className, "No bean class name for configuration class bean definition"); MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className); processConfigurationClass(new ConfigurationClass(reader, beanName)); }
public ConfigurationClass(MetadataReader metadataReader, String beanName) { Assert.notNull(beanName, "Bean name must not be null"); this.metadata = metadataReader.getAnnotationMetadata(); this.resource = metadataReader.getResource(); this.beanName = beanName; }
final class ConfigurationClass { private final AnnotationMetadata metadata; private final Resource resource; @Nullable private String beanName; ............. }
这里的MetadataReader与ConfigurationClass都是去描叙这个class的内容的。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { ........... } // Recursively process the configuration class and its superclass hierarchy. SourceClass sourceClass = asSourceClass(configClass); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); }
然后这里的this.conditionEvaluator.shouldSkip方法的调用,在前一章已经讲过,其是看当前class有没有注解Condition进行对应match判断处理。
往下,可以看到这里是用来一个map去做缓存处理,SourceClass:
private class SourceClass implements Ordered { private final Object source; // Class or MetadataReader private final AnnotationMetadata metadata; ........... }
然后来到doProcessConfigurationClass方法:
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { ........... // Process any @PropertySource annotations for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } } // Process any @ComponentScan annotations Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate( holder.getBeanDefinition(), this.metadataReaderFactory)) { parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } } } (这后面的内容先不展开) // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true); .............. return null; }
首先是获取@PropertySources、@PropertySource注解的内容,通过后面的
if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); }
所以这里应该是将这两个注解的描叙设置到容器的环境中,先不展开了。
然后就是本次的关键,获取@ComponentScans、@ComponentScan注解的内容。如果不为空,这里又掉了一次this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN),不过这次传的是REGISTER_BEAN,最开始是传的PARSE_CONFIGURATION。
获取关于@ComponentScans、@ComponentScan注解的属性描叙AnnotationAttributes后然后遍历调用:
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); .............. ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy"); if (scopedProxyMode != ScopedProxyMode.DEFAULT) { scanner.setScopedProxyMode(scopedProxyMode); } else { Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver"); scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass)); } scanner.setResourcePattern(componentScan.getString("resourcePattern")); for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); } } boolean lazyInit = componentScan.getBoolean("lazyInit"); if (lazyInit) { scanner.getBeanDefinitionDefaults().setLazyInit(true); } Set<String> basePackages = new LinkedHashSet<>(); String[] basePackagesArray = componentScan.getStringArray("basePackages"); .......... for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(declaringClass)); } scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) { return declaringClass.equals(className); } }); return scanner.doScan(StringUtils.toStringArray(basePackages)); }
可以看到这里是将AnnotationAttributes描叙的内容设置到ClassPathBeanDefinitionScanner中:
设置之后调用ClassPathBeanDefinitionScanner的doScan方法(scanner.doScan(StringUtils.toStringArray(basePackages))):
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) { 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); } 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; }
然后遍历basePackages包,再通过调用findCandidateComponents方法,去获取每个包下面定义的BeanDefinition:
String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; private String resourcePattern = DEFAULT_RESOURCE_PATTERN; static final String DEFAULT_RESOURCE_PATTERN = "**/*.class" private Set<BeanDefinition> scanCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { 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 = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } .............. return candidates; }
private ResourcePatternResolver getResourcePatternResolver() { if (this.resourcePatternResolver == null) { this.resourcePatternResolver = new PathMatchingResourcePatternResolver(); } return this.resourcePatternResolver; }
获取搜索路径packageSearchPath下面的class文件:
获取后遍历通过isCandidateComponent方法判断:
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } return false; }
可以看到这里就是处理在@ComponentScans、@ComponentScan中加的excludeFilters、includeFilters属性值实现TypeFilter接口的类。进行match,一种是排除、一种是包括,类似于前面讲的Condition注解的作用。
满足的话,然后就将扫描到的class转换到系统,描叙为ScannedGenericBeanDefinition Beandefinition。
将这些resource描叙为ScannedGenericBeanDefinition并添加到candidates后就返回到doScan(String... basePackages)方法的调用:
Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); ........ }
这里就是设置ScannedGenericBeanDefinition beanDefinition的属性。类型上章讲的设置AnnotatedGenericBeanDefinition的属性。
这些都处理完了后,我们再回到doProcessConfigurationClass方法,下面就是最开始描叙的
processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); ............
这里就先不展开了,这些流程等到梳理ApplicationContext容器的时候,再具体分析其内容。本次主要是是描叙ScannedGenericBeanDefinition的初始化过程。