Spring注解版执行流程 ConfigurationClassPostProcessor

Spring注解版执行流程 ConfigurationClassPostProcessor

上一篇文章我们对容器中存在的配置类进行了解析,解析完毕之后是对配置类进行校验工作。

parser.validate();
// 循环遍历所有的配置类,调用配置了的校验方法,problemReporter是
// ConfigurationClassPostProcessor后置处理器初始化中赋值的默认参数 new FailFastProblemReporter()
// 再创建ConfigurationClassParser对象时传入构造方法中的。
// 主要作用是抛出错误。
public void validate() {
	for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
		configClass.validate(this.problemReporter);
	}
}
public void validate(ProblemReporter problemReporter) {
	// 获取 @Configuration 注解的属性值,除非配置类声明为 proxyBeanMethods=false 不适用 CGLIB 代理模式,否则的话不可能为 final 类
	Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
	if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
		// 如果配置类是final类型,则抛出异常
		if (this.metadata.isFinal()) {
			problemReporter.error(new FinalConfigurationProblem());
		}
		// 校验配置类中@Bean定义的方法
		// 要求bean方法不能是static方法/final方法和重载方法
		for (BeanMethod beanMethod : this.beanMethods) {
			beanMethod.validate(problemReporter);
		}
	}
}

proxyBeanMethods 是为了让使用 @Bean 注解的方法被代理而实现 bean 的生命周期的行为。
设置为 true,那么直接调用方法获取 bean,不会创建新的 bean,而是会走 bean 的生命周期的行为。
设置为 false, 那么直接调用方法获取 bean,会创建新的 bean,且不会走 bean 的生命周期的行为。

验证完之后继续往后看。在此之前,注入的 BeanDefinition 都是 Configuration 配置类中定义的内部 bean,因为配置类依赖于这些内部的实例,所以后面这部分工作就是处理配置类 BD 加载工作.

// 获取所有的 bean,包括扫描的 bean 对象,@Import 导入的 bean 对象
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 清除掉已经解析处理过的配置类
configClasses.removeAll(alreadyParsed);
// 判断读取器是否为空,如果为空的话,就创建完全填充好的 ConfigurationClass 实例的读取器
if (this.reader == null) {
	this.reader = new ConfigurationClassBeanDefinitionReader(
			registry, this.sourceExtractor, this.resourceLoader, this.environment,
			this.importBeanNameGenerator, parser.getImportRegistry());
}
// 核心方法,将完全填充好的ConfigurationClass实例通过BeanDefinition注册入IOC容器
this.reader.loadBeanDefinitions(configClasses);
// 添加到已经处理的集合中
alreadyParsed.addAll(configClasses);
candidates.clear();

this.reader.loadBeanDefinitions(configClasses)中的处理逻辑。

private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
	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;
	}
	// 若 bean 通过 @Import(ImportSelector) 方式添加到容器中的,那么此时 configClass#isImported 返回的是 true
	// 1.configClass.importedBy 属性里面存储的是 ConfigurationClass 就是将 bean 导入的类
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	// 2.判断当前 bean 是否含有 @Bean 注解方法,如果有,需要把这些方法产生 bean 放入到 BeanDefinitionMap 当中
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}
	// 3.将 @ImportResource 引入的资源注入 IOC 容器
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 4.如果 bean 上存在 @Import 注解,且 import 是一个实现了 ImportBeanDefinitionRegistrar 接口,则执行 ImportBeanDefinitionRegistrar#registerBeanDefinitions 方法
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

1.registerBeanDefinitionForImportedConfigurationClass 方法

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
	AnnotationMetadata metadata = configClass.getMetadata();
	// 定义 bd 实例
	AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
	// 设置 scope 属性以及通过生成器生成 beanName、公共的属性值信息
	ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
	configBeanDef.setScope(scopeMetadata.getScopeName());
	String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
	AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
	configClass.setBeanName(configBeanName);
	if (logger.isTraceEnabled()) {
		logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
	}
}

处理被 @Import 导入的类,并且是没有加配置注解的【@Component、@Confuguration】否则会被先识别的配置类所替代,因为同样的配置类是只允许出现一个的
@Import 注解导入的类中如果不是 DeferredImportSelector 或 ImportBeanDefinitionRegistrar 这个类型的话,就会当作是一个普通的配置类进行 BeanDefinition 注入,importBy 属性值就是导入的类
2.loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	ConfigurationClass configClass = beanMethod.getConfigurationClass();
	// 获取方法元数据
	MethodMetadata metadata = beanMethod.getMetadata();
	// 获取方法名称
	String methodName = metadata.getMethodName();
	// 是否标记为当前 @Bean 需要被跳过
	if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
		configClass.skippedBeanMethods.add(methodName);
		return;
	}
	if (configClass.skippedBeanMethods.contains(methodName)) {
		return;
	}
	// 获取bean注解的属性
	AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
	Assert.state(bean != null, "No @Bean annotation attributes");
	// 获取别名
	List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
	String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
	for (String alias : names) {
		// 注册剩下的别名
		this.registry.registerAlias(beanName, alias);
	}
	// 是否存在同名 bean 定义,这实际上已经覆盖之前(例如通过XML)
	if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
		if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
			throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
					beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
					"' clashes with bean name for containing configuration class; please make those names unique!");
		}
		return;
	}
	// 封装为ConfigurationClassBeanDefinition,表示是来自配置类里的bean定义
	ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
	// 设置来源的类
	beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
	// 判断是否是静态的,设置 BeanClass
	if (metadata.isStatic()) {
		if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
			beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
		}
		else {
			beanDef.setBeanClassName(configClass.getMetadata().getClassName());
		}
		beanDef.setUniqueFactoryMethodName(methodName);
	}
	else {
		// instance @Bean method
		// 设置工厂名
		beanDef.setFactoryBeanName(configClass.getBeanName());
		beanDef.setUniqueFactoryMethodName(methodName);
	}
	// 如果方法元数据是标准方法元数据的话,就设置解析的工厂方法
	if (metadata instanceof StandardMethodMetadata) {
		beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
	}
	// 设置自定义装配模式,默认是构造器
	beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	// 设置略过属性检查
	beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
			SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
	// 处理通用注解,注解里可能还有自动装配注解
	AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
	// 获取自动装配枚举信息
	Autowire autowire = bean.getEnum("autowire");
	if (autowire.isAutowire()) {
		//如果是自动装配,也就是BY_NAME 或者 BY_TYPE,再设置了一次自动装配模式
		beanDef.setAutowireMode(autowire.value());
	}
	// 自动装配候选,默认是true
	boolean autowireCandidate = bean.getBoolean("autowireCandidate");
	if (!autowireCandidate) {
		beanDef.setAutowireCandidate(false);
	}
	// 初始化方法 @PostConstruct、@PreDestroy 或 XML 或 InitializingBean、DisposableBean 接口
	String initMethodName = bean.getString("initMethod");
	if (StringUtils.hasText(initMethodName)) {
		beanDef.setInitMethodName(initMethodName);
	}
	// 销毁方法
	String destroyMethodName = bean.getString("destroyMethod");
	beanDef.setDestroyMethodName(destroyMethodName);
	// 处理作用域
	ScopedProxyMode proxyMode = ScopedProxyMode.NO;
	AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
	if (attributes != null) {
		beanDef.setScope(attributes.getString("value"));
		proxyMode = attributes.getEnum("proxyMode");
		if (proxyMode == ScopedProxyMode.DEFAULT) {
			proxyMode = ScopedProxyMode.NO;
		}
	}
	// 如果必要的话就替换原来 bean 定义与目标信息
	BeanDefinition beanDefToRegister = beanDef;
	// 如果作用域不是no的话就要使用代理
	if (proxyMode != ScopedProxyMode.NO) {
		BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
				new BeanDefinitionHolder(beanDef, beanName), this.registry,
				proxyMode == ScopedProxyMode.TARGET_CLASS);
		beanDefToRegister = new ConfigurationClassBeanDefinition(
				(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
	}
	if (logger.isTraceEnabled()) {
		logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
				configClass.getMetadata().getClassName(), beanName));
	}
	this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

将 @Bean注解方法元数据取出来分析,分析有没有别名、有没有跟 xml 配置冲突,封装成一个configurationClassBeanDefinition,然后设置工厂方法名,获取 bean 注解的属性,设置初始化方法,销毁方法,是否自动装配,是否需要代理等,最后将 BD 信息加入到 BeanDefinitionMap、BeanDefinitionNames 集合中

3.loadBeanDefinitionsFromImportedResources 方法

private void loadBeanDefinitionsFromImportedResources(
		Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
	Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
	importedResources.forEach((resource, readerClass) -> {
		// 选择默认的读取器类型
		if (BeanDefinitionReader.class == readerClass) {
			if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
				// When clearly asking for Groovy, that's what they'll get...
				readerClass = GroovyBeanDefinitionReader.class;
			}
			else {
				// Primarily ".xml" files but for any other extension as well
				readerClass = XmlBeanDefinitionReader.class;
			}
		}
		BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
		if (reader == null) {
			try {
				// 初始化 reader 读取器实例
				reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
				// Delegate the current ResourceLoader to it if possible
				if (reader instanceof AbstractBeanDefinitionReader) {
					AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
					abdr.setResourceLoader(this.resourceLoader);
					abdr.setEnvironment(this.environment);
				}
				readerInstanceCache.put(readerClass, reader);
			}
			catch (Throwable ex) {
				throw new IllegalStateException(
						"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
			}
		}
		// 该方法是 XML 方式注入 Bean 核心的解析工作步骤
		reader.loadBeanDefinitions(resource);
	});
}

加载 ImportResources 中引入的 xml 文件,有两种加载类 GroovyBeanDefinitionReader、XmlBeanDefinitionReader,不指定默认采用的就是 XmlBeanDefinitionReader 读取器,然后用这个 reader 去加载 xml 资源。

最后,还有一步保证措施需要执行,主要是为了检测 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions 是否还有其他的配置类进行了引入

if (registry.getBeanDefinitionCount() > candidateNames.length) {
	String[] newCandidateNames = registry.getBeanDefinitionNames();
	Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
	Set<String> alreadyParsedClasses = new HashSet<>();
	for (ConfigurationClass configurationClass : alreadyParsed) {
		alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
	}
	// 如果有未解析的类,则将其添加到 candidates 中,这样 candidates 不为空,就会进入到下一次的 while 的循环中
	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;
}

1.判断 registry.getBeanDefinitionCount() > candidateNames.length 目的:为了知道 reader.loadBeanDefinitions(configClasses) 这一步有没有向 BeanDefinitionMap 中添加新的 BeanDefinition
2.实际上就是看配置类,例如:AppConfig 类「Spring ImportTests 测试内部静态类」会向 BeanDefinitionMap 中添加 bean,这里的 AppConfig 类向容器中添加的 bean,实际上在 parser#parse 方法 这一步已经全部被解析好了,只是待塞入到 bdNames/bdMaps 集合中
3.如果有,registry.getBeanDefinitionCount 就会大于 candidateNames.length,这样就需要再次遍历新加入的 BeanDefinition,并判断这些 bean 是否已经被解析过了,如果未解析,需要重新进行解析

循环结束以后。

    //往工厂对象里面添加ImportRegistry对象。以支持ImportAware @Configuration类
	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();
	}

至此,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法已经全部分析完成。
这两篇文章虽然里面的细节远不是这两篇文章可以将明白的,我只能说:“佩服!!!”。
还记得我们为什么要将这个方法嘛。是因为我们在refresh#invokeBeanFactoryPostProcessors方法中找实现了BeanDefinitionRegistryPostProcessor#PriorityOrdered的后置处理器,执行postProcessBeanDefinitionRegistry方法。
代码往后执行呢。你会发现后面就没有执行任何其他后置处理器方法了。后面执行ConfigurationClassPostProcessor#postProcessBeanFactory。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值