栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码学习(十二)--配置类解析(ConfigurationClassPostProcessor)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码学习(十二)--配置类解析(ConfigurationClassPostProcessor)

前言

上一篇文章分析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,直到全部处理完成过后,那么就退出循环, 配置类的解析工作就完成了。

ConfigurationClassParser源码解析

配置类解析器,这个是配置类的解析器,是spring内置的解析器类,我们看下上面的代码调用配置类的解析器中的parse方法进行解析的,所以我们看下这个类的parse方法如下:

parse方法
public void parse(Set 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);
}
processConfigurationClass方法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate 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);
}
doProcessConfigurationClass方法
@Nullable
protected final SourceClass doProcessConfigurationClass(
		ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
		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 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真正完成了对配置类的解析,一共做了下面几件事

  1. 解析配置类中的内部类,看内部类中是否有配置类,如果有进行递归处理
  2. 处理配置类上的@PropertySources跟@PropertySource注解
  3. 处理@ComponentScan,@ComponentScans注解
  4. 处理@import注解
  5. 处理@importResource注解
  6. 处理@Bean注解
  7. 处理接口中的default方法
  8. 返回父类,让外部的循环继续处理当前配置类的父类

我们逐一进行分析

@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 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 Set parse(AnnotationAttributes componentScan, final String declaringClass) {
	// 第一步就创建了一个ClassPathBeanDefinitionScanner对象
	// 在这里我们就知道了,Spring在进行扫描时没有使用在最开始的时候创建的那个对象进行扫描
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
	// 解析成bd时采用的beanName的生成规则
	Class 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 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,
		Collection importCandidates, 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集合中;

处理@importResource注解
AnnotationAttributes importResource =
      AnnotationConfigUtils.attributesFor(sourceClass.getmetadata(), importResource.class);
if (importResource != null) {
   String[] resources = importResource.getStringArray("locations");
   Class readerClass = importResource.getClass("reader");
   for (String resource : resources) {
      //占位符处理,占位符可以是@importResouce("${xxxx}")
      String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
      //将占位符处理过后,添加到集合中
      configClass.addimportedResource(resolvedResource, readerClass);
   }
}
处理@Bean注解

将配置类中所有的被@Bean标注的方法添加到configClass的BeanMethod集合中

处理接口中的default方法

代码也很简单,Java8中接口能定义default方法,这里就是处理接口中的default方法,看其是否有@Bean标注的方法

 

到此为止,我们分析完了整个解析的过程。可以发现Spring将所有解析到的配置信息都存储在了ConfigurationClass类中,但是到目前为止这些存储的信息都没有进行使用。那么Spring是在哪里使用的这些信息呢?回到我们的第三段代码,其中有一行代码如图所示:

loadBeanDefinitions方法
// configurationModel:被解析完成了配置类集合,其中保存了@Bean注解解析信息,@import注解解析信息等等
public void loadBeanDefinitions(Set configurationModel) {
    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博客

图灵学院--周瑜老师课程

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/602034.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号