spring 创建bean的过程

spring 创建bean的过程

生成BeanDefinition – > 合并BeanDefinition --> 创建单例Bean对象(非懒加载) --> 依赖注入(属性赋值) --> 初始化前(@PostConstruct)–>初始化(InitializingBean)–>初始化后(AOP)–>bean

AbstractAutowireCapableBeanFactory.doCreateBean(创建bean) --> instanceWrapper.getWrappedInstance(实例化bean) --> populateBean(填充属性)–>initializeBean(初始化)–>applyBeanPostProcessorsAfterInitialization(AOP)

生成BeanDefinition

spring启动时会进行扫描,会先调用
org.Springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComonents(String basePackage) 扫描某个包路径,并得到BeanDefinition的Set集合.

  1. 首先,通过ResourcePatternResolver获得指定包路径下的所有.class文件(封装成Resource对象)
  2. 遍历每个Resource对象
  3. 利用MetadataReaderFactory解析Resourece对象,得到MetadataReader
  4. 利用MetadataReader的具体实现类进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选
  5. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition
  6. 在基于metadataReader判断对应的是否是接口或者抽象类
  7. 如果筛选通过则表示扫描到一个bean,将ScannedGenericBeanDefinition加入结果集
  8. Definition对象的加载采用ASM技术,并没有加载到jvm
  9. MetadataReader表示类的元数据读取器,主要包含了一个AnnotationMetadata,可以获取
    类名
    父类名
    所以实现接口名
    所有内部类名
    判断是不是抽象类
    判断是不是接口
    判断是不是注解
    获取拥有某个注解的方法集合
    获取类上所有注解信息
    获取类上添加的所有注解类型集合

在创建bean时,会创建BeanDefiniton对象,该对象会存储bean的一些注解信息,bean信息等。

模拟创建BeanDefinition:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
beanDefinition.setScope("prototype");
//注册bean
context.registerBeanDefinition("userService",beanDefinition);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
reader.register(UserService.class);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.example");

合并BeanDefinition

spring支持创建父子bean,则子bean对应的BeanDefinition需要合并父Bean的BeanDefinition的信息。

创建单例Bean对象

  • 这一步就会进行实例化bean,如果.class文件还没有加载,会在实例化前进行加载。
  • 在类加载完后,可以实现InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(),该方法会在加载完所有类,但是在bean实例化前被调用
  • postProcessBeforeInstantiation可以有返回值,如果返回某个对象,则spring不会对该对象进行实例化和依赖注入,会直接进入初始化后。
@Component
public class UserBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {if ("userService".equals(beanName)) {System.out.println("实例化前");return new UserService();}return null;
}
}

调用构造方法
推断构造方法:

  • bean实例化默认调用无参构造方法
  • bean实例化时如果有一个非无参构造方法则调用该方法
  • bean实例化时如果有多个构造方法则调用无参方法
  • bean实例化时如果有多个构造方法且没有无参方法,抛出异常
  • bean实例化时有参构造方法的入参必须是对象,spring容器中如果没有对应bean,抛出异常。
  • bean实例化时有参构造会,spring容器进行参数注入时会先根据类型查找过滤,然后再根据bean的名称过滤。 所以:
    1.如果存在多个该类型的bean,一个同名的bean则注入该bean;
    2.如果存在一个该类型的bean,bean名称和入参不同,注入该bean;
    3.如果存在多个该类型的bean,bean名称和入参都不相同,抛出异常。

依赖注入(属性赋值)

例如@Autowired,初始化前会通过遍历object.class.getFields(),判断field.isAnnotationPresent(Autowired.class),拿到对应的field进行依赖注入。

初始化前

@PostConstruct:初始化前会通过遍历object.class.getMethods(),判断method.isAnnotationPresent(PostConstruct.class),然后method.invoke()

所以我们可以在bean中的方法上加上@PostConstruct方法,使该方法可以在bean初始化前被调用。

初始化

InitalizingBean:初始化时会判断bean instance of InitalizingBean(是否实现InitalizingBean接口),并且 调用其afterPropertiesSet()。

所以可以在Bean上实现InitializingBean接口,并实现afterPropertiesSet方法,使其在bean初始化时被调用。

BeanPostProcessor:BeanPostProcessor有初始化前和初始化后的方法,同样可以自己实现

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {String value() default "";
}
@Component
public class UserService {@TestAnnotation("test")private String test;}
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if(bean instanceof UserService){for (Field field : bean.getClass().getFields()) {if(field.isAnnotationPresent(TestAnnotation.class)){try {field.set(bean,field.getAnnotation(TestAnnotation.class));} catch (IllegalAccessException e) {e.printStackTrace();}}}}return bean;}
}

初始化后

  • 如果进行AOP会产生一个代理对象,代理对象会成为spring的AOP
  • 该代理对象不会有依赖注入的bean
  • 该代理对象会继承被代理的对象,并且代理对象会先调用AOP逻辑
  • 该代理对象会放入被代理对象,在AOP逻辑完成后,使用被代理对象调用方法(被代理对象拥有依赖注入)。
  • AOP中 joinPoint.getTarget()可以获取被代理对象
  • 遍历所有的切面bean,遍历切面bean中方法,找到被代理对象的方法时则表示该被代理对象经行了AOP,则将其缓存到map,被代理对象触发AOP时使用
  • spring事务也会生成代理对象:1.判断是否有注解@Transactional;2.创建一个数据库连接(事务管理器dataSource创建);3.conn.autocommit = false(修改属性,关闭自动提交事务);4.执行被代理对象方法;5.提交事务或者回滚。
  • 当在上一点的第四点中,被代理对象中调用另一个带有@Trasactional的方法时会导致事务失效,因为当前对象不是代理对象。解决方法可在当前被代理对象中自己注入自己获得代理对象,用代理对象调用另一个事务方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835646.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode/NowCoder-链表经典算法OJ练习1

目录 说在前面 题目一&#xff1a;移除链表元素 题目二&#xff1a;反转链表 题目三&#xff1a;合并两个有序链表 题目四&#xff1a;链表的中间节点 SUMUP结尾 说在前面 dear朋友们大家好&#xff01;&#x1f496;&#x1f496;&#x1f496;数据结构的学习离不开刷题…

接口测试的流程

1.拿到接口api文档(通过抓包工具获取)&#xff0c;熟悉接口业务&#xff0c;接口地址&#xff0c;鉴权方式&#xff0c;入参码。 2.编写接口用例以及评审, 思路: 正例:输入正常入参&#xff0c;接口能够成功返回数据 反例: 鉴权反例: 鉴权码…

机器人系统仿真

0、何为仿真 通过计算机对实体机器人系统进行模拟的技术。 1、为何仿真 低成本&#xff1a; 机器人实体一般价格昂贵&#xff0c;为降低机器人学习、调试的成本&#xff1b;高效&#xff1a; 搭建的环境更为多样且灵活&#xff0c;可以提高测试效率以及测试覆盖率&#xff1b…

三大消息传递机制区别与联系

目录 总结放开头 1、定义区别&#xff1a; EventBus Broadcast Receiver Notification 2、使用区别: EventBus Broadcast Receiver Notification 3、补充通知渠道&#xff1a; 通知渠道重要程度 总结放开头 BroadCast Receiver:属于安卓全局监听机制&#xff0c;接收…

【算法】最短路问题 bfs 到 dijkstra

1976、到达目的地的方案数 你在一个城市里&#xff0c;城市由 n 个路口组成&#xff0c;路口编号为 0 到 n - 1 &#xff0c;某些路口之间有 双向 道路。输入保证你可以从任意路口出发到达其他任意路口&#xff0c;且任意两个路口之间最多有一条路。 给你一个整数 n 和二维整…

五一 大项目--docker-compose编排lnmp完成wordpress

Docker 中的 Nginx 服务为什么要启用 HTTPS 一安装容器 1 安装docker-20.10.17 2 安装所需的依赖 sudo yum install -y yum-utils device-mapper-persistent-data lvm23 添加Docker官方仓库 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos…

Linux-线程概念

1. 线程概念 线程&#xff1a;轻量级进程&#xff0c;在进程内部执行&#xff0c;是OS调度的基本单位&#xff1b;进程内部线程共用同一个地址空间&#xff0c;同一个页表&#xff0c;以及内存中的代码和数据&#xff0c;这些资源对于线程来说都是共享的资源 进程&#xff1a;…

RabbitMQ (windows) 安装

大家好我是苏麟 , 今天安装一下 RabbitMQ . 官网 : RabbitMQ: One broker to queue them all | RabbitMQ 1.点击 Getting Started 2. 点击 Docs 3.点击 Install And Upgrade 4.点击 installation via Chocolatory 5. 直接下载安装包 RabbitMQ 下好了先放在一遍 RabbitMQ 需要 E…

思科基础命令(对标华为的HCIA知识)

设备的基本模式&#xff08;四种&#xff09; Router> ⽤户模式 可以对设备进⾏简单的查看 Router>enable Router# 特权模式 可以进⾏所有的查看以及简单的配置 r1#configure terminal r1(config)# 全局配置模式&#xff0c;可以对设备进⾏所有的操作 r1(config)#line co…

pytorch版本的bert模型代码(MLM)

魔改bert就必须要知道Bert的结构&#xff1a; 主要解答与BertForMaskedLM&#xff08;MLM&#xff09;有关的类&#xff1a; 下面是MLM的分类头&#xff1a; class BertLMPredictionHead(nn.Module):def __init__(self, config, bert_model_embedding_weights):super(BertLM…

【C++】-------反向迭代器的模拟实现(补充)

目录 前言 一、反向迭代器接口&#xff08;用户层&#xff09; 二、模拟实现 三、以vector模拟实现为例 四、总结 前言 在vector和list的接口中我们实际上有说明过反向迭代器的用法&#xff0c;这里就有个问题&#xff0c;并不是只有这两个容器存在反向迭代器的。那么对于他…

点云DBSCAN聚类,同时获取最多点数量的类,同时删除其他的类并显示

代码的主要目的是处理一个点云文件(从某个巷道或类似环境中获取的),并尝试识别并可视化其中的主要结构(比如墙壁),同时去除可能的噪声和异常点。它首先读取一个点云文件,进行降采样和异常点移除,然后使用DBSCAN聚类算法对剩余的点云进行聚类,最后选择并可视化包含最多…

力扣爆刷第133天之动态规划收尾(距离编辑与回文子串)

力扣爆刷第133天之动态规划收尾&#xff08;距离编辑与回文子串&#xff09; 文章目录 力扣爆刷第133天之动态规划收尾&#xff08;距离编辑与回文子串&#xff09;一、72. 编辑距离二、647. 回文子串三、516. 最长回文子序列 一、72. 编辑距离 题目链接&#xff1a;https://l…

应用案例 | 商业电气承包商借助Softing NetXpert XG2节省网络验证时间

一家提供全方位服务的电气承包商通过使用Softing NetXpert XG2顺利完成了此次工作任务——简化了故障排查的同时&#xff0c;还在很大程度上减少了不必要的售后回访。 对已经安装好的光纤或铜缆以太网网络进行认证测试可能会面临不同的挑战&#xff0c;这具体取决于网络的规模、…

示例五、气敏传感器

通过以下几个示例来具体展开学习,了解气敏传感器原理及特性&#xff0c;学习气敏传感器的应用&#xff1a; 示例五、气敏传感器 一、基本原理&#xff1a;随着人们生活水平的不断提高&#xff0c;人们对环境和健康问题越来越重视。各种燃气的广泛使用&#xff0c;使生产效率和…

socket编程 学习笔记 理解

在使用socket&#xff08;也就是套接字&#xff09;编程的时候&#xff0c;其实是工作于应用层和传输层之间 如果使用的是基于TCP的socket&#xff0c;那每个数据包的发送的过程大致为&#xff1a; 数据通过socket套接字构造符合TCP协议的数据包在屏蔽底层协议的情况下&#…

多模态CLIP和BLIP

一、CLIP 全称为Contrastive Language-Image Pre-Training用于做图-文匹配&#xff0c;部署在预训练阶段&#xff0c;最终理解为图像分类器。 1.背景 以前进行分类模型时&#xff0c;存在类别固定和训练时要进行标注。因此面对这两个问题提出CLIP&#xff0c;通过这个预训练…

显式Intent

activity.xml <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto&q…

B 站评论系统架构设计难点

更多大厂面试内容可见 -> http://11come.cn B 站评论系统架构设计难点 这里整理一下在哔哩哔哩技术公众号看到的 B 站评论系统的架构设计文章&#xff0c;自己在学习过程中&#xff0c;对其中感觉比较有帮助的点做一下整理&#xff0c;方便以后查阅&#xff0c;详细版可以点…

你要顺着毛撸Rust——简评LogLogGames放弃Rust游戏开发

庄晓立/LIIGO&#xff0c;2024年5月11日。 上个月底&#xff0c;游戏开发工作室LogLogGames发文《Leaving Rust gamedev after 3 years》&#xff0c;声明在经历3年磨难后决定放弃用Rust语言开发游戏。万字长文&#xff0c;开启吐槽模式&#xff0c;引发国内外大量争论。 我尊…