本篇主要梳理下这个ConfigurationClassPostProcessor(BeanFactoryPostProcessor)对@Configuration、@Component、@Import、@ImportResource、@ComponentScan这些注解的扫描,及由这些注解加载的Bean注册到BeanFactory。
一、ConfigurationClassPostProcessor的结构
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException; }
我们可以看到ConfigurationClassPostProcessor的主要结构是有实现BeanDefinitionRegistryPostProcessor。那这个postProcessBeanDefinitionRegistry方法是在哪里被调用的呢?其是在AbstractApplicationContext的refresh方法中被调用的,关于这个refresh方法的具体内容我们就不再展开了,以前有梳理过,有兴趣可以看下以前的博文。
@Override public void refresh() throws BeansException, IllegalStateException { ........ // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); ....... }
二、postProcessBeanDefinitionRegistry方法
下面我们来具体分析下ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法:
1、postProcessBeanDefinitionRegistry方法
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { ........ processConfigBeanDefinitions(registry); }
2、processConfigBeanDefinitions方法
这个processConfigBeanDefinitions方法的处理逻辑有点多,我们分为几个部分来梳理,避免过长,看的比较乱。
1、第一部分configCandidates(List)的添加
List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } }
这里首先是将registry(所有注册的BeanDefinition)中所有的BeanDefinition循环获取。这里有一个if、else if。这里第一个if是相当于对第二个else if的是否有处理判断,如果在else if中有处理了,就不需要再进入到else if处理。
public static boolean isFullConfigurationClass(BeanDefinition beanDef) { return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE)); } public static boolean isLiteConfigurationClass(BeanDefinition beanDef) { return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE)); } private static final String CONFIGURATION_CLASS_FULL = "full"; private static final String CONFIGURATION_CLASS_LITE = "lite"; private static final String CONFIGURATION_CLASS_ATTRIBUTE = Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
可以看到这里是否已经用else if处理的标注是看这个BeanDefinition有没有设置CONFIGURATION_CLASS_ATTRIBUTE属性,如果有就表示已经处理了(会在else if中进行设置)。
下面我们来看下else if的判断条件ConfigurationClassUtils.checkConfigurationClassCandidate:
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { String className = beanDef.getBeanClassName(); ........... AnnotationMetadata metadata; if (beanDef instanceof AnnotatedBeanDefinition && metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata(); } else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) { Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass(); metadata = new StandardAnnotationMetadata(beanClass, true); } else { .... MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className); metadata = metadataReader.getAnnotationMetadata(); ........ } if (isFullConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } else if (isLiteConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { return false; } ........ return true; }
这一段主要是有两部分。第一部分是通过这个BeanDefinition看其哪种类型,然后获取对应的AnnotationMetadata,这个AnnotationMetadata我们在前面我在有提到个,其主要是用来描叙这个BeanDefinition对应Class有加那些注解,及这些注解的信息(关于BeanDefinition的父子结构如AbstractBeanDefinition 、AnnotatedBeanDefinition有哪些子类及对应的使用逻辑,这些前面博文也有梳理,话说现在我的影响也不是很深了,O(∩_∩)O哈哈~)。不过通过见名知意,我们可以大概知道注解相关的BeanDefiniton一般为AnnotationMetadata。例如我们的demo:
@Configuration public class MyConfiguration { @Bean public MyFilter getFilter() { return new MyFilter(); } }
其的描叙就是用的AnnotationMetadata的子类。然后我们再来看下这个metadata所表示的信息
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { @AliasFor(annotation = Component.class) String value() default ""; }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface Component { String value() default ""; }
可以看到这里jdk的元注解:Target、Retention、Documented并不会注入到metadata去描叙。其描叙的是spring自定义的注解如Component、Indexed。其各个属性所描叙的这里就不再分享了,注解就能看明白。
获取到metadata后我们来看第二部分:isFullConfigurationCandidate、isLiteConfigurationCandidate方法的调用,这里就与前面if那个逻辑对应,看是哪种情况,再设置CONFIGURATION_CLASS_ATTRIBUTE。
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) { return metadata.isAnnotated(Configuration.class.getName()); } public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) { if (metadata.isInterface()) { return false; } // Any of the typical annotations found? for (String indicator : candidateIndicators) { if (metadata.isAnnotated(indicator)) { return true; } } // Finally, let's look for @Bean methods... try { return metadata.hasAnnotatedMethods(Bean.class.getName()); } ......... } private static final Set<String> candidateIndicators = new HashSet<>(4); static { candidateIndicators.add(Component.class.getName()); candidateIndicators.add(ComponentScan.class.getName()); candidateIndicators.add(Import.class.getName()); candidateIndicators.add(ImportResource.class.getName()); }
可以看到,这里就是前面添加到configCandidates的入口,如果不是这两种情况,checkConfigurationClassCandidate方法就返回的false,就不会添加到configCandidates,然后configCandidates就为empty,整个processConfigBeanDefinitions方法就不会往后面处理了。
if (isFullConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } else if (isLiteConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { return false; }
可以看到这两个方法涉及到的注解总共有@Configuration、@Component、@ComponentScan、@Import、@ImportResource、@Bean注解。如果这个BeanDefinition所表示的类上面有除@Bean(不用于类级别标注)的其他对应注解,就返回true。
2、configCandidates非空校验、排序,其他属性初始化
讲完configCandidates的填充后,我们再来看下其他相关逻辑:
if (configCandidates.isEmpty()) { return; } // Sort by previously determined @Order value, if applicable configCandidates.sort((bd1, bd2) -> { .......... }); SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); }
这里需要注意的是,ConfigurationClassPostProcessor有继承EnvironmentAware接口,应该一般会通过这个Aware接口去设置environment。
3、构建ConfigurationClassParser及通过其对configCandidates进行解析处理
// Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { parser.parse(candidates); parser.validate(); ..........(这一部分也很重要,这里先屏蔽,下面再分析) } while (!candidates.isEmpty());
这里先是通过一些成员变量去构建ConfigurationClassParser,再调用parse方法去解析处理candidates。
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } .......... } processDeferredImportSelectors(); }
这里虽然是会判断holder(BeanDefinitionHolder ),这个BeanDefinitionHolder我们在前面源码梳理的时候有提到,其是用来装BeanDefinition的:
public class BeanDefinitionHolder implements BeanMetadataElement { private final BeanDefinition beanDefinition; private final String beanName; @Nullable private final String[] aliases;
这里虽然是分情况调用parse方法,但:
protected final void parse(@Nullable String className, String beanName) throws IOException { MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className); processConfigurationClass(new ConfigurationClass(reader, beanName)); } protected final void parse(Class<?> clazz, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(clazz, beanName)); } protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName)); }
都是大同小异,最终都是构建ConfigurationClass去调用processConfigurationClass方法,这个ConfigurationClass就先不展开了,可以知道其是用来描叙Metadata的。
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) { if (configClass.isImported()) { if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } return; } else { // Explicit bean definition found, probably replacing an import. // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); this.knownSuperclasses.values().removeIf(configClass::equals); } } SourceClass sourceClass = asSourceClass(configClass); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); }
这里的this.conditionEvaluator.shouldSkip就不再展开了,其是对Condition接口的处理,可以看下前面的这篇,有相关的一些梳理。可以看到先是对this.configurationClasses的get如果没有才会调用doProcessConfigurationClass方法去处理(下面有相应的put)。这先是会通过configClass构建一个SourceClass,再调用doProcessConfigurationClass方法,这里是一个do-while结构,这个是用来判断这个Class有没有父类的(先剧透,所以这个可以不关注,就按正常的没有父类这种情况来分析)。
doProcessConfigurationClass方法
@Nullable protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { processMemberClasses(configClass, sourceClass); // Process any @PropertySource annotations for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { ............(这里关于@PropertySources这种注解就先跳过) } // 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)) { ........ } // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces processInterfaces(configClass, sourceClass); // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete return null; }
1、 这里的processMemberClasses方法就先跳过,因为这里也是一个父子类这种循环处理。
2、@ComponentScans、@ComponentScan注解的扫描处理
// 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) { // The config class is annotated with @ComponentScan -> perform the scan immediately Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate( holder.getBeanDefinition(), this.metadataReaderFactory)) { parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } } }
这里是如果当前关于Class描叙的Metadata中有ComponentScans注解或者ComponentScans注解,就遍历解析,通过this.componentScanParser.parse方法:
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); 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 (String pkg : basePackagesArray) { String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); basePackages.addAll(Arrays.asList(tokenized)); } 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)); } protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry); }
可以看到这里是对componentScan注解属性的处理,然后将这些信息设置到scanner(ClassPathBeanDefinitionScanner)中去,这里需要了解@ComponentScan的基本使用,可以搜索下其他的博文介绍。,这里先注意下TypeFilter接口关于exclude、include的设置。然后通过scanner扫描这些包名。
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; }
这里是Scanner扫描器的相关逻辑了,这里我们就梳理下其主要内容。
这里就是通过findCandidateComponents(下面再分析)方法去扫描分析basePackage包,获取其下的BeanDefinition,再遍历,再通过checkCandidate方法(这个方法主要是判断其有没有在当前的registry中,然后不在,就调用registerBeanDefinition方法注入到registry中)。
下面我们来看这里主要的方法findCandidateComponents
其一般会调到scanCandidateComponents方法:
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)) { candidates.add(sbd); } ...... } } } ........ return candidates; }
这里首先是获取该包下所有的资源Resource,即使是没有加对应的注解的也会获取到。然后可读判断,通过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; }
可以看到这里,就是就是对前面注入的TypeFilter,当然springMVC容器默认会注入一些。可以看到如果exclude、include都不满足,最终是返回false不注入。
同时这里我们需要再回到前面关于scanner的创建,我们这里的scanner是ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); 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); } public @interface ComponentScan { .......... boolean useDefaultFilters() default true; ............
protected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader(); try { this.includeFilters.add(new AnnotationTypeFilter( ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false)); ......... } public AnnotationTypeFilter(Class<? extends Annotation> annotationType) { this(annotationType, true, false); } public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) { super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces); this.annotationType = annotationType; this.considerMetaAnnotations = considerMetaAnnotations; }
可以看到这里默认会注入一些includeFilters,通过构建AnnotationTypeFilter,这里我们比较熟悉的是@Component,说到这个@Component,我们知道还有@Repository,、@Service、@Controller。但其实这些@Repository,、@Service其是对@Component注解的拓展,可以用@Component完全代替@Repository,、@Service:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { @AliasFor(annotation = Component.class) String value() default ""; } ....... @Component public @interface Service { @AliasFor(annotation = Component.class) String value() default ""; } ........ @Component public @interface Repository { @AliasFor(annotation = Component.class) String value() default ""; }
之所以由@Component拓展这些注解,就是用来体现分层的。标注其他的在源码级别等于就是标注的@Component,然后在这里通过添加的默认扫描@Component的AnnotationTypeFilter去注入这些Bean。
public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilter { ....... @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { if (matchSelf(metadataReader)) { return true; } } @Override protected boolean matchSelf(MetadataReader metadataReader) { AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); return metadata.hasAnnotation(this.annotationType.getName()) || (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())); }
这里如果有注解@Component,这个isCandidateComponent就返回true,去去构建这个Resouce的BeanDefinition,当然,你也可以去实现自己的TypeFilter(同时SpringMVC自己也有注入其他的TypeFilter)。
isCandidateComponent方法调用构建BeanDefinition后,再调用 isCandidateComponent,这次的入参是BeanDefinition:
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); }
这一步也通过,就正式将这个BeanDefinition添加到candidates中等待注入。
现在我们再回到最初的doProcessConfigurationClass方法,我们当前将的还是这个逻辑:
2、@ComponentScans、@ComponentScan注解的扫描处理
这里的调用有点深入了:
for (AnnotationAttributes componentScan : componentScans) { Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate( holder.getBeanDefinition(), this.metadataReaderFactory)) { parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } }
前面这一部分就是获取scannedBeanDefinitions。可以看到这里会再调用ConfigurationClassUtils.checkConfigurationClassCandidate方法判断,通过再调用parse方法,到这里就有一个循环了,与前面"这里先是通过一些成员变量去构建ConfigurationClassParser,在调用去parse方法去解析处理candidates" 这里,整个就有形成一个循环。因为这里你可能通过@ComponentScan注入的BeanDefinition会再有@Configuration、@ComponentScan这些注解,所以会再扫描注入。
3、@Import注解的处理
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { if (visited.add(sourceClass)) { .......... imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } } private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException { ......... else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } ........... } public @interface Import { /** * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar} * or regular component classes to import. */ Class<?>[] value(); }
可以看到@Import注解的,注入如ImportSelector、ImportBeanDefinitionRegistrar(这个用法可以搜索其他博文),同时这里会形成两个循环调用,如果是ImportSelector,会有一个这个方法本身的循环调用processImports,如果是一般的,就会调用processConfigurationClass,这里就又回到前面的方法循环了:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { ............ SourceClass sourceClass = asSourceClass(configClass); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); }
同时这里需要注意this.configurationClasses.put的操作。因为这里最初我梳理这个源码的时候有个疑问,这些@Import、@ComponentScan等注解主要是为了注入其他的我们自定义要使用的Bean的,关于@Import这里整个逻辑没有体现这个点,例如我们通过@Import注入一个普通的类,例如Student,并且这个Student上面并没有加@Component等注解,这个Student是怎样注入的呢,答案就是在个configurationClasses中。
4、@ImportResource、@Bean的注入
// Process any @ImportResource annotations AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); }
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) { this.importedResources.put(importedResource, readerClass); } private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) { AnnotationMetadata original = sourceClass.getMetadata(); Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName()); ............ return beanMethods; }
上面这些获取的信息都是设置在configClass(ConfigurationClass)中。
下面的关于processInterfaces、以及SuperClass就不展开了。到这里整个doProcessConfigurationClass方法就梳理完成了。然后这些信息都已经通过configClass保存到了configurationClasses中了
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
然后在回到parse方法,这里最后会处理@Import注入的DeferredImportSelector,通过processDeferredImportSelectors方法。
我们再回到最开始的地方,processConfigBeanDefinitions方法:
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); do { parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); ............ this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty());
这里就是通过parser.parse(candidates)方法将这些信息填充到parser(ConfigurationClassParser)的属性,例如前面的configurationClasses,然后通过parser.getConfigurationClasses()获取构建configClasses,再通过
this.reader.loadBeanDefinitions(configClasses);
reader(ConfigurationClassBeanDefinitionReader)去注入这些Bean:
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); } } private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
这里注入这些BeanDefinition后,会candidates.clear(),在获取一次registry.getBeanDefinitionNames(),这次排除以前的,再检索这次新注入的BeanDefinition,因为我们可能例如通过注入的XML中读取到了新的Bean,这些Bean再次出发解析:例如我们前面没有展开的解析的:
private void loadBeanDefinitionsFromImportedResources( Map<String, Class<? extends BeanDefinitionReader>> importedResources) { Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>(); for (Map.Entry<String, Class<? extends BeanDefinitionReader>> entry : importedResources.entrySet()) { String resource = entry.getKey(); Class<? extends BeanDefinitionReader> readerClass = entry.getValue(); if (BeanDefinitionReader.class == readerClass) { if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) { // When clearly asking for Groovy, that's what they'll get... readerClass = GroovyBeanDefinitionReader.class; } else { // Primarily ".xml" files but for any other extension as well readerClass = XmlBeanDefinitionReader.class; } } ............. // TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations reader.loadBeanDefinitions(resource); } }
这里可能创建XmlBeanDefinitionReader去解析注入的XML。如果能读到新的BeanDefinition,再通过ConfigurationClassUtils.checkConfigurationClassCandidate方法判断,通过再添加到candidates(前面clear了),然后再出发while的循环。
至此,关于这个ConfigurationClassPostProcessor的主要逻辑就梳理完成了。