processPropertySource
// 如果配置类上加了 @PropertySource 注解,那么就解析加载 properties 文件,并将属性添加到 spring 上下文中 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"); } }
默认创建的环境对象实例是 StandardEnvironment
,它实现了 ConfigurableEnvironment 接口,处理使用 @PropertySource 注解修饰的类
private void processPropertySource(AnnotationAttributes propertySource) throws IOException { // 获取name属性 String name = propertySource.getString("name"); if (!StringUtils.hasLength(name)) { name = null; } // 获取encoding属性 String encoding = propertySource.getString("encoding"); if (!StringUtils.hasLength(encoding)) { encoding = null; } // 获取value属性 String[] locations = propertySource.getStringArray("value"); Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required"); boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound"); Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory"); PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ? DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass)); for (String location : locations) { try { // 处理属性值的占位符 String resolvedLocation = this.environment.resolveRequiredPlaceholders(location); // 讲指定位置的资源转换成 resource 对象 Resource resource = this.resourceLoader.getResource(resolvedLocation); // 添加 resource 对象为属性资源 addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding))); } catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) { // Placeholders not resolvable or resource not found when trying to open it if (ignoreResourceNotFound) { if (logger.isInfoEnabled()) { logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage()); } } else { throw ex; } } } }
获取 name、value、encoding 属性,将 value 属性转换为 String[] locations;
对 locations 数组进行遍历,先进行占位符解析工作,如:classpath:myconfig${name}.properties
再转换为 Resource 源对象,最后将其添加至 propertySources
集合中【创建标准化环境对象(StandardEnvironment)时有用到】
处理 @ComponentScan、@ComponentScans 注解
// 处理 @ComponentScan 或 @ComponentScans 注解,并将扫描包下的所有 bean 转换成填充后的 ConfigurationClass 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) { // 比如 basePackages = com.vnjohn, 那么在这一步会扫描出这个包及子包下的 class,然后将其解析成 BeanDefinition(BeanDefinition 可以理解为等价于 BeanDefinitionHolder) Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // 通过上一步扫描包 com.vnjohn,有可能扫描出来的 bean 中可能也添加了 ComponentScan 或 ComponentScans 注解. // 所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有 ComponentScan、ComponentScans for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } // 判断是否是一个配置类,并设置 full 或 lite 属性 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { // 通过递归方法进行解析 parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } }
通过注解工具类解析当前配置类中是否包含了 @ComponentScan、@ComponentScans 注解,存在就进行遍历挨个调用 ComponentScanAnnotationParser#parse
方法进行包的扫描工作
扫描工作完成后,将满足条件的 BeanDefinitions 进行再次解析,对 BD 集合进行遍历,判别集合中的元素是否依然是配置类,是的话就继续往回走,调用 ConfigurationClassParser#parse 方法
方法
对 ComponentScanAnnotationParser#parse
扫描包的解析方法前置工作进行详细分析,如下:
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { // 创建对应的扫描类 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); // 获取 @ComponentScan 参数,并进行参数的设置工作 Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); // 获取 scopedProxy 属性 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)); } // 获取 resourcePattern 属性 scanner.setResourcePattern(componentScan.getString("resourcePattern")); // 获取 includeFilters 属性 for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } // 获取 excludeFilters 属性 for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); } } // 获取 lazyInit 属性 boolean lazyInit = componentScan.getBoolean("lazyInit"); if (lazyInit) { scanner.getBeanDefinitionDefaults().setLazyInit(true); } Set<String> basePackages = new LinkedHashSet<>(); // 获取 basePackages 属性 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); } // 获取 basePackageClasses 属性,对全限定类进行包名截取 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); } }); // 开始执行扫描,最终的扫描器是 ClassPathBeanDefinitionScanner return scanner.doScan(StringUtils.toStringArray(basePackages)); }
- 创建实际进行扫描工作的类:ClassPathBeanDefinitionScanner,填充该类型所需用到的一些属性「scopedProxyMode、resourcePattern、includeFilters、excludeFilters、basePackages」
- 调用 ClassPathBeanDefinitionScanner#parse 方法,扫描出 basePackages 属性包及子包下的 class,然后将其解析成 BeanDefinition 信息
对ClassPathBeanDefinitionScanner#parse
实际扫描工作的方法进行详细解析,开始执行扫描工作,如下:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); // 遍历basePackages for (String basePackage : basePackages) { // 扫描 basePackage,将符合要求 bean 定义全部找出来 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); // 遍历所有候选的 bean 定义 for (BeanDefinition candidate : candidates) { // 解析 @Scope 注解,包括 scopeName 和 proxyMode ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 使用 beanName 生成器来生成 beanName String 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,@Description AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 检查 beanName 是否已经注册过,如果注册过,检查是否兼容 if (checkCandidate(beanName, candidate)) { // 将当前遍历的 bean 定义、beanName 封装成 BeanDefinitionHolder BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); // 根据 proxyMode 值,选择是否创建作用域代理 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); // 注册 beanDefinition registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
- 先调用
findCandidateComponents(backPackage)
将符合条件的 BeanDefinition(实际是 ScannedGenericBeanDefinition) 找出来
条件1:excludeFilters 不包含
条件2:includeFilters 至少匹配一个
条件3:该类不能是接口或抽象类
findCandidateComponents->scanCandidateComponents->isCandidateComponent
- 处理 BeanDefinition 对象的属性信息,解析 @Scope 注解,设置 scopeName、proxyMode,通过 beanNameGenerator 生成 beanName
- 设置自动装配属性,例如:该 bean 是否可以自动装配到其他 bean 中
- AnnotationConfigUtils#processCommonDefinitionAnnotations:处理定义在目标类上的通用注解,包括「@Lazy、@Primary、@DependsOn、@Role、@Description」填充对应的属性进去
- checkCandidate(beanName, candidate):检查 beanName 是否已经被注册过,如果被注册过考虑其是否与当前类兼容,不兼容就抛出异常,兼容则跳过当前 BeanDefinition 操作;如果未注册过,进行如下操作:
把当前遍历的 bean 定义信息和 beanName 封装成 BeanDefinitionHolder
调用
AnnotationConfigUtils.applyScopedProxyMode
,根据 proxyMode 值来选择是否要创建代理,接口基于 JDK 动态代理,类基于 CGLIB 动态代理主动 beanDefinition,放入到 BeanDefinitionMap、BeanDefinitionNames 中
第一点描述的符合条件方法 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; }
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); /** * isIndependent:确定底层类是否是独立的,即它是否是顶级类或者嵌套类,他可以独立于封闭类构造 * isConcrete:判断底层类是否表示具体类,即:既不是接口也不是抽象类 * isAbstract && hasAnnotatedMethods:是否被标记为抽象类 && 确定基础类是否具有使用给定注解 @Lookup 标注的方法 */ return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); }
至此,扫描工作完成以后就到了 ComponentScanAnnotationParser#parse
方法处理的最后一步了,拿到所扫描到的 Set<BeanDefinitionHolder>
集合,遍历每一个 BeanDefinitionHolder ,判断是否是一个配置类,并设置 full 或 lite 属性,再次往回走调用 (parse—>processConfigurationClass) 方法进行后续解析工作
processImports
处理 @Import 注解,导入额外的配置类,同时完成具体类的实例化工作,该类型处理也涉及到自动装配的工作
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
getImports—>collectImports:递归获取被 @Import 注解标注的类,被它标注的类无须加 @Component、@Configuration 等配置注解,否则该 Bean 会被添加两次,但 Spring 会进行合并的工作
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { // 如果使用 @Import 注解修饰的类集合为空,那么直接返回 if (importCandidates.isEmpty()) { return; } // 通过一个栈结构解决循环引入,栈中存在该配置类则抛出异常 if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { // 添加到栈中,用于处理循环引入的问题 this.importStack.push(configClass); try { // 遍历每一个 @Import 注解的类 for (SourceClass candidate : importCandidates) { // 检验配置类 Import 引入的类是否是 ImportSelector 子类: if (candidate.isAssignable(ImportSelector.class)) { // 候选类是一个导入选择器->委托来确定是否进行导入 Class<?> candidateClass = candidate.loadClass(); // 通过反射生成一个 ImportSelect 对象 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); // 获取选择器的额外过滤器 Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } // 判断引用选择器是否是 DeferredImportSelector 接口的实例 // 如果是则应用选择器将会在所有的配置类都加载完毕后加载 if (selector instanceof DeferredImportSelector) { // 将选择器添加到 deferredImportSelectorHandler 实例中,预留到所有的配置类加载完成后统一处理自动化配置类 this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // 获取引入的类,然后使用递归方式将这些类中同样添加了 @Import 注解引用的类 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 递归处理,被 Import 进来的类也有可能 @Import 注解 processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } // 如果是实现了 ImportBeanDefinitionRegistrar 接口的 bd:SpringBoot 中的 AutoConfigurationPackages$Registrar else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // 候选类是ImportBeanDefinitionRegistrar -> 委托给当前注册器注册其他bean Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); // 放到当前 configClass 的 importBeanDefinitionRegistrars 中 // 在 ConfigurationClassPostProcessor 处理 configClass 时会随之一起处理 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // 候选类既不是 ImportSelector 也不是 ImportBeanDefinitionRegistrar-->将其作为 @Configuration 配置类处理 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); // 如果 Import 类型是普通类,则将其当作带有 @Configuration 类一样处理 // 把 candidate 构造为 ConfigurationClass,标注为 importedBy,意味着它是通过被@Import 进来的 // 后面处理会用到这个判断将这个普通类注册进 DefaultListableBeanFactory 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(); } } }
- 判断被 @Import 注解标注的类集合是否为空,不为空才进行后续的处理工作,循环遍历每一个配置类,判断它所匹配的类型
- 如果是 ImportSelector 接口的子类但非 DeferredImportSelector 接口的子类,就对其配置类进行递归处理,因为当前类可能还有使用 @Import 注解导入其他的配置类,递归调用的是 processImports 方法
- 如果是 ImportSelector & DeferredImportSelector 接口的子类,将其先暂时添加到 deferredImportSelectorHandler 集合中,待所有的配置类都加载完成以后:也就是当所有的类都调用 parse 方法结束后,再统一处理这些类型的配置类.
回忆一下,在 ConfigurationClassParser#parse 方法中会作这步操作 > this.deferredImportSelectorHandler.process(); - 如果是 ImportBeanDefinitionRegistrar 接口子类,会将其进行实例化后存入集合中,待所有配置类处理完后,调用其类下的
registerBeanDefinitions
设置具体的 BeanDefinition 类型,如 SpringBoot 中设置的就是专门由 Spring 内部使用的 BD - 如果以上都不是的话,则将其当作带有 @Configuration 类一样处理,将 candidate 构造为 ConfigurationClass,标注为 importedBy,意味着它是通过被 @Import 进来的
处理 @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); } }
处理 @ImportResource 注解,导入 spring 配置文件,通过此方式引入的 xml 文件来通过 IOC 容器注入 Bean 实例对象
处理 @Bean 注解
检索配置类中加了 @Bean 注解的方法,将 @Bean 方法转化为 BeanMethod 对象,保存再集合中
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); }
processInterfaces
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // 找到配置类的所有接口,遍历接口 for (SourceClass ifc : sourceClass.getInterfaces()) { // 找到含有 @Bean 注解的默认方法 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc); for (MethodMetadata methodMetadata : beanMethods) { if (!methodMetadata.isAbstract()) { // A default method or other concrete method on a Java 8+ interface... // 添加到集合中 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } // 递归处理,因为接口可能存在父接口 processInterfaces(configClass, ifc); } }
处理接口的默认方法实现,从 JDK8 开始,接口中的方法可以有自己的默认实现,若这个接口的方法加了 @Bean 注解,也需要被解析;然后检索配置类中加了 @Bean 注解的方法,将 @Bean 方法转化为 BeanMethod 对象,保存再集合中