揭密springboot自动装配(5)--ioc及@Autowired注解

2024-06-04 19:18

本文主要是介绍揭密springboot自动装配(5)--ioc及@Autowired注解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

@Autowired 注解的bean什么时候实例化给它?


我们直接从AbstractAutowireCapableBeanFactory.doCreateBean开始,这个方法从上一章内容可得知是创建实例化对象然后放入三级缓存的singletonFactories里面,我们接着这个方法继续深究

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {populateBean(beanName, mbd, instanceWrapper);exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

这里可以看到bean实例化之后放入三级缓存接着就会进入populateBean方法进行判断该实例化对象是否有@Autowired注解,有的话会进行@Autowired的对应的bean的获取或创建,废话不多说,直接看代码:下面populateBean部分关键代码

AbstractAutowireCapableBeanFactory.populateBean方法我们看如图,遍历所有beanPostProcessors

这里的beanPostProcessors是在AbstractApplicationContext.refresh方法里registerBeanPostProcessors(beanFactory);放进去的,里面有对应的AutowiredAnnotationBeanPostProcessor,这个就是专门处理@Autowired注解的

接着调用PropertyValues pvsToUse = (AutowiredAnnotationBeanPostProcessor)ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

这个方法里面可看到findAutowiringMetadata进行查询所有注解信息,可以看到拿到了usera这个属性

private com.example.demo.service.UserA com.example.demo.service.UserB.usera

我们进入AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata

接着AutowiredAnnotationBeanPostProcessor.buildAutowiringMetadata

AutowiredAnnotationBeanPostProcessor.findAutowiredAnnotation

this.autowiredAnnotationTypes这里面放的就是在AbstractApplicationContext.refresh方法里registerBeanPostProcessors(beanFactory)构造AutowiredAnnotationBeanPostProcessor时放入的@Autowired

返回这里:

然后调用metadata.inject(bean, beanName, pvs)进行对应属性usera初始化,继续往里走

AutowiredAnnotationBeanPostProcessor.inject()

DefaultListableBeanFactory.resolveDependency()

DefaultListableBeanFactory.doResolveDependency(),该方法里面继续调用DependencyDescriptor.resolveCandidate

DependencyDescriptor.resolveCandidate到这个方法里面就会发现一个熟悉的东西AbstractBeanFactory.getBean(beanName)

这不就是上章提到的获取bean嘛

调用这里将会进行对象获取如果获取不到就接着userA实例化,这就是一个递归

顺带提一下上节提到的三级缓存解决依赖注解的问题,从这里我们就可以看到,bean实例化时候将进入三级缓存,然后接着一系列操作看实例化的bean是否里面有@Autowired这样的注解,有的话接着对应属性的bean实例化,没有的话就将三级缓存的bean 放入一级缓存中

我们创建往userA之后接着回到AutowiredAnnotationBeanPostProcessor.inject()方法,最后将创建好的bean放入对应field里面完成@Autowired注解的属性的实例化

 

这篇关于揭密springboot自动装配(5)--ioc及@Autowired注解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1030888

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏