1.扫描包路径下所有的类加载解析成bean定义信息
ClassPathBeanDefinitionScanner .doScan方法调用路径
doScan:276, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
parse:95, ComponentScanBeanDefinitionParser (org.springframework.context.annotation)
parse:76, NamespaceHandlerSupport (org.springframework.beans.factory.xml)
parseCustomElement:1475, BeanDefinitionParserDelegate (org.springframework.beans.factory.xml)
parseCustomElement:1452, BeanDefinitionParserDelegate (org.springframework.beans.factory.xml)
parseBeanDefinitions:181, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
doRegisterBeanDefinitions:150, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:97, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:526, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
doLoadBeanDefinitions:397, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:341, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:310, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:190, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:234, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:197, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:267, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:150, AbstractXmlApplicationContext (org.springframework.context.support)
loadBeanDefinitions:102, AbstractXmlApplicationContext (org.springframework.context.support)
refreshBeanFactory:138, AbstractRefreshableApplicationContext (org.springframework.context.support)
obtainFreshBeanFactory:718, AbstractApplicationContext (org.springframework.context.support)
refresh:577, AbstractApplicationContext (org.springframework.context.support)
<init>:150, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:98, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:15, MyClassPathXmlApplicationContext (com.mashibing)
main:84, Test (com.mashibing)
parse:95, ComponentScanBeanDefinitionParser (org.springframework.context.annotation)
解析节点使用scanner在执行的basePackages包中执行扫描,返回已注册的bean定义
@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 获取<context:component-scan>节点的base-package属性值String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);//base-package// 解析占位符basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);// 解析base-package(允许通过,;\t\n中的任一符号填写多个)String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);// Actually scan for bean definitions and register them.// 构建和配置ClassPathBeanDefinitionScannerClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);//类路径Bean定义扫描器// 使用scanner在执行的basePackages包中执行扫描,返回已注册的bean定义Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);// 组件注册(包括注册一些内部的注解后置处理器,触发注册事件)registerComponents(parserContext.getReaderContext(), beanDefinitions, element);return null;}
doScan:276, ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
扫描开始
/*** Perform a scan within the specified base packages, 在指定的基本包内执行扫描,* returning the registered bean definitions. 返回已注册的bean定义。* <p>This method does <i>not</i> register an annotation config processor 这个方法不注册注释配置处理器* but rather leaves this up to the caller. 而是把这个问题留给调用者。* @param basePackages the packages to check for annotated classes 要检查带注释的类的包* @return set of beans registered if any for tooling registration purposes (never {@code null}) 为了工具注册目的而注册的bean集(从不{@code null})*/protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();// 遍历basePackagesfor (String basePackage : basePackages) {// 扫描basePackage,将符合要求的bean定义全部找出来Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 遍历所有候选的bean定义for (BeanDefinition candidate : candidates) {// 解析@Scope注解,包括scopeName和proxyModeScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());// 使用beanName生成器来生成beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {// 处理beanDefinition对象,例如,此bean是否可以自动装配到其他bean中postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 处理定义在目标类上的通用注解,包括@Lazy,@Primary,@DependsOn,@Role,@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查beanName是否已经注册过,如果注册过,检查是否兼容if (checkCandidate(beanName, candidate)) {// 将当前遍历bean的bean定义和beanName封装成BeanDefinitionHolderBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);// 根据proxyMode的值,选择是否创建作用域代理definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册beanDefinitionregisterBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
// 扫描basePackage,将符合要求的bean定义全部找出来
Set candidates = findCandidateComponents(basePackage);
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 {//组装扫描路径(组装完成后是这种格式:classpath*:org/springframework/learn/demo01/**/*.class)String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);//根据路径获取资源对象,即扫描出该路径下的的所有class文件,得到 Resourceboolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {//根据资源对象获取资源对象的MetadataReaderMetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);if (isCandidateComponent(metadataReader)) {// 1. 是否需要初始化为spring bean,即是否有 @Component、@Service等注解//2. 查看配置类是否有@Conditional一系列的注解,然后是否满足注册Bean的条件ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);// 将 metadataReader 转换为 ScannedGenericBeanDefinition,这也是BeanDefinition家族中的一员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;}
判断是否可以生成bean定义信息
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;}
/*** Determine whether the given class is a candidate component based on any 确定给定的类是否是基于任何的候选组件* {@code @Conditional} annotations.{@code @Conditional}注释。* @param metadataReader the ASM ClassReader for the class* @return whether the class qualifies as a candidate component*/private boolean isConditionMatch(MetadataReader metadataReader) {if (this.conditionEvaluator == null) {this.conditionEvaluator =new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);}return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());}
/*** Determine if an item should be skipped based on {@code @Conditional} annotations.* The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a* {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION})** @param metadata the meta data* @return if the item should be skipped*/public boolean shouldSkip(AnnotatedTypeMetadata metadata) {return shouldSkip(metadata, null);}
/*** 基于@Conditional标签判断该对象是否要跳过* <p>* Determine if an item should be skipped based on {@code @Conditional} annotations.** @param metadata the meta data* @param phase the phase of the call* @return if the item should be skipped*/public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {// metadata为空或者配置类中不存在@Conditional标签if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {return false;}// 采用递归的方式进行判断,第一次执行的时候phase为空,向下执行 // 判断传入的 phaseif (phase == null) {// 下面的逻辑判断中,需要进入ConfigurationClassUtils.isConfigurationCandidate方法,主要的逻辑如下:// 1、metadata是AnnotationMetadata类的一个实例// 2、检查bean中是否使用@Configuration注解// 3、检查bean不是一个接口// 4、检查bean中是否包含@Component @ComponentScan @Import @ImportResource中任意一个// 5、检查bean中是否有@Bean注解// 只要满足其中1,2或者1,3或者1,4或者1,5就会继续递归if (metadata instanceof AnnotationMetadata &&ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);}return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);}// 实例化 condition,其放入 conditions 中List<Condition> conditions = new ArrayList<>();for (String[] conditionClasses : getConditionClasses(metadata)) {// 1. getConditionClasses(metadata):获取 @Conditional 中指定的判断类for (String conditionClass : conditionClasses) {// 获取到@Conditional注解后面的value数组 // 2. 实例化操作(用到的还是反射),统一放到 conditions 中Condition condition = getCondition(conditionClass, this.context.getClassLoader());conditions.add(condition);}}// 对相关的条件进行排序操作AnnotationAwareOrderComparator.sort(conditions);// 3. 排序上面得到的 condition 实例for (Condition condition : conditions) {ConfigurationPhase requiredPhase = null;if (condition instanceof ConfigurationCondition) {requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();}// requiredPhase只可能是空或者是ConfigurationCondition的一个实例对象if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {//此逻辑为:1.requiredPhase不是ConfigurationCondition的实例//2.phase==requiredPhase,从上述的递归可知:phase可为ConfigurationPhase.PARSE_CONFIGURATION或者ConfigurationPhase.REGISTER_BEAN//3.condition.matches(this.context, metadata)返回false//如果1、2或者1、3成立,则在此函数的上层将阻断bean注入Spring容器return true;// 4. 调用 Condition#matches 方法进行判断}}return false;}
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata))
/*** 检查给定的元数据,以查找给定的候选配置类是否被指定的注解标注** Check the given metadata for a configuration class candidate* (or nested component class declared within a configuration/component class).* @param metadata the metadata of the annotated class* @return {@code true} if the given class is to be registered for* configuration class processing; {@code false} otherwise*/public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {// Do not consider an interface or an annotation...// 不考虑接口或注解if (metadata.isInterface()) {return false;}// Any of the typical annotations found?// 检查是否被注解@Component、@ComponentScan、@Import、@ImportResource标注for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, let's look for @Bean methods...// 最后检查是否有@Bean标注的方法try {return metadata.hasAnnotatedMethods(Bean.class.getName());}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);}return false;}}