下面我们进入refresh()方法里面去:debug到
this.invokeBeanFactoryPostProcessors(beanFactory);
这个时发现加入了大量类
那我们继续往下(注意我们的注意力在beanfactory里面(一般在this和refistry里面都是同一个传递的类或者有继承关系)):
找到这个方法:
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
java8之后的版本:
postProcessor.postProcessBeanDefinitionRegistry(registry);
与上面一样,进入这个方法:
parser.parse(candidates);
发现了这个方法添加了:configurationClasses类,我们后来添加到工厂中的类大多数来自于这里
这个扫描包下的所有类:
那必须进去看看:
进入这个方法:
sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
@Nullable protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter) throws IOException { if (configClass.getmetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass, filter); } // 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); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getmetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations Set 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 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) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @import annotations processimports(configClass, sourceClass, getimports(sourceClass), filter, 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 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; }
该方法前面是包的扫描,后面是import引入:
下面我们来研究研究这两个类和方法:
注意这里是难点:因为接下来的都是具有递归的思想(包扫描和import):
首先记住这个方法:processConfigurationClass(ConfigurationClass configClass, Predicate filter)
protected void processConfigurationClass(ConfigurationClass configClass, Predicatefilter) 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); } // Otherwise ignore new imported config class; existing non-imported class overrides it. 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); } } // Recursively process the configuration class and its superclass hierarchy. SourceClass sourceClass = asSourceClass(configClass, filter); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); }
能看到这个方法调用了
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
包解析这个方法:
然后我们再看这个方法里面也会调用**processConfigurationClass(ConfigurationClass configClass, Predicate filter)**方法:
看到绿色的那一句,进去:
能看到这里也调用了**processConfigurationClass(ConfigurationClass configClass, Predicate filter)**方法:
import解析方法:
我们找到绿色的那一句点进去:
private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass, CollectionimportCandidates, Predicate exclusionFilter, boolean checkForCircularimports) { if (importCandidates.isEmpty()) { return; } if (checkForCircularimports && isChainedimportOnStack(configClass)) { this.problemReporter.error(new CircularimportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(importSelector.class)) { // Candidate class is an importSelector -> delegate to it to determine imports Class> candidateClass = candidate.loadClass(); importSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, importSelector.class, this.environment, this.resourceLoader, this.registry); Predicate selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredimportSelector) { this.deferredimportSelectorHandler.handle(configClass, (DeferredimportSelector) selector); } else { String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata()); Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processimports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(importBeanDefinitionRegistrar.class)) { // Candidate class is an importBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class> candidateClass = candidate.loadClass(); importBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, importBeanDefinitionRegistrar.class, 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 this.importStack.registerimport( currentSourceClass.getmetadata(), candidate.getmetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } 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(); } } }
发现这里也是和上面一样!!!!
在这个方法里,我们想看看是怎么解析类到configurationClasses里面的:
这里跟明显是最后局添加的:
难度在于递归遍历:
刚开始的时候能看到:configClass的值,但这时不是要加进去的值
我们debug继续往下:这个方法是得到我们要的类的方法,进去看看:
进去后我们看到最后起作用的是这个方法;
看到传递的是这个包名!!!
然后进这个方法:
protected SetdoScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new linkedHashSet<>(); for (String basePackage : basePackages) { Set 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; }
走过这个方法时,
能看到我们得到了这个类:
我们在进入这个类里面去:
Setcandidates = findCandidateComponents(basePackage);
private SetscanCandidateComponents(String basePackage) { Set candidates = new linkedHashSet<>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolvebasePackage(basePackage) + '/' + this.resourcePattern; Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } if (resource.isReadable()) { try { metadataReader metadataReader = getmetadataReaderFactory().getmetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setSource(resource); 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 (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; }
发现了这个类,然后看这句得到最终解析类路径的方法:
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolvebasePackage(basePackage) + '/' + this.resourcePattern;
看到了这个路径的值:
再看我们的包结构:
明了了吧!!!!!!
那肯定的是得到:
这个类的,然后后面就是通过路径得到类装进候选里面传递出去!!!!
然后执行到出来后,我们再来看doScan这个方法:
看到这最后四句,是不是好熟悉,没错就是和前面一样的包装,将类放在beanfactory里面;
这里获得了阶段性的成果了,已经知道了包的类怎么扫描到spring的工厂里了!!!!!!!!
不过这里要注意checkCandidate方法,后面递归有作用:
发现了在这里我们就把该类放到了工厂里面去啦!!!!
然后执行出来,看看我们doProcessConfigurationClass()开始递归啦!
这时看到我们递归进去的类已经是dtest2Application了
进去:
看到传递过去的congigurationClass已经是:
class path resource [com/example/dtest2/Dtest2Application.class]
继续:发现现在是在第一个循环里面了:
又开始了doProcessConfigurationClass()方法:
第二次得到的路径名字为:
总结:spring直接包扫描流程我们现在已经知道了,那@import和@Component呢?
续:spring源码5–@import和@Compone



