Spring源码二十二:Bean实例化流程五
上一篇Spring源码二十一:Bean实例化流程四,咱们主要分析里createBeanInstance方法Spring给我们提供给的FactoryMethod方法,举例说明了factoryMethod属性如何使用,同时简单讨论了具体实现逻辑。
这一篇咱们将进入反射实例化Bean:
createBeanInstance构造推断
// 如果有多个构造方法,通过该方法查找对应的构造法方法Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// Preferred constructors for default construction?// 获取首选的构造函数列表ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// No special handling: simply use no-arg constructor.// 用无参构造函数来创建bean,先进入这个方法看下return instantiateBean(beanName, mbd);
查找构造方法:
determineConstructorsFromBeanPostProcessors
方法会调用BeanPostProcessor来查找与给定Bean类和Bean名称对应的构造函数。如果找到了一个或多个构造方法,或者满足以下任何一个条件:
如果满足其中任何一个条件,则调用 autowireConstructor
方法来通过构造函数自动装配来实例化Bean。
mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR
:自动装配模式为构造函数自动装配。mbd.hasConstructorArgumentValues()
:Bean定义中有构造函数参数值。!ObjectUtils.isEmpty(args)
:构造函数参数不为空。
获取首选的构造函数:
如果前面的条件不满足,代码会尝试获取首选的构造函数列表。如果存在首选的构造函数,也会调用 autowireConstructor
方法来实例化Bean。
使用无参构造函数:
如果既没有找到构造方法,也没有指定构造函数参数,则使用无参构造函数来创建Bean。调用 instantiateBean
方法来实例化Bean对象。
instantiateBean
/*** 使用默认构造实例化一个bean* 首先使用instantiate方法实例化一个beanInstance* 然后构建一个BeanWrapper* 返回BeanWrapper对象** Instantiate the given bean using its default constructor.** @param beanName the name of the bean* @param mbd the bean definition for the bean* @return a BeanWrapper for the new instance*/protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {try {Object beanInstance;final BeanFactory parent = this;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->getInstantiationStrategy().instantiate(mbd, beanName, parent),getAccessControlContext());}else {// 核心的方法是instantiatebeanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);}BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);}}
上述代码也是比较清晰的,咱们来简单分析一下:通过默认构造函数来实例化一个Bean,并将该Bean封装在一个 BeanWrapper 实例中。它首先检查系统是否启用了安全管理器,如果启用,则在特权模式下实例化Bean;否则,直接实例化。最后,它会对 BeanWrapper 进行初始化并返回。如果在此过程中出现任何异常,方法会捕获并抛出一个 BeanCreationException。
instantiate
通过上述分析,咱们接着进入instantiate方法看下。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// Don't override the class with CGLIB if no overrides.//if (!bd.hasMethodOverrides()) {Constructor<?> constructorToUse;synchronized (bd.constructorArgumentLock) {constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse == null) {final Class<?> clazz = bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, "Specified class is an interface");}try {if (System.getSecurityManager() != null) {constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);}else {constructorToUse = clazz.getDeclaredConstructor();}bd.resolvedConstructorOrFactoryMethod = constructorToUse;}catch (Throwable ex) {throw new BeanInstantiationException(clazz, "No default constructor found", ex);}}}// 实例化beanreturn BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass.return instantiateWithMethodInjection(bd, beanName, owner);}}
上述代码:首先检查 bd
是否有方法重写,如果没有则采用直接实例化的方式。通过同步块确保构造函数解析的线程安全性,尝试获取默认构造函数。如果类是接口或没有默认构造函数,则抛出异常。成功获取构造函数后,通过 BeanUtils.instantiateClass
方法实例化 bean。如果有方法重写,则使用 CGLIB 动态生成子类进行实例化。
我们再进入BeanUtils.instantiateClass方法中看下:
BeanUtils.instantiateClass
{Assert.notNull(ctor, "Constructor must not be null");try {ReflectionUtils.makeAccessible(ctor);if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {return KotlinDelegate.instantiateClass(ctor, args);}else {Class<?>[] parameterTypes = ctor.getParameterTypes();Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");Object[] argsWithDefaultValues = new Object[args.length];for (int i = 0 ; i < args.length; i++) {if (args[i] == null) {Class<?> parameterType = parameterTypes[i];argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);}else {argsWithDefaultValues[i] = args[i];}}// 通过反射来实例化一个bean实例return ctor.newInstance(argsWithDefaultValues);}}catch (InstantiationException ex) {throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);}catch (IllegalAccessException ex) {throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);}catch (IllegalArgumentException ex) {throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);}catch (InvocationTargetException ex) {throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());}}
上述代码可以看到:首先确保传入的构造函数不为 null,并通过 ReflectionUtils.makeAccessible
方法确保构造函数可访问。如果类是 Kotlin 类型,则通过 KotlinDelegate.instantiateClass
方法实例化,这块可以直接跳古偶。
否则,检查参数长度并为 null 参数赋默认值,然后调用构造函数创建实例。若实例化过程中出现异常,则抛出相应的 BeanInstantiationException
异常,提示可能的错误原因,如类是否为抽象类、构造函数是否可访问、参数是否合法或构造函数是否抛出异常。
小结
今天咱们主要了解到bean在实例化之前会推测构造方法,然后根据构造方法的类型来通过反射机制来完成具体的实例化。到这里咱们终于看到了实例化的bean,接下来Spring会对这个刚刚实例化好的bean做些什么呢?
总结
相关文章:

Spring源码二十二:Bean实例化流程五
上一篇Spring源码二十一:Bean实例化流程四,咱们主要分析里createBeanInstance方法Spring给我们提供给的FactoryMethod方法,举例说明了factoryMethod属性如何使用,同时简单讨论了具体实现逻辑。 这一篇咱们将进入反射实例化Bean&am…...

Unity3D中UI层级改变详解
在Unity3D开发中,UI层级的调整是常见的需求,它直接关系到用户界面(UI)元素的显示顺序。在Unity的UI系统中,主要使用UGUI(Unitys Graphical User Interface)来实现界面布局和元素展示。本文将详细讲解Unity3D中如何改变…...

centos安装数据库同步工具sqoop并导入数据,导出数据,添加定时任务
目录 1.安装jdk 1.1上传jdk安装包到/opt目录下并解压 1.2解压 1.3配置环境变量 2.安装hadoop 2.1.下载hadoop 2.2.解压hadoop 2.3配置环境变量 3.安装sqoop 3.1下载 3.2解压 3.3下载依赖包并复制到指定位置 3.3.1下载commons-lang-2.6-bin.tar.gz 3.3.2将mysql-c…...

asp .net core 避免请求body数据量过大
方法1, 全局避免 引入包 dotnet add package Microsoft.AspNetCore.Http.Features using Microsoft.AspNetCore.Http.Features;public void ConfigureServices(IServiceCollection services) {services.Configure<FormOptions>(options >{// 设置允许的最…...

搭建discuz论坛(lvs+nginx+http+mysql+nfs)8台服务器
搭建discuz论坛(lvsnginxhttpmysqlnfs) 一、IP规划 服务名IP地址服务LVS1192.168.100.110keepalivedipvsadmLVS2192.168.100.111keepalivedipvsadmnginx1192.168.100.113nginxnginx2192.168.100.114nginxnfs192.168.100.116nfs-utilweb1192.168.100.11…...

就业平台小程序的设计
管理员账户功能包括:系统首页,个人中心,学生管理,企业管理,企业类型管理,留言板管理,系统管理 微信端账号功能包括:系统首页,招聘信息,简历,我的 …...

hid-ft260驱动学习笔记 5 - ft260_i2c_probe
目录 1. 保存ft260_device到私有数据 2. 初始化I2C设备分配属性 3. 添加I2C适配器 4. 初始化GPIO 5. ft260_i2c_algo 5.1 ft260_functionality 5.2 ft260_i2c_xfer 5.3 ft260_smbus_xfer 6. ft260_i2c_quirks 这个函数是i2c的接口probe函数。 1. 保存ft260_device到私…...

Android上如何使用perfetto分析systrace
Android上如何使用perfetto分析systrace Perfetto 是一个用于性能分析的工具,提供了对 Android 系统内部工作情况的详细视图。它可以用来替代传统的 systrace 工具,提供更加全面的性能分析功能。以下是如何使用 Perfetto 分析 Systrace 数据的详细指南&…...

React Hooks学习笔记
一、usestate的使用方法-初始化state函数 import React, { useState } from "react"; function App() {const [count, setCount] useState(0);return (<div><p>点击{count}次</p><button onClick{() > setCount(count 1)}>点击</bu…...

BGP第二日
上图为今日所用拓扑 ,其中R1和R4,R3和R5为EBGP邻居,R1和R3为IBGP邻居,AS200区域做OSPF动态路由 一.BGP建立邻居的六种状态 1.idle 空闲状态:建立邻居最初的状态 2.Connect 连接状态:在…...

rabbitmq集群创建admin用户之后,提示can access virtual hosts是No access状态
问题描述: 因业务需要使用的rabbitmq是3.7.8版本的,rabbitmq在3.3.0之后就允许使用guest账号的权限了,所以需要创建一个administrator标签的用户。 如下操作创建的用户: 创建完成之后就提示如下的报错: 注:…...

ARM功耗管理之多核处理器启动
安全之安全(security)博客目录导读 思考:SecureBoot?多核处理器启动流程?PSCI启动方式? 一般嵌入式系统使用的都是对称多处理器(Symmetric Multi-Processor, SMP)系统,包含了多个cpu, 这几个cp…...

java使用easypoi模版导出word详细步骤
文章目录 第一步、引入pom依赖第二步、新建导出工具类WordUtil第三步、创建模版word4.编写接口代码5.导出结果示例 第一步、引入pom依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><…...

Android 内部保持数据的方式
Android内部保持数据的方式主要有五种,每种方式都有其特定的用途和优点。以下是详细的介绍: SQLite数据库 定义:SQLite是一个轻量级的、跨平台的数据库,所有的信息都存储在单一文件内,占用内存小,并且支持…...

uniapp 表格,动态表头表格封装渲染
1.接口表格数据: {"headers": [{"label": "实例名","name": "v1","order": 1,"hide": false,"dateTypeValue": null},{"label": "所属科室","name&quo…...

beyond Compare连接 openWrt 和 VsCode
连接步骤总结 1. 新建会话 -> 文件夹比较 2.点击浏览文件夹 3.在弹出页面 配置 ftp 3.1)选中ftp 配置文件 3.2)选中ssh2 3.3)填写我们需要远端连接的主机信息 先点击连接并浏览 得到下方文件夹 弹出无效登录,说明需要密码 我们返回右键刚刚创建的新 …...

量化机器人能否识别市场机会?
量化机器人的设计和应用是为了通过高级算法和大数据分析,精确地识别和把握市场中的交易机会。这些机器人的能力不仅仅局限于执行预定的交易策略,更包括在复杂和快速变化的市场环境中识别利润机会。 首先,量化机器人能够处理和分析大量的市场…...

香橙派AIpro开发板评测:部署yolov5模型实现图像和视频中物体的识别
OrangePi AIpro 作为业界首款基于昇腾深度研发的AI开发板,自发布以来就引起了我的极大关注。其配备的8/20TOPS澎湃算力,堪称目前开发板市场中的顶尖性能,实在令人垂涎三尺。如此强大的板子,当然要亲自体验一番。今天非常荣幸地拿到…...

MongoDB教程(二):mongoDB引用shell
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言一、MongoD…...

A133 Android10 root修改
1.前言 客户应用需求root相关的权限,我们需要修改系统的权限才可以满足客户需求 2.修改方法 frameworks层:注释掉 diff --git a/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp b/frameworks/base/core/jni/com_android_internal_os_…...

实验场:在几分钟内使用 Bedrock Anthropic Models 和 Elasticsearch 进行 RAG 实验
作者:来自 Elastic Joe McElroy, Aditya Tripathi 我们最近发布了 Elasticsearch Playground,这是一个新的低代码界面,开发人员可以通过 A/B 测试 LLM、调整提示(prompt)和分块数据来迭代和构建生产 RAG 应用程序。今天…...

代理详解之静态代理、动态代理、SpringAOP实现
1、代理介绍 代理是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。为了对外开放协议,B往往实现了一个接口,A也会去实现接口。但是B是“真正”实现类,A则比较“虚”,他借用了B的方法去实现接口的方法。A…...

Laravel - laravel-websockets 开发详解
1.我laravel-websockets 的开发环境 Laravel 9.0Laravel WebSockets (最新版)Laravel Vite 2. 安装服务器端包 beyondcode/laravel-websockets 运行以下命令安装laravel-websockets composer require beyondcode/laravel-websockets 安装完后&#…...

vue3 学习笔记04 -- axios的使用及封装
vue3 学习笔记04 – axios的使用及封装 安装 Axios 和 TypeScript 类型定义 npm install axios npm install -D types/axios创建一个 Axios 实例并封装成一个可复用的模块,这样可以在整个应用中轻松地进行 API 请求管理。 在 src 目录下创建一个 services 文件夹&…...

键盘快捷键设置录入
效果图: 代码: import React, {useContext, useEffect, useRef} from react import {message} from "antd"; import lodash from "lodash"; import {StateContext} from ../../index.tsx import {useUpdateEffect} from "ahoo…...

刷题Day49|647. 回文子串、516.最长回文子序列
647. 回文子串 647. 回文子串 - 力扣(LeetCode) 思路:递推公式的含义是[i, j]内的子串是否为回文子串(bolean[][])。一共两种情况:s[i] s[j],i和j相差1以外就得判断中间包含的的字符串是否为回文了&…...

关于transformers库验证时不进入compute_metrics方法的一些坑
生成式任务输入就是标签 transformers在进入compute_metrics前会有一个判断,源码如下: # 版本 transformers4.41.2 # 在trainer.py 的 3842 行 # Metrics! if (self.compute_metrics is not Noneand all_preds is not Noneand all_labels is not Nonea…...

苹果提出RLAIF:轻量级语言模型编写代码
获取本文论文原文PDF,请在公众号【AI论文解读】留言:论文解读 代码生成一直是一个充满挑战的领域。随着大型语言模型(LLM)的出现,我们见证了在自然语言理解和生成方面的显著进步。然而,当涉及到代码生成&a…...

[leetcode] shortest-subarray-with-sum-at-least-k 和至少为 K 的最短子数组
. - 力扣(LeetCode) class Solution { public:int shortestSubarray(vector<int>& nums, int k) {int n nums.size();vector<long> preSumArr(n 1);for (int i 0; i < n; i) {preSumArr[i 1] preSumArr[i] nums[i];}int res n…...

专业140+总分420+天津大学815信号与系统考研经验天大电子信息与通信工程,真题,大纲,参考书。
顺利上岸天津大学,专业课815信号与系统140,总分420,总结一些自己的复习经历,希望对于报考天大的同学有些许帮助,少走弯路,顺利上岸。专业课: 815信号与系统:指定教材吴大正…...