@Bean注解从方法到一个bean的过程

  • 说明
  • 前言
  • AbstractApplicationContext的refresh()方法
  • PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors静态方法
  • ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
  • ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
  • ConfigurationClassParser的parse方法
  • ConfigurationClassParser的processConfigurationClass方法
  • ConfigurationClassParser的doProcessConfigurationClass方法
  • ComponentScanAnnotationParser类的parse方法
  • 总结



)

说明

本人第二次写博客,受技术水平所限,必有不足之处,请多多包涵且指出问题所在,鄙人不胜感激。(第一次也是写的这个,但是因为的博客账号url名字不好看,强迫症,url那个名字改不了,然后就把之前哪个博客账号给注销啦,重新申请的博客账号。。。)

本文所使用的spring版本是 5.0.6-release,其他版本的源码可能略有差异。
此博文为源码分析,所有代码均为源码,如果你没有研究过spring的源码,看起来会比较费劲。

前言

Spring创建bean 的方式有很多种,包括@Component、@Bean、xml配置等,当然也可以自己实现BeanDefinitionRegistry向注册表中注册 BeanDefinition 实例,完成注册的过程。

今天我要跟大家分享的就是我们最常用之一的@Bean注解让spring来管理我们的bean。

好了,废话不多说,直接进入主题。

当然还是AbstractApplicationContext的方法啦

AbstractApplicationContext的refresh()方法

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
	......
	......
		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// 这里就是注册bean的入口
			invokeBeanFactoryPostProcessors(beanFactory);

			//这个是注册所有BeanPostProcessors的地方,不是本次的讲解范畴
			registerBeanPostProcessors(beanFactory);

			......
			......
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors静态方法

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	
	//这个PostProcessorRegistrationDelegate的静态方法里面实例化
	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()));
	}
}

然后对每个BeanDefinitionRegistryPostProcessor进行处理,由于这个方法比较长,我只留本次要讲的内容

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	Set<String> processedBeans = new HashSet<>();
	//这里会把BeanDefinitionRegistryPostProcessor和它的父类BeanFactoryPostProcessor分开
	//因为BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法会先注册BeanFactoryPostProcessor
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
		//这里调用postProcessBeanDefinitionRegistry注册BeanDefinitionRegistry
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}
		//凡是currentRegistryProcessors这里这里面的BeanDefinitionRegistryPostProcessor都会立即实例化并且马上使用
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// 这里从beanDefinitionNames找出所有的BeanDefinitionRegistryPostProcessor,其中这里面就包括初始化	
		//@Component、@Bean等的ConfigurationClassPostProcessor
		//说明一下,@Configuration也属于 @Component
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			//这里如果实现了PriorityOrdered且优先级高的,会先实例化BeanDefinitionRegistryPostProcessor
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		//此方法会调用多次,当然这里是第一次调用这个方法,这里面会注册所有的spring的bean。额外说明下mybatis、mq等等其他的暂时不在这里注册哈,它们不属于spring,但是也是交给spring管理的
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();


		.......
		......
}

ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法

/**
 * Derive further bean definitions from the configuration classes in the registry.
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	//判断当前BeanDefinitionRegistry是否已经注册了,如果是已经注册了说明是重复注册,就抛异常
	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);
}

ConfigurationClassPostProcessor的processConfigBeanDefinitions方法

```java

```java
/**
 * Build and validate a configuration model based on the registry of
 * {@link Configuration} classes.
 */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		//判断是否是 “"full”<全>配置类 、“lite”<半>配置类,个人乱翻译的哈
		//@Configuration是“全”配置类,@Component、@ComponentScan等等是”半“配置类
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
				ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			//这儿很重要,比如SpringBoot的启动类@SpringBootApplication类就是在这里开始解析里面的配置的
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

	// Return immediately if no @Configuration classes were found
	if (configCandidates.isEmpty()) {
		return;
	}

	// 排序
	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(CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

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

	// 创建解析 @Configuration 的类
	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();

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

ConfigurationClassParser的parse方法

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	this.deferredImportSelectors = new LinkedList<>();

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

	processDeferredImportSelectors();
}

ConfigurationClassParser的processConfigurationClass方法

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
	//判断是否需要跳过此解析,例如 -如果有@Conditional注解,就会在这里判断是否需要暂时跳过下面的解析
	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);
	do {
		//这里就开始解析bean的方法,请看下面的方法解析
		sourceClass = doProcessConfigurationClass(configClass, sourceClass);
	}
	while (sourceClass != null);
	//只要配置好了的类,都会添加到这个map里面
	this.configurationClasses.put(configClass, configClass);
}

ConfigurationClassParser的doProcessConfigurationClass方法

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

	// Recursively process any member (nested) classes first
	processMemberClasses(configClass, sourceClass);

	// 处理@PropertySource注解
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			processPropertySource(propertySource);
		}
		else {
			logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
					"]. Reason: Environment must implement ConfigurableEnvironment");
		}
	}

	//处理@ComponentScans注解,这里多说两句,为什么这里会有@ComponentScan??我的@SpringBootApplication没有配置这个注解啊?
	//因为@SpringBootApplication这个注解被@ComponentScan注解了,那为什么我没有配置scanBasePackages,而spring会自动扫描@SpringBootApplication类当前目录和子目录的bean?
	//因为默认扫描@SpringBootApplication类当前目录和子目录的bean,默认值!
	Set<AnnotationAttributes> 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
			//开始扫描@ComponentScan里面的包了哦,返回的结果就是bean的包装,这个holder里面有beandefinition
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			// Check the set of scanned definitions for any further config classes and parse recursively if needed
			//然后递归解析每个BeanDefinition,如果BeanDefinition里面有配置再递归解析
			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());
				}
			}
		}
	}

	// Process any @Import annotations
	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<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
		for (String resource : resources) {
			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
			configClass.addImportedResource(resolvedResource, readerClass);
		}
	}

	// 本文核心就是这里,这里就会找出所有的bean里面的@Bean的方法,所以,如果我们随便写一个类的,在里面写个方法,方法什么加个注解@Bean,spring是不会知道的啦
	//前提有三个,第一这个类必须spring可以扫描到,第二这个类必须是由spring来管理,比如@Component,第三,这个类没有额外被屏蔽,可以实例化
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	//到此,@Bean方法就已经从一颗种子开始发芽了,就等最后真正实例化啦!
	for (MethodMetadata methodMetadata : beanMethods) {
		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;
}

ComponentScanAnnotationParser类的parse方法

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	//获取扫描类,此类就是真正扫描bean的类
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));
	//这里设置代理的类型
	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<String> 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));
	}
	//如果没有单独配置扫描的包,默认就是ClassUtils.getPackageName(declaringClass)
	if (basePackages.isEmpty()) {
		basePackages.add(ClassUtils.getPackageName(declaringClass));
	}

	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
		@Override
		protected boolean matchClassName(String className) {
			return declaringClass.equals(className);
		}
	});
	//这里开始扫描刚刚配置的包下面所有的bean
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}

ClassPathBeanDefinitionScanner的doScan方法

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	for (String basePackage : basePackages) {
		//这里会把所有的bean扫描出来,mybatis的mapper也是在这里扫描的,只是判断是否是bean的类和spring的判断类不一样
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				//把bean注册到BeanFactory里面去,不能再往下写了,跑题了。。。。
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

总结

spring解析@Bean注解,首先还是必须是spring自己的bean(为什么?因为比如mybatis的bean,你在里面写个@Bean是不得行的,哈哈哈),并且可以被spring扫描到,然后在解析spring自己的bean的时候,解析里面是否带有@Bean注解,当然同时也会解析其他的比如@Import、@ComponentScan等等这些注解。而且解析的时候入口就是springboot的启动类,从启动类开始解析,把这些解析成单独的bean定义后,再递归解析每个bean定义,总之是一个复杂的过程,也是spring启动过程中很重要的一步,这里面很多地方可以自定义,自己实现可扩展性很强,所以也是其他框架比如mybatis、mq等等很容易就集成的一个重要原因。