上一篇文章分析Spring启动流程中有一个步骤是执行BeanFactoryPostProcessor,在refresh-->invokeBeanFactoryPostProcessors(beanFactory),该方法中会先执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,然后执行postProcessBeanFactory方法,其中ConfigurationClassPostProcessor是Spring内置的一个BeanDefinitionRegistryPostProcessor的实现类,在创建AnnotatedBeanDefinitionReader的过程中它对应的BeanDefinition就被注册到容器中了。接下来我们就来分析ConfigurationClassPostProcessor这个类的源码
ConfigurationClassPostProcessor源码分析它实现了BeanDefinitionRegistryPostProcessor,所以首先执行它的postProcessBeanDefinitionRegistry方法,其源码如下
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 这里生成一个注册IDregistryId,为了防止同一个注册器多次调用,SET集合本身具有去重功能,所以用SET存放
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);
}
processConfigBeanDefinitions
processConfigBeanDefinitions方法的代码很长,我们拆分一段段分析,先看第一段
第一段
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// ========第一段代码========
// 声明一个list,用来存放我们的配置类(什么配置类??),比如我们的配置类是AppConfig,
// 这个类我们是通过spring提供的方法register注册到DefaultListableBeanFactory的bdmap中的
// 所以这里的configCandidates主要为了先存放我们的配置类,因为配置类可以有多个,所以这里是一个集合
List configCandidates = new ArrayList<>();
// 这里是拿到容器中所有的BeanDefinition的名字,如果你只设置了一个配置类,你没有手动添加一些bean工厂的后置处理器的话,那么这里
// 拿到的就只有6个,有5个bd是spring的内置的bd,有一个bd是你的配置类,而这里我们主要就是拿到这个配置bd,然后进行处理
// ???
String[] candidateNames = registry.getBeanDefinitionNames();
// 循环处理这个bdmmap集合
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//这里判断我们的BeanDefinition中是否有一个configurationClass属性,configurationClass是配置类信息封装对象
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 检查是否是配置类,在这里会将对应的bd标记为FullConfigurationClass或者LiteConfigurationClass
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 是配置类的话,将这个bd添加到configCandidates中
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
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// ...
上面这段代码有这么几个问题:
1.当前容器中有哪些BeanDefinition
在上篇文章分析启动流程中,Spring在创建AnnotatedBeanDefinitionReader对象的时候Spring已经往容器中注册了5个内置的BeanDefinition,再加上我们自己注册的1个配置类,那么此时容器中应该存在6个BeanDefinition,我们可以打个断点验证
2.检查是否是配置类:checkConfigurationClassCandidate
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, metadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
// 下面这一段都是为了获取一个Annotationmetadata
// Annotationmetadata包含了对应class上的注解元信息以及class元信息
Annotationmetadata metadata;
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getmetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
// 已经解析过了,比如注册的配置类就属于这种,直接从bd中获取
metadata = ((AnnotatedBeanDefinition) beanDef).getmetadata();
}
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.
// 拿到字节码重新解析获取到一个Annotationmetadata
Class> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = Annotationmetadata.introspect(beanClass);
}
else {
try {
// class属性都没有,就根据className利用ASM字节码技术获取到这个Annotationmetadata
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;
}
}
Map config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 如果被@Configuration注解标注了,说明是一个FullConfigurationCandidate
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 如果被这些注解标注了,@Component,@ComponentScan,@import,@importResource
// 或者方法上有@Bean注解,那么就是一个LiteConfigurationCandidate
// 也就是说你想把这个类当配置类使用,但是没有添加@Configuration注解
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
// 解析@Order注解,用于排序
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
第二段
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 第一段
// .....
// ========第二段代码========
// Detect any custom bean name generation strategy supplied through the enclosing application context
// 我们的注册器BeanDefinitionRegistry肯定是SingletonBeanRegistry,看工厂类DefulatListableBeanFactory就知道
// 这里就是判断你应用是否实现了beanName的生成器,如果没有就使用默认的生成器
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
// beanName的生成策略
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
// 因为后置的扫描要处理@ProperResouce注解,所以如果这里之前没有设置environment,那么这里重新创建
// 其实在spring启动准备的时候就已经加了这个环境的bean了,所以这里肯定是不能为空,只是spring设计的严谨一点
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, this.componentScanBeanNameGenerator, registry);
// 第三段
第三段
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 第一段,第二段
// .....
// 这里重新申明了一个SET结合来存放我们上面得到的配置类,为什么要用一次set来存放?(set去重,set底层实现就是map的key,所以是可以去重的)
Set candidates = new linkedHashSet<>(configCandidates);
// 存放容器中已经被处理过的配置类集合
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 在第二段代码中创建了一个ConfigurationClassParser,这里就是使用这个parser来解析配置类
// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass
// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass
parser.parse(candidates);
// 校验在解析过程是中是否发生错误,同时会校验@Configuration注解的类中的@Bean方法能否被复写(被final修饰或者访问权限为private都不能被复写),如果不能被复写会抛出异常,因为cglib代理要通过复写父类的方法来完成代理
parser.validate();
Set configClasses = new linkedHashSet<>(parser.getConfigurationClasses());
// 移除已经解析过的配置类,防止重复加载了配置类中的bd
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getimportRegistry());
}
// 将通过解析@Bean,@import等注解得到相关信息解析成bd被注入到容器中
this.reader.loadBeanDefinitions(configClasses);
// 将已经处理过的配置类放入已处理的列表中
alreadyParsed.addAll(configClasses);
// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClass
// 将当前已经处理过的配置类集合清除(它是do while循环退出的依据)
candidates.clear();
// 如果大于,说明容器中新增了一些bd,那么需要重新判断新增的bd是否是配置类,如果是配置类,需要再次解析
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 从容器中重新拿出来的所有的Beand的名字集合
String[] newCandidateNames = registry.getBeanDefinitionNames();
// 上一次获取的BeanDefinition名字集合
Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set 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 classes
// 注册importRegistry到容器中
// 当通过@import注解导入一个全配置类A(被@Configuration注解修饰的类),A可以实现importAware接口
// 通过这个Aware可以感知到是哪个类导入的A
if (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();
}
}
1.从BeanFactory中(属性beanDefinitionNames)中拿到所有的beanName的名字;
2.循环这个beanNames,根据beanName去beanDefinitionMap获取BeanDefinition,然后判断这个BeanDefinition是否是一个配置类,配置类的检查条件是是实现了@Configutation、@Component、@ComponScan、@import、@importResource、@Bean的条件之一都满足,唯一有一个区别就是如果是加了@Configuration注解的配置类,那么会设置一个属性full表示是全注解的配置类,否则就是一个lite属性,表示部分注解的配置类,如果是全注解的配置类,那么这个配置类最后也是在单例池中生成一个对象,这个对也是一个代理对象,否则就是一个简单Bean对象;满足条件的BeanDefinition就会添加一个配置类的处理集合中candidates;
3.如果筛选出来的candidates集合不为空,那么就开始do while循环,然后循环中调用配置类解析方法parse去解析,解析主要处理了@Component、@ComponScan、@import、@importResource、@Bean这个几个注解:
a.判断是否加了@Componet注解,如果加了,处理@Component所在类的内部类,因为内部类可能有其他注解,然后这里是一个递归处理;
b.判断是否有@ProperResource注解,如果有,处理@ProperResource,将配置的资源文件解析出来放入到Environment中;
c.处理@ComponScan注解,执行真正的扫描工作,将符合条件的创建ConfigurationClass;
d.处理@import注解,@import注解有三种类型,普通类的导入,importSelector,importBeanDefinitionRegistrar;
e.处理@importResource注解,@importResouce注解一般导入的是spring的配置文件,配置的是;
f.处理每个配置类的@Bean方法。
配置类解析完成过后,然后do while循环中又重新重容器中拿到BeanDefinition中的数量,然后和之前获取的数量进行比较,最后找出新产生的,最新产生的如果也是满足配置类的检查条件,又加入到candidates中进行循环调用parse方法,直到将容器中的所有配置类都解析完成,就是将系统中所有符合条件的每个配置类都解析成BeanDefinition,直到全部处理完成过后,那么就退出循环, 配置类的解析工作就完成了。
配置类解析器,这个是配置类的解析器,是spring内置的解析器类,我们看下上面的代码调用配置类的解析器中的parse方法进行解析的,所以我们看下这个类的parse方法如下:
parse方法public void parse(SetprocessConfigurationClass方法configCandidates) { // 遍历所有的配置类,一个个完成解析 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { // 三个判断最终都会进入到同一个方法---->processConfigurationClass方法 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()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } // 对importSelector进行延迟处理 this.deferredimportSelectorHandler.process(); } protected final void parse(@Nullable String className, String beanName) throws IOException { Assert.notNull(className, "No bean class name for configuration class bean definition"); metadataReader reader = this.metadataReaderFactory.getmetadataReader(className); processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER); }
protected void processConfigurationClass(ConfigurationClass configClass, PredicatedoProcessConfigurationClass方法filter) throws IOException { // 条件注解,就是看有没有类上是否有@Conditional注解,如果有,则进行条件匹配 if (this.conditionevaluator.shouldSkip(configClass.getmetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } // 判断解析器是否已经解析过这个配置类了 ConfigurationClass existingClass = this.configurationClasses.get(configClass); // 不为null,说明已经解析过了 if (existingClass != null) { // 如果这个要被解析的配置类是被@import注解导入的 if (configClass.isimported()) { // 并且解析过的配置类也是被导入的 // OrderService导入了AccountService,UserService也导入了AccountService,就会符合这个条件 if (existingClass.isimported()) { // 那么这个配置类的导入类集合中新增当前的配置类的导入类 existingClass.mergeimportedBy(configClass); } // Otherwise ignore new imported config class; existing non-imported class overrides it. // 如果已经解析过的配置类不是被导入的,那么直接忽略新增的这个被导入的配置类。也就是说如果一个配置类同时被@import导入以及正常的 // 添加到容器中,那么正常添加到容器中的配置类会覆盖被导入的类 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); // 每个配置类扫描处理完成过后都加入到configurationClasses // ConfigurationClass重写了equals方法,只要两个ConfigurationClass对应的className相等就可以 this.configurationClasses.put(configClass, configClass); }
@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 // 处理内部类 // 在解析一个配置类时,如果类上有@Component,则会判断内部类是不是lite配置类并进行解析,并且会记录为被导入的 processMemberClasses(configClass, sourceClass, filter); } // Process any @PropertySource annotations // 处理@PropertySources跟@PropertySource注解,将对应的属性资源添加容器中(实际上添加到environment中) 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 // 处理@ComponentScan,@ComponentScans注解,真正进行扫描的地方就是这里 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 // 检查扫描出来的bd是否是配置类,如果是配置类递归进行解析 for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } // 判断扫描出来的bd是否是一个配置类,如果是的话继续递归处理 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @import annotations // 处理@import注解 // getimports(sourceClass)会拿到@import导入的类 // 如果导入的是普通类,那么会直接把它当做配置类来解析 // 如果导入的是普通importSelector,那么会将返回的类再次调用processimports() // 如果导入的是特殊importSelector,DeferredimportSelector,那么暂时不会处理,会在解析完所有当前这轮配置类后进行导入,将返回的类再次调用processimports() // 如果导入的是importBeanDefinitionRegistrar,那么暂时不会处理,会在解析完所有当前这轮配置类后,将配置类解析成为BeanDefinition之后进行调用 processimports(configClass, sourceClass, getimports(sourceClass), filter, true); // Process any @importResource annotations // 处理@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); } } // Process individual @Bean methods // 解析配置类中的@Bean,但并没有真正处理@Bean,只是暂时找出来 Set beanMethods = retrieveBeanMethodmetadata(sourceClass); for (Methodmetadata methodmetadata: beanMethods) { configClass.addBeanMethod(new BeanMethod(methodmetadata, configClass)); } // Process default methods on interfaces // 处理接口中的default方法 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; }
可以看到,在doProcessConfigurationClass真正完成了对配置类的解析,一共做了下面几件事
- 解析配置类中的内部类,看内部类中是否有配置类,如果有进行递归处理
- 处理配置类上的@PropertySources跟@PropertySource注解
- 处理@ComponentScan,@ComponentScans注解
- 处理@import注解
- 处理@importResource注解
- 处理@Bean注解
- 处理接口中的default方法
- 返回父类,让外部的循环继续处理当前配置类的父类
我们逐一进行分析
@Component内部类处理
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate filter) throws IOException {
Collection memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
//循环获取内部类,然后判断是否是一个配置类的候选者,如果是,加入candidates
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getmetadata()) &&
!memberClass.getmetadata().getClassName().equals(configClass.getmetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularimportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
//进行循环递归调用
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
@PropertySources配置文件加载
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
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 = this.resourceLoader.getResource(resolvedLocation);
//然后加入到环境变量中
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException 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;
}
}
}
}
@ComponScan处理
org.springframework.context.annotation.ComponentScanAnnotationParser#parse
public Setparse(AnnotationAttributes componentScan, final String declaringClass) { // 第一步就创建了一个ClassPathBeanDefinitionScanner对象 // 在这里我们就知道了,Spring在进行扫描时没有使用在最开始的时候创建的那个对象进行扫描 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); // 解析成bd时采用的beanName的生成规则 Class extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); // 配置这个扫描规则下的ScopedProxyMode的默认值 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 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) { @Override protected boolean matchClassName(String className) { return declaringClass.equals(className); } }); // 在完成对扫描器的配置后,直接调用其doScan方法进行扫描 return scanner.doScan(StringUtils.toStringArray(basePackages)); }
第一步就创建了一个ClassPathBeanDefinitionScanner,紧接着通过解析注解,对这个扫描器进行了各种配置,然后调用doScan方法完成了扫描,扫描的源码在bean的生命周期的文章中分析过了。
处理@import注解private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass, CollectionimportCandidates, Predicate exclusionFilter, boolean checkForCircularimports) { // 没有要导入的类,直接返回 if (importCandidates.isEmpty()) { return; } // checkForCircularimports:Spring中写死的为true,需要检查循环导入 // isChainedimportOnStack方法:检查导入栈中是否存在了这个configClass,如果存在了说明 // 出现了A import B,B import A的情况,直接抛出异常 if (checkForCircularimports && isChainedimportonStack(configClass)) { this.problemReporter.error(new CircularimportProblem(configClass, this.importStack)); } else { // 没有出现循环导入,先将当前的这个配置类加入到导入栈中 this.importStack.push(configClass); try { // 遍历所有要导入的类 for (SourceClass candidate : importCandidates) { // 如果要导入的类实现了importSelector if (candidate.isAssignable(importSelector.class)) { // Candidate class is an importSelector -> delegate to it to determine imports Class> candidateClass = candidate.loadClass(); // 反射创建这个importSelector importSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, importSelector.class, this.environment, this.resourceLoader, this.registry); Predicate selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } // 如果import的是DeferredimportSelector,表示推迟导入 // 如果是一个DeferredimportSelector,添加到deferredimportSelectors集合中去 // 在所有的配置类完成解析后再去处理deferredimportSelectors集合中的importSelector if (selector instanceof DeferredimportSelector) { this.deferredimportSelectorHandler.handle(configClass, (DeferredimportSelector) selector); } else { // 不是一个DeferredimportSelector,那么通过这个importSelector获取到要导入的类名 String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata()); Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 递归处理要导入的类 processimports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } // 如果import的类实现了importBeanDefinitionRegistrar接口 else if (candidate.isAssignable(importBeanDefinitionRegistrar.class)) { // Candidate class is an importBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class> candidateClass = candidate.loadClass(); // 先通过反射创建这个importBeanDefinitionRegistrar importBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, importBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); // 最后将其添加到configClass的importBeanDefinitionRegistrars集合中 // 之后会统一调用其importBeanDefinitionRegistrar的registerBeanDefinitions方法,将对应的bd注册到容器中 configClass.addimportBeanDefinitionRegistrar(registrar, currentSourceClass.getmetadata()); } else { // Candidate class not an importSelector or importBeanDefinitionRegistrar -> // process it as an @Configuration class // 既不是一个importSelector也不是一个importBeanDefinitionRegistrar,直接导入一个普通类 // 并将这个类作为配置类进行递归处理 // 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedBy 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(); } }
这里是@import的三种类型,分别是import的普通类,importSelector,importBeanDefinitionRegistrar
1.如果导入的是普通类,那么会递归去调用processConfigurationClass,将普通类注册成一个ConfigClass,它有一个属性为importBy,这个importby就表示是谁将它导入的
2.如果是importSelector,那么会调用它的selectimports返回一个列表,这个列表也是要被导入的类列表,类可能是普通类,可能是importSelector,也有可能是importBeanDefinitionRegistrar,
如果是普通类,进入普通类的逻辑,如果还是importSelector,又递归,如果是importBeanDefinitionRegistrar,添加到ConfigClass中属性importBeanDefinitionRegistrars集合中
3.如果是importBeanDefinitionRegistrar,就直接添加到ConfigClass中属性importBeanDefinitionRegistrars集合中;
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) {
//占位符处理,占位符可以是@importResouce("${xxxx}")
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
//将占位符处理过后,添加到集合中
configClass.addimportedResource(resolvedResource, readerClass);
}
}
处理@Bean注解
处理接口中的default方法将配置类中所有的被@Bean标注的方法添加到configClass的BeanMethod集合中
代码也很简单,Java8中接口能定义default方法,这里就是处理接口中的default方法,看其是否有@Bean标注的方法
到此为止,我们分析完了整个解析的过程。可以发现Spring将所有解析到的配置信息都存储在了ConfigurationClass类中,但是到目前为止这些存储的信息都没有进行使用。那么Spring是在哪里使用的这些信息呢?回到我们的第三段代码,其中有一行代码如图所示:
loadBeanDefinitions方法// configurationModel:被解析完成了配置类集合,其中保存了@Bean注解解析信息,@import注解解析信息等等 public void loadBeanDefinitions(SetconfigurationModel) { TrackedConditionevaluator trackedConditionevaluator = new TrackedConditionevaluator(); for (ConfigurationClass configClass : configurationModel) { // 调用这个方法完成的加载 loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionevaluator); } }
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionevaluator trackedConditionevaluator) {
// 判断是否需要跳过,例如A导入了B,A不满足加载的条件需要被跳过,那么B也应该被跳过
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()) {
// 将被导入的类生成BeanDefinition并注册到Spring容器中
// @Component的内部类,@import所导入的类都是被导入的类
registerBeanDefinitionForimportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 解析@Bean标注的Method得到对应的BeanDefinition并注册到容器中
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 解析导入的配置文件,并将从中得到的bd注册到容器中
loadBeanDefinitionsFromimportedResources(configClass.getimportedResources());
// 执行configClass中的所有importBeanDefinitionRegistrar的registerBeanDefinitions方法
loadBeanDefinitionsFromRegistrars(configClass.getimportBeanDefinitionRegistrars());
}
参考文章:
你知道Spring是怎么解析配置类的吗?_做一个认真的程序员-CSDN博客_spring解析配置类
Spring 配置类解析过程详解_JAVA技术爱好者-CSDN博客
图灵学院--周瑜老师课程



