Spring源码解析(三) 包扫描,ConfigurationClassPostProcessor(1)

编程入门 行业动态 更新时间:2024-10-25 06:30:22

Spring<a href=https://www.elefans.com/category/jswz/34/1770099.html style=源码解析(三) 包扫描,ConfigurationClassPostProcessor(1)"/>

Spring源码解析(三) 包扫描,ConfigurationClassPostProcessor(1)

上一篇主要讲了refresh()方法的invokeBeanFactoryPostProcessors方法,主要是执行后置处理器BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,
执行BeanDefinitionRegistryPostProcessor的方法是
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
进入方法

private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {//循环遍历spring内部的BeanDefinitionRegistryPostProcessor,其实只有一个,即ConfigurationClassPostProcessorfor (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanDefinitionRegistry(registry);}}

然后走到了ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法

@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {//根据对象的内存地址算出的一个数值,和object.hashCode()不同int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}this.registriesPostProcessed.add(registryId);//设置配置类processConfigBeanDefinitions(registry);}

详解一下processConigBeanDefitions方法

	/*** postProcessBeanDefinitionRegistry方法调用,处理包解析* Build and validate a configuration model based on the registry of* {@link Configuration} classes.*/public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();//得到beanFactory中所有的beanNamesString[] candidateNames = registry.getBeanDefinitionNames();//循环遍历beanNamesfor (String beanName : candidateNames) {//根据beanName得到bdBeanDefinition beanDef = registry.getBeanDefinition(beanName);//判断bd是不是被处理过if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}//检查bd是不是加了@Configuration注解else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {//将所有@Configuration标识的类都放到列表中configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were found//如果是空则直接返回if (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicable//类按order排序,不重要configCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integerpare(i1, i2);});// Detect any custom bean name generation strategy supplied through the enclosing application context//设置bean生成策略,不重点关注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) {thisponentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}if (this.environment == null) {this.environment = new StandardEnvironment();}// Parse each @Configuration class//实例化ConfigurationClassParser,为了解析各个配置类ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, thisponentScanBeanNameGenerator, registry);//去重Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());do {//开始扫描包,最重要的方法parser.parse(candidates);parser.validate();//去重Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());//清除已经被解析的配置类configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}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());// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classesif (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {// Clear cache in externally provided MetadataReaderFactory; this is a no-op// for a shared cache since it'll be cleared by the ApplicationContext.((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();}}

首先先看下检查bd是不是配置类的方法,里面有很重要的操作。即org.springframework.context.annotation.ConfigurationClassUtils#checkConfigurationClassCandidate方法

/**** 判断类是不是带有@Configuration注解和* 没有标注@Configuration,但是标注了@Import,@Component,@InportSource,@ComponentScan也被标识成标注@Configuration*/public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {//得到bd的classNameString className = beanDef.getBeanClassName();if (className == null || beanDef.getFactoryMethodName() != null) {return false;}//声明元数据AnnotationMetadata metadata;//对AnnotatedBeanDefinition的bd和AbstractBeanDefinition的bd处理方式不同//从AnnotatedBeanDefinition的bd中得到元数据,从元数据中判断是不是被注解修饰if (beanDef instanceof AnnotatedBeanDefinition &&className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {// Can reuse the pre-parsed metadata from the given BeanDefinition...//AnnotatedBeanDefinition得到元数据的方法metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();}//从AbstractBeanDefinition的bd中得到元数据else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {// Check already loaded Class if present...// since we possibly can't even load the class file for this Class.//AbstractBeanDefinition得到元数据的方法Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();metadata = new StandardAnnotationMetadata(beanClass, true);}else {try {//其他bd获取元数据的方法MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);metadata = metadataReader.getAnnotationMetadata();}catch (IOException ex) {if (logger.isDebugEnabled()) {logger.debug("Could not find class file for introspecting configuration annotations: " +className, ex);}return false;}}/*** 判断当前bd是不是加了@Configuration注解,如果存在,spring会把它标注成“full”* spring认为他是一个全注解的类*/if (isFullConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}/*** 判断是否加了@Import,@Component,@InportSource,@ComponentScan注解* 如果不存在@Configuration注解,spring会标注为“lite”,被认为部分注解类*/else if (isLiteConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);}/*** 不管是全注解类还是部分注解类,spring都会把它们认作配置类* 但如果上述几个注解都没加,则不是配置类,返回false*/else {return false;}//进行排序,不重要Integer order = getOrder(metadata);if (order != null) {beanDef.setAttribute(ORDER_ATTRIBUTE, order);}return true;}

lite标注的几个注解证明:isLiteConfigurationCandidate方法

for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}

进行debug,看candidateIndicators

这也就是我们再写配置类中,直接写@Component也能使用的证明

@ComponentScan("com.spring")
public class Config {
}

如果到这里还能看懂,那下面进入正题,研究解析包的操作,parse方法

public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {//根据AnnotatedBeanDefinition的元数据去扫描if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}//根据AbstractBeanDefinition的元数据去扫描else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}//根据其他种类bd的元数据去扫描else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);}}this.deferredImportSelectorHandler.process();}

看一下AnnotatedBeanDefinition的解析,由于发生了多次调用,这里直接分析到真正的解析方法,到org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass方法,先看@ComponentScan解析部分

Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {//遍历所有@ComponentScan的注解for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediately//扫描普通类Set<BeanDefinitionHolder> scannedBeanDefinitions =thisponentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}

进入thisponentScanParser.parse方法

/*** 主要对componentScan注解中的参数进行解析* @param componentScan* @param declaringClass* @return*/public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {//处理@ComponentScan的信息,value,scopedProxy,excludeFilters等等//又new了一个scanner,说明在AnnotationConfigApplicationContext中new的Scanner没用到ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);//得到bean的生成器Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :BeanUtils.instantiateClass(generatorClass));//和web相关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的BeanDefinitionDefaults的默认值填充上lazy值,因为这时要扫描的bd还没产生,需要存储在一个地方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);Collections.addAll(basePackages, 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) {@Overrideprotected boolean matchClassName(String className) {return declaringClass.equals(className);}});//扫描方法return scanner.doScan(StringUtils.toStringArray(basePackages));}

这个方法主要解析@ComponentScan注解的各个属性,然后得到要解析的包,进行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) {//扫描包,使用asm实现,得到的BeanDefinition是AnnotatedGenericBeanDefinition,是AbstractBeanDefinition的子类Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//循环遍历扫描出来的bdfor (BeanDefinition candidate : candidates) {//得到Scope的元数据ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);//bd设置Scope属性candidate.setScope(scopeMetadata.getScopeName());//生成beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);//下面两个if主要是设置bd的属性值,如果先都按没有配置属性(@lazy等等...)来,再判断真正有没有加注解配属性,将真正的属性配置上if (candidate instanceof AbstractBeanDefinition) {//如果扫描出来的类是AbstractBeanDefinition的子类//则为它设置默认值,比如lazy,init,destory..postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {//这个方法是查看每个bd实际被标明注解的情况,将默认的属性替代掉AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);//设置Scope代理模式definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//加入到set中beanDefinitions.add(definitionHolder);//注册方法,加入到map当中,前面已经分析过registerBeanDefinition(definitionHolder, this.registry);}}}//返回注册到的扫描出来的beanreturn beanDefinitions;}

注解已经写好,可以一行一行研究,其中,findCandidateComponents方法是真正解析的方法,用的asm技术,比较困难,感兴趣可以去研究,研究spring这里可以用黑盒理论。
到这里就完成了@ComponentScan注解包的扫描,再回到org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass,方法并没有结束,解析完@ComponentScan还要解析@Import注解。

@Import注解主要可以分为三种情况,①添加ImportSelector实现类,②添加普通类,③添加ImportBeanDefinitionRegister实现类

//处理Import//ImportSelect//普通类//ImportBeanDefinitionRegisterprocessImports(configClass, sourceClass, getImports(sourceClass), true);//处理@ImportResource注解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);}}//处理个性化的@Bean方法Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}//处理接口的默认方法processInterfaces(configClass, sourceClass);//如果有父类,则执行父类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 recursereturn sourceClass.getSuperClass();}}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, boolean checkForCircularImports) {//判断是不是空if (importCandidates.isEmpty()) {return;}if (checkForCircularImports && isChainedImportOnStack(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));}else {this.importStack.push(configClass);try {//遍历@Import(class)中的类for (SourceClass candidate : importCandidates) {//如果是ImportSelector的实现类if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector -> delegate to it to determine imports//得到该类的ClassClass<?> candidateClass = candidate.loadClass();//实例化此ImportSelectorImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);//设置ImportSelector的beanFactory,供方法内使用ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);//如果selector是DeferredImportSelector,另外执行方法if (selector instanceof DeferredImportSelector) {this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);}else {//得到ImportSelector实现类返回的类,递归判断返回的类是不是也加了@ImportString[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}}//如果当前类是ImportBeanDefinitionRegistrar实现类else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitionsClass<?> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar =BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);//处理ImportBeanDefinitionRegistrar方法ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}else {// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->// process it as an @Configuration class//处理普通类,直接注册到beanFactorythis.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass));}}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +configClass.getMetadata().getClassName() + "]", ex);}finally {this.importStack.pop();}}

主要分三种情况进行处理。注释已经表明,到这里,扫描包的方法基本完成。ConfigurationClassPostProcessor的processConfigBeanDefinitions方法已经完成。
下面一篇将ConfigurationClassPostProcessor中postProcessBeanFactory方法的作用。

更多推荐

Spring源码解析(三) 包扫描,ConfigurationClassPostProcessor(1)

本文发布于:2024-03-12 22:51:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1732597.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:源码   Spring   ConfigurationClassPostProcessor

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!