Spring中的Bean的扫描、实例化、初始化

本文详细介绍了Spring启动后Bean的扫描、实例化和初始化过程。从Bean的扫描,包括通过注解类进行配置、构造函数的选择,到Bean的实例化,涉及InstantiationAwareBeanPostProcessor等多个后置处理器的作用,再到Bean的初始化,涵盖@PostConstruct注解方法和InitializingBean接口的afterPropertiesSet方法的执行。整个流程详细剖析了Spring管理Bean的生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring中Bean的实例化的过程
在Spring启动之后,个人暂时将Spring注入Bean对象的过程分为3个大的步骤,分别是:
Bean的扫描→Bean的实例化→Bean的初始化。

第一步:Bean的扫描

在Spring启动的时候,AnnotationConfigApplicationContext的几种构造参数可以选择使用XML、配置类、包路径来进行扫描

//配置类扫描
 ApplicationContext ac=new AnnotationConfigApplicationContext(AppConfig.class);
//配置文件XML扫描
 ApplicationContext ac1 =new ClassPathXmlApplicationContext("Spring-rl.xml");
//直接包路径扫描
 ApplicationContext ac2 =new AnnotationConfigApplicationContext("com.test");

本文下面以注解类为启动流程
AppConfig.Class 配置类:

package com.asop.app;


import org.springframework.context.annotation.ComponentScan;

/**
 * @description:
 * @author:19047590
 * @date: Created in 2020-05-23 16:56
 */
@ComponentScan("com.asop")
public class AppConfig {

}

启动类:

public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(AppConfig.class);
}
}

AnnotationConfigApplicationContext 在启动的时候的构造函数

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		this();
		//在初始化的时候,直接将appConfig放入到bdMap中。否则就是不能执行了
		//这个方式就用来完成Spring中的初始化需要的一些基本的bd
		register(componentClasses);
		//Bean的注入
		refresh();
	}
		/**
	 * Create a new AnnotationConfigApplicationContext that needs to be populated
	 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
	 */
	public AnnotationConfigApplicationContext() {
		//reader 对于外部的beanDefinition进行读取的
		//父类的构造方法 创建一个读取注解的Bean定义读取器
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//可以用来扫描包或者类 然后转化成bd
		//实际上扫描包工作的时候不是scanner这个对象完成的
		//是Spring自己new一个ClassPathBeanDefinitionScanner
		//这里的scanner仅仅是为了能够在外部调用AnnotationConfig
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

因为AnnotationConfigApplicationContext继承了GenericApplicationContext。所以在执行AnnotationConfigApplicationContext的构造函数的时候时候首先执行了GenericApplicationContext的构造函数,创建了beanFactory

	public GenericApplicationContext() {
	//创建了beanFactory 
		this.beanFactory = new DefaultListableBeanFactory();
	}

在创建完成BeanFactory之后,执行AnnotationConfigApplicationContext的构造函数,创建了AnnotatedBeanDefinitionReader读取注解的Bean定义读取器。
ClassPathBeanDefinitionScanner(为了能够在外部调用AnnotationConfig)。
以上执行完成了AnnotationConfigApplicationContext的无参构造函数。
接着执行有参构造中的方法:register()方法

register方法主要是将AppConfig.Class类解析为AnnotatedGenericBeanDefinition类后注入到BeanFactory当中去。

注册到BeanFactory的核心的代码
//AnnotatedGenericBeanDefinition abd 继承了GenericBeanDefinition 用来处理注解类,注册为BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
abd.setInstanceSupplier(supplier);
abd.setScope(scopeMetadata.getScopeName());
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//将自定义注解类注册进去。
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

BeanFactory中加入了AppConfig类
refresh() 方法,进行Bean对象的扫描和注入。

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
			//子类的refreshBeanFactory()方法启动
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//为BeanFactory配置容器特性,例如类加载器、事件处理器等
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//为容器的某些子类指定特殊的BeanPost事件处理器
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//调用所有注册的BeanFactoryPostProcessor的Bean
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				//为BeanFactory注册BeanPost事件处理器.
				//BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//初始化信息源,和国际化相关.
				initMessageSource();

				// Initialize event multicaster for this context.
				//初始化容器事件传播器.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//调用子类的某些特殊Bean初始化方法
				onRefresh();

				// Check for listener beans and register them.
				//为事件传播器注册事件监听器.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//初始化所有剩余的单例Bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				//初始化容器的生命周期事件处理器,并发布容器的生命周期事件
				finishRefresh();
			}

invokeBeanFactoryPostProcessors 扫描出AppConfig中的指定的路径下的所有需要注册的Bean,并存放在BeanDefinitionMap中。
首先处理BeanDefinitionRegistryPostProcessor,处理完成之后处理开始扫描其它的类。 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);该方法中的scanCandidateComponents会根据AppConfig中的包路径来对编译好的Class文件进行扫描
scanCandidateComponents(String basePackage).

String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//将该路径下的类转化为Spring自定义的Resource类。
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

扫描出com.asop下的所有的class文件并转为Resource类
接下来会for循环来判断该类是否是需要注册的对象

for (Resource resource : resources) {
  if (resource.isReadable()) {
	MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
	if (isCandidateComponent(metadataReader)) {
		//当前类是否有@Component注解或者是用户扩展的自定义注解
	ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
	sbd.setSource(resource);
	if (isCandidateComponent(sbd)) {
		//是否满足其他条件
    if (debugEnabled) {
	logger.debug("Identified candidate component class: " + resource);
	}
	candidates.add(sbd);
	}		
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {
			//AppConfig中的ComponentScan是否配置了需要排除的包
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		for (TypeFilter tf : this.includeFilters) {
			//注解扩展 默认有@Component  然后可以有用户自定义的扩展的注解
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

如果符合条件,会添加到LinkedHashSet集合candidates中。
然后将扫描出来的类转化为BeanDefinitionHolder类型的Set集合并返回

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);
					//将扫描完成的beanDefinitions注入到BeanDefiintionMap中
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;

往下执行后会执行扩展的BeanFactoryPostProcessor

	private static void invokeBeanFactoryPostProcessors(
			Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
//这里就可以执行用户自己扩展的BeanFactoryPostProcessor
		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanFactory(beanFactory);
		}
	}

以上步骤就是Spring启动之后扫描Bean的主要的流程

bean的实例化及初始的过程

bean的实例化、初始化过程主要是针对于@Scope类型是单例模式(singleton)的bean。
主要是经过了8次后置处理器的方法后完成了实例化、初始化。其中前6次后置处理器是完成实例化的,后两次是完成初始化的功能。
1、InstantiationAwareBeanPostProcessor bp.postProcessBeforeInstantiation
主要调用的实现方法AbstractAutoProxyCreator.postProcessBeforeInstantiation
主要是判断当前类是否需要aop的代理。如果需要的话,并且当前的bean不为空的话,生成对应的代理对象,但是这里一定为空.因为还没有实例化Bean对象。所以只是做了advisedBeans缓存
postProcessBeforeInstantiation ->之后会调用doCreateBean来创建bean对象。
2、determineConstructorsFromBeanPostProcessors 里面调用了第二次后置处理器
SmartInstantiationAwareBeanPostProcessor bp.determineCandidateConstructors
来决定返回哪些方法 选择使用哪个构造器,这个后置处理器处理的主要是使用了@Autowired注解的(该构造方法的入参必须是Spring在Ioc容器中可以找到所有的对象,如果有一个找不到的话 就会报错)
当没有使用@autoWired注解选择对应的构造函数的时候,Spring这个时候会判断当前对象的自动注入模型。如果是1 no的话,那么就是默认使用无参构造,
如果是3的话,就是byType。那么会使用贪婪模式,选择最长的构造函数(同上,需要满足该构造函数的对象都在Spring容器中。)
3、applyMergedBeanDefinitionPostProcessors 方法第三次调用Bean的后置处理器. 这个后置处理器 涉及到了BeanDefinition对象的合并和使用 合并主要是指在SpringXML文件中有配置的Bean使用了
MergedBeanDefinitionPostProcessor processor.postProcessMergedBeanDefinition
这个后置处理器主要是找到当前的Bean需要注入的属性 主要有@AutoWired注解和@Resource注解注入的属性。 injectionMetadataCache在后面是相同处理的。
@Resource在Spring中是根据CommonAnnotationBeanPostProcessor找到的
@AutoWired在Spring中是根据AutowiredAnnotationBeanPostProcessor找到的
4、第四次调用后置处理器 循环依赖 提前暴露一个对象Bean工厂 然后可以处理Bean的Aop的内容
SmartInstantiationAwareBeanPostProcessor bp.getEarlyBeanReference
根据第一步判断当前类是否需要aop代理,然后需要的话,根据类是否强制优化 是否是单独的类或者是实现了接口的类 来判断是使用JDK动态代理或者是CGLIB动态代理来生成代理对象
在完成了动态代理之后,在Spring容器中存放的就不是和普通类相同的Bean,而是代理对象。
5、第五次调用后置处理器InstantiationAwareBeanPostProcessor bp.postProcessAfterInstantiation
判断当前实现了InstantiationAwareBeanPostProcessor的接口是否都是需要要注入属性的 是的话返回true 不是的话 返回false 只要有一个不是的话 直接返回false 该对象就不注入属性
可以自己实现该接口 然后来阻止该对象进行注入。
6、InstantiationAwareBeanPostProcessor bp.postProcessProperties用来处理@Autowired注解和@Resource注解的属性。
完成扫描后和上面autowiring自动注入找到的属性值一起填充。注入的方式使用的是Java反射方法中的Filed.set方法
7、第七次调用后置处理器BeanPostProcessor postProcessBeforeInitialization方法 这个时候已经实例化结束
开始了初始化的工作 初始化前置方法 完成@PostConstruct注解方法 在执行完成之后 invokeInitMethods方法会执行实现了InitializingBean接口的afterPropertiesSet方法 所以两个方法有先后顺序
8、BeanPostProcessor postProcessAfterInitialization 初始化后置方法Spring主要用来执行aop方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值