【栖梧-源码-spring】@Bean从解析到注册到beanDefinitionMap

【栖梧-源码-spring】@Bean从解析到注册到beanDefinitionMap

  • 序幕
    • 源码阅读技巧
    • 本文说明
    • 类 ConfigurationClassParser#doProcessConfigurationClass
    • 方法retrieveBeanMethodMetadata
    • 类 BeanMethod
    • 类ConfigurationClassBeanDefinitionReader
    • 方法loadBeanDefinitionsForBeanMethod
    • 类DefaultListableBeanFactory
    • 总结

序幕

本文是我的第一篇博客,自我研读spring源码以来,收获颇丰。自工作以来,疑惑颇多,于是通过网络、同事、领导、技术网友等益友的分享和指导,解决了工作中许多疑难杂症,所以我也非常希望把我工作中、学习中的收获分享给所有需要的人。同时受水平所限,其中必有缺漏不足之处,还望指出。

"道友"解释->志同道合者;

源码阅读技巧

书山有路勤为径,学海无涯需持久!
源码阅读是一件枯燥乏味的事情,这种说法是对没有时间、没有兴趣、没有好奇心的道友来讲的。要想深入理解一个框架的原理,必须了解其实现细节,所以花费大量的时间、精力来吸取里面的营养是必须的。

<源码-spring>系列文章均涉及大量源码,且自建简单的项目是基于springboot 2的版本,如果其他版本的源码可能稍有差异,属正常情况。
如果道友你从来没有看过spring源码,阅读起来将会吃力,请悉知!

本文说明

本文核心讲解的是@Bean注解从解析bean到beanFactory的beanDefiniton中

类 ConfigurationClassParser#doProcessConfigurationClass

package org.springframework.context.annotation;

当spring启动后,走到高级AbstractApplicationContext这个高级容器的最核心的 refresh() 方法后,再进入invokeBeanFactoryPostProcessors(beanFactory)调用后置处理器方法,就会调用静态方法PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()) 开始解析所有的BeanDefinition了,由于本文主要讲解@Bean,所以其他的暂时不详解。

	//此类就是解析配置类的入口
	@Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
		//先判断是否有@Component注解,
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		    //首先递归处理任何成员(嵌套)类
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}
		//处理带有@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");
			}
		}

		// 处理 @ComponentScan 注解,注意里面是多个递归解析(如果不清楚是递归的道友进入这个方法可能会晕掉的),这
		//里面就会解析所有的@Component注解的,包括@Controller、@Service等这些被@Component注解过的注解,解析后的
		//bean全部放到ConfigurationClassParser这个对象的 configurationClasses 这个map里面进行后续处理
		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
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		//处理@Import的注解
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		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);
			}
		}

		// 关键来了,本文重点就是分析 @Bean的解析过程,。先获取被@Bean了的方法,下面会讲解此方法
		Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
		    //然后把@Bean注解的方法放入到 ConfigurationClass 这个对象里面的 beanMethods这个/Set 里面
		    //到此,解析@Bean的bean第一步-先把@Bean找出来,就在这完成了,下面会简单说一下装@Bean的类BeanMethod
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		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;
	}

方法retrieveBeanMethodMetadata

此方法是获取当前类所有的@Bean注解的方法

	//此方法是检索所有@Bean方法的元数据
	private Set retrieveBeanMethodMetadata(SourceClass sourceClass) {
		//获取元数据信息
		AnnotationMetadata original = sourceClass.getMetadata();
		//获取所有的@Bean方法
		Set beanMethods = original.getAnnotatedMethods(Bean.class.getName());
		if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
			//尝试通过ASM读取类文件以确定性声明顺序... 不幸的是,JVM的标准反射以任意//顺序返回方法,甚至在同一JVM上
			//同一应用程序的不同运行之间。
			try {
				AnnotationMetadata asm =
						this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
				Set asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
				if (asmMethods.size() >= beanMethods.size()) {
					Set selectedMethods = new LinkedHashSet<>(asmMethods.size());
					for (MethodMetadata asmMethod : asmMethods) {
						for (MethodMetadata beanMethod : beanMethods) {
							if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
								selectedMethods.add(beanMethod);
								break;
							}
						}
					}
					if (selectedMethods.size() == beanMethods.size()) {
						// All reflection-detected methods found in ASM method set -> proceed
						beanMethods = selectedMethods;
					}
				}
			}
			catch (IOException ex) {
				logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
				// No worries, let's continue with the reflection metadata we started with...
			}
		}
		return beanMethods;
	}

以上操作就会把所有的@Bean方法找出来

类 BeanMethod

package org.springframework.context.annotation;

上面的源码中,看见new BeanMethod(),这个BeanMethod继承了ConfigurationMethod类,ConfigurationMethod它有两个字段MethodMetadata和ConfigurationClass这两个对象,而BeanMethod集成后没有单独的字段,仅仅覆写了validate此方法和有一个私有的非静态的内部类,


final class BeanMethod extends ConfigurationMethod {

	public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
		super(metadata, configurationClass);
	}

	@Override
	public void validate(ProblemReporter problemReporter) {
		if (getMetadata().isStatic()) {
			// static @Bean methods have no constraints to validate -> return immediately
			return;
		}

		if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
			if (!getMetadata().isOverridable()) {
				// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
				problemReporter.error(new NonOverridableMethodError());
			}
		}
	}

	//这个BeanMethod.NonOverridableMethodError内部类的作用仅仅是处理@Bean方法 “ must not be private or final ”
	private class NonOverridableMethodError extends Problem {

		public NonOverridableMethodError() {
			super(String.format("@Bean method '%s' must not be private or final; change the method's modifiers to continue",
					getMetadata().getMethodName()), getResourceLocation());
		}
	}
}

上面将bean解析成ConfigurationClass后,接下来就需要把ConfigurationClass里面的beanMethods注册成为ConfigurationClassBeanDefinition

类ConfigurationClassBeanDefinitionReader

package org.springframework.context.annotation;


	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;
		}

		//如果是
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		//此方法就是把@Bean注册到beanFactory的入口
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
		
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		//这里面处理实现了ImportBeanDefinitionRegistrar的类,此时会调用ImportBeanDefinitionRegistrar的registerBeanDefinitions方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

方法loadBeanDefinitionsForBeanMethod

	private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
		//获取@Bean方法的类的信息
		ConfigurationClass configClass = beanMethod.getConfigurationClass();
		//获取@Bean的元数据信息
		MethodMetadata metadata = beanMethod.getMetadata();
		//获取方法名,也就是默认的bean的名称
		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 names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
		String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

		// 将别名注册到beanFactory
		for (String alias : names) {
			this.registry.registerAlias(beanName, alias);
		}

		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它是ConfigurationClassBeanDefinitionReader的内部的私有的静态类
		//ConfigurationClassBeanDefinition它继承了RootBeanDefinition,RootBeanDefinition的层级关系这里就不罗列了哈
		//为什么要用ConfigurationClassBeanDefinition把bean信息包装一层?  因为beanFactory的beanDefinitionMap必须是BeanDefinition的子类
		//实现了它才是标准的BeanDefinition,spring实例化bean只能实例化BeanDefinition
		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
		beanDef.setResource(configClass.getResource());
		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

		//静态的@Bean和非静态的处理方式有一点点区别
		if (metadata.isStatic()) {
			// 静态 @Bean 方法,这里设置的是setBeanClassName
			beanDef.setBeanClassName(configClass.getMetadata().getClassName());
			beanDef.setFactoryMethodName(methodName);
		}
		else {
			// 实例 @Bean 方法setFactoryBeanName
			beanDef.setFactoryBeanName(configClass.getBeanName());
			beanDef.setUniqueFactoryMethodName(methodName);
		}
		//下面都是设置@Bean注解里面属性
		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()) {
			beanDef.setAutowireMode(autowire.value());
		}

		boolean autowireCandidate = bean.getBoolean("autowireCandidate");
		if (!autowireCandidate) {
			beanDef.setAutowireCandidate(false);
		}

		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定义替换为目标bean定义
		BeanDefinition beanDefToRegister = beanDef;
		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);
		}

		if (logger.isTraceEnabled()) {
			logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
					configClass.getMetadata().getClassName(), beanName));
		}
		//这里调用了真正的、幕后的BeanFactory->DefaultListableBeanFactory的registerBeanDefinition方法,下面继续看源码
		this.registry.registerBeanDefinition(beanName, beanDefToRegister);
	}

类DefaultListableBeanFactory

package org.springframework.beans.factory.support;

躲在层层包装之后的beanFactory就是它了,spring的beanFactory的核心类之一,DefaultListableBeanFactory

	//这个方法是BeanDefinitionRegistry接口的实现
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		//老规矩,先验证合法性
		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		//如果beanDefinitionMap已经存在了,就验证是否两个对象相同然后打印一下废话日志等等,反正最后要把它给覆盖了,哈哈哈
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			//管你已经占着茅坑在拉屎,现在我是老大一脚把你踢开让我来,哈哈哈哈
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			//检查此工厂的bean创建阶段是否已经开始,即是否在此期间将任何bean标记为已创建,说白了就是
			//目前为止 IOC 容器已经有病了(有bean),哈哈哈
			//这里为什么要整一个判断 IOC 容器是否已经启动了呢????
			//情况成员变量: private volatile List beanDefinitionNames = new ArrayList<>(256);
			//明白了没?    size = 256 !!!   如果容器已经启动了,那么有可能 beanDefinitionNames已经满了,装不下了,数组越界,所以
			//需要新建一个数组,容量加一个,然后重新引用。。。。
			if (hasBeanCreationStarted()) {
				// 无法再修改启动时集合元素(用于稳定迭代),这里就最终的开始将@Bean的bean注册到beanDefinitionMap了
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					//上面说的list容量加一,就是这里哈
					List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				//仍在启动注册阶段,意思就是目前为止 IOC 没病(bean),容器还是空的
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDe	finition(beanName);
		}
	}

至此,@Bean的bean从配置类里面已经成功从一个小妹妹变成了一个大菇凉了。

总结

spring在启动时,在调用后置处理器PostProcessor的时候,将会把所有的bean包括@Bean的bean注册到beanFactory的beanDefiniton里面去,先将@Bean解析到父ConfigurationClass里面去,然后再一个一个的加载ConfigurationClass里面的bean定义。最后再告诉道友一个小秘密哦,这里面的所有操作都在 ConfigurationClassPostProcessor 这个 PostProcessor里面的invokeBeanDefinitionRegistryPostProcessors静态方法里面完成的,哈哈哈哈

你可能感兴趣的:(源码解读-Spring,spring源码,@Bean注解原理,@Bean)