解析Spring中@Bean的实现原理

介绍

在SpringBoot的项目中,经常会使用@Bean这样的注解,这个是定义在方法上的注解,也可以用来替代以前通过XML注入Bean的方式,但又与@Configuration或者@Component这样正常的注入方式不太一样,本文将会分析具体的实现原理。

如何扫描到@Bean注解的

1. refresh入口

我们知道refresh是Spring容器启动的主流程方法,就从这开始看起。

@Override
public void refresh() throws BeansException, IllegalStateException {
	//。。。省略部分代码
	//这个方法会处理bean中的各种注解,其中包含了@Bean的解析
	invokeBeanFactoryPostProcessors(beanFactory);
	//。。。省略部分代码
			
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}
public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	//。。。省略部分代码
	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
	//。。。省略部分代码
}

2. postProcessBeanDefinitionRegistry

这里利用BeanFactoryPostProcessor扩展处理

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
	
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessBeanDefinitionRegistry(registry);
	}
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	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);
}

3. 核心解析流程

大概分析这部分处理流程

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	//先获取容器中所有的BeanDefinition对象,这部分对象会更早的被容器加载到,利用ConfigurationClassPostProcessor这个类完成的,我在之前的博文中有介绍过
	String[] candidateNames = registry.getBeanDefinitionNames();
	
	//遍历所有beanName
	for (String beanName : candidateNames) {
		//通过beanName,获取BeanDefinition对象
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		//这个判断会找当前BeanDefinition的方法中是否有@Bean的注解,如果有就返回true
		/**
		// Finally, let's look for @Bean methods...
		try {
				return metadata.hasAnnotatedMethods(Bean.class.getName());
			}
			catch (Throwable ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
				}
				return false;
		}
		*/
		
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			//封装成BeanDefinitionHolder对象,并添加到list集合中
			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
	//有@Order注解的完成排序
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});

	// Detect any custom bean name generation strategy supplied through the enclosing application context
	SingletonBeanRegistry sbr = null;
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);

	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		//核心解析,看后面的分析
		parser.parse(candidates);
		parser.validate();
		
		//从刚刚解析的过程中获取ConfigurationClass集合,这个类里面又包含了BeanMethod对象集合,而这个对象封装了@Bean的方法
		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		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对象到BeanDefinitions中,看后面分析。
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);

		candidates.clear();
		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());
			}
			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
	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();
	}
}

parser.parse(candidates)执行几步后,最终会把有@Bean注解的封装成BeanMethod对象,并添加到ConfigurationClass类中的一个set集合属性中。


public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			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);
		}
	}
	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, Predicate<String> filter) throws IOException {
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}
	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				existingClass.mergeImportedBy(configClass);
			}
			// Otherwise ignore new imported config class; existing non-imported class overrides it.
			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);
	this.configurationClasses.put(configClass, configClass);
}

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {
	//。。。省略部分代码
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		//主要看这边,把有@Bean注解的封装成BeanMethod对象,并添加到ConfigurationClass类中的一个set集合属性中
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}
	//。。。省略部分代码

}

loadBeanDefinitions

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
	TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
	for (ConfigurationClass configClass : configurationModel) {
		loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
	}
}

loadBeanDefinitionsForConfigurationClass

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);
	}
	//遍历ConfigurationClass中的beanMethods集合。
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}

	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	ConfigurationClass configClass = beanMethod.getConfigurationClass();
	MethodMetadata metadata = beanMethod.getMetadata();
	//。。。省略部分代码
	ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
	//。。。省略部分代码
	// instance @Bean method
	//设置BeanDefinition中的factoryBeanName属性值为当前class对象的beanName
	beanDef.setFactoryBeanName(configClass.getBeanName());
	//设置BeanDefinition中的factoryMethodName属性值为当前class对象中@Bean方法的methodName
	beanDef.setUniqueFactoryMethodName(methodName);
	//。。。省略部分代码
	BeanDefinition beanDefToRegister = beanDef;
	//。。。省略部分代码
	//把封装后的BeanDefinition注册到beanDefinitionMap和beanDefinitionNames容器中,spring实例化过程会遍历这个容器中的bean
	//beanDefinitionMap中key是@Bean的方法名,value是@Bean所属对象的BeanDefinition
	//beanDefinitionNames是list集合,存放的是@Bean的方法名
	this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

4. 流程梳理

分析到这对有@Bean注解的方法,Spring的处理策略就大致了解了。

  1. 先找到有@Configuration或者@Component注解的bean对象。
  2. 检查bean对象中是否有@Bean注解的方法,如果存在封装成BeanMethod对象,并添加到一个set集合中。
  3. 遍历集合,然后拿到bean对象对应的BeanDefinition,设置factoryMethodName属性为@Bean方法的先关信息,这就相当于在当前bean对应的BeanDefinition对象中添加了一个标识,用于识别是否有@Bean的方法。
  4. 最后把以@Bean注解的方法名为key,BeanDefinition为value,添加到beanDefinitionMap容器中,把@Bean注解的方法名添加到beanDefinitionNames容器中,一个map集合,一个list集合。

如何注入@Bean实例的

1. 处理factoryMethodName属性

@Override
public void preInstantiateSingletons() throws BeansException {
	//。。。省略部分代码
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	//遍历beanDefinitionNames集合,包含了之前添加进去的@Bean注释的方法名
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				//获取bean对象
				getBean(beanName);
			}
		}
	}
	//。。。省略部分代码
}
@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

getBean会执行到doGetBean方法

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

			//。。。省略部分代码
			//根据beanName获取BeanDefinition对象,之前解析过可以从一个名为beanDefinitionMap的map容器中获取,value就是bean对应的BeanDefinition对象。
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			
			//。。。省略部分代码
			// Create bean instance.
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						//创建bean对象,beanName为方法名,mbd为bean对应的BeanDefinition对象
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			//。。。省略部分代码
}

2. 实例化

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	//。。。省略部分代码
	//判断当前BeanDefinition是否有factoryMethodName属性,之前分析过有@Bean注解的会设置这个属性
	if (mbd.getFactoryMethodName() != null) {
		//利用反射调用@Bean注释的方法
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}
	//。。。省略部分代码
}
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
		@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
		//。。。省略部分代码
		try {
			//factoryMethod即@Bean注释的方法,利用反射完成调用并返回方法中的对象
			Object result = factoryMethod.invoke(factoryBean, args);
			if (result == null) {
				result = new NullBean();
			}
			return result;
		}
		//。。。省略部分代码
}

参考方法调用时序图

AbstractApplicationContext PostProcessorRegistrationDelegate ConfigurationClassPostProcessor ConfigurationClassParser ConfigurationClassBeanDefinitionReader 1. refresh() 2. invokeBeanFactoryPostProcessors() 3. invokeBeanFactoryPostProcessors() 4. invokeBeanDefinitionRegistryPostProcessors() 5. postProcessBeanDefinitionRegistry() 6. processConfigBeanDefinitions() 7. parse() 8. processConfigurationClass() 9. doProcessConfigurationClass() 10. loadBeanDefinitions() 11. loadBeanDefinitionsForConfigurationClass() 12. loadBeanDefinitionsForBeanMethod() AbstractApplicationContext PostProcessorRegistrationDelegate ConfigurationClassPostProcessor ConfigurationClassParser ConfigurationClassBeanDefinitionReader

总结

后半部分也比较简单,先遍历beanDefinitionNames这个list集合,依次处理,再通过beanDefinitionMap找到bean对应的BeanDefinition对象,最后在实例化对象的时候,判断当前BeanDefinition对象中factoryMethodName属性是否有值,如果有则通过反射调用@Bean注释的方法拿到bean的实例,这就实现将@Bean注解的方法注入到容器中了,name为方法名,value为方法返回值。

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值