一起学SF框架系列5.9-spring-Beans-bean实例创建

news2024/11/26 12:28:34

bean实例化底层采用Java反射机制,但Spring根据框架需要提供了更多的增强功能。

类关系图

在这里插入图片描述

InstantiationStrategy:接口-定义了创建RootBeanDefinition对应bean实例方法
SimpleInstantiationStrategy:简单bean的实例化处理。实现了InstantiationStrategy,但不支持方法注入。
CglibSubclassingInstantiationStrategy:继承于SimpleInstantiationStrategy,主要实现有方法注入bean的实例化。是BeanFactory的默认实例化bean的构建器。

AbstractClassGenerator:CGLIB实例化器使用到的工具抽象类。除了缓存生成的类以提高性能外,它还提供了钩子,用于自定义ClassLoader、生成的类的名称以及生成前应用的转换
Enhancer:增强类,生成用于方法拦截的动态子类。动态生成的子类覆盖超类的非最终方法,并具有回调到用户定义的拦截器实现的钩子。

BeanUtils:封装JavaBeans实例化方法的抽象类(全部是静态方法),包括实例化bean、检查bean属性类型、复制bean属性等。

ReflectionUtils:spring封装的用于处理类反射API和处理反射异常的实用程序类。

SimpleInstantiationStrategy

instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)

bean实例化入口

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
		// 无重写方法bean的实例化
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					//没有指定bean的构建器,就取Class默认构建器
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						// 调用Java类的获取Class默认构建器
						constructorToUse = clazz.getDeclaredConstructor();
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			// 构建bean实例
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// 有重写方法bean的实例化(见CglibSubclassingInstantiationStrategy)
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

CglibSubclassingInstantiationStrategy

instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)

动态实例化类入口

	// 过渡方法
	@Override
	protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		return instantiateWithMethodInjection(bd, beanName, owner, null);
	}

	@Override
	protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
			@Nullable Constructor<?> ctor, Object... args) {
		// 调用内部类方法:CglibSubclassCreator.instantiate
		return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
	}

内部类CglibSubclassCreator.instantiate(@Nullable Constructor<?> ctor, Object… args)

		public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
			// 创建增强的动态子类
			Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
			Object instance;
			if (ctor == null) {
				// 如果是构造函数为空,则使用默认的构造函数创建实例,注意这里创建的实例是bean的增强子类的
				instance = BeanUtils.instantiateClass(subclass);
			}
			else {
				try {
					// 根据参数类型从增强子类的class中获取对应的增强子类构造函数
					Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
					// 通过增强子类构造函数,创建bean的增强子类的实例对象
					instance = enhancedSubclassConstructor.newInstance(args);
				}
				catch (Exception ex) {
					throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
							"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
				}
			}
			// 设置回调被代理类的方法
			// SPR-10785: set callbacks directly on the instance instead of in the
			// enhanced class (via the Enhancer) in order to avoid memory leaks.
			Factory factory = (Factory) instance;
			factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
					new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
					new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
			return instance;
		}

内部类CglibSubclassCreator.createEnhancedSubclass

创建增强的动态子类

		public Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
			// 创建Enhancer类 
			Enhancer enhancer = new Enhancer();
			// beanDefinition为增强子类的父Classs
			enhancer.setSuperclass(beanDefinition.getBeanClass());
			// 设置命令策略-实例化
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			//使用临时的类加载器
			enhancer.setAttemptLoad(true);
			// 设置类加载器(将应用程序ClassLoader作为为当前线程上下文ClassLoader)
			if (this.owner instanceof ConfigurableBeanFactory cbf) {
				ClassLoader cl = cbf.getBeanClassLoader();
				enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
			}
			// 设置代理器(回调方法),用于获取使用哪种cglib的interceptor来增强子类
			enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
			// 设置回调类型
			enhancer.setCallbackTypes(CALLBACK_TYPES);
			return enhancer.createClass();
		}
	}

内部类MethodOverrideCallbackFilter

CGLIB回调过滤器,只要针对方法拦截行为。实现了CallbackFilter接口,主要就是accept方法。

	private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {

		private static final Log logger = LogFactory.getLog(MethodOverrideCallbackFilter.class);

		public MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
			super(beanDefinition);
		}

		@Override
		public int accept(Method method) {
			// 从beanDefinition中获取方法的MethodOverride
			MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
			if (logger.isTraceEnabled()) {
				logger.trace("MethodOverride for " + method + ": " + methodOverride);
			}
			if (methodOverride == null) {
				//不存在
				return PASSTHROUGH;
			}
			else if (methodOverride instanceof LookupOverride) {
				//可按bean名称或bean类型(基于方法声明的返回类型)查找对象的Override方法。对应内部类LookupOverrideMethodInterceptor
				return LOOKUP_OVERRIDE;
			}
			else if (methodOverride instanceof ReplaceOverride) {
				//非LookupOverride类型的其它重载方法。对应内部类ReplaceOverrideMethodInterceptor
				return METHOD_REPLACER;
			}
			throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
					methodOverride.getClass().getName());
		}
	}

内部类LookupOverrideMethodInterceptor

CGLIB MethodInterceptor重写方法,用在容器中查找的bean的实现返回。
主要实现MethodInterceptor.intercept。

	private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {

		private final BeanFactory owner;

		public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
			super(beanDefinition);
			this.owner = owner;
		}

		@Override
		public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
			//获取LookupOverride 
			// Cast is safe, as CallbackFilter filters are used selectively.
			LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
			Assert.state(lo != null, "LookupOverride not found");
			Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
			if (StringUtils.hasText(lo.getBeanName())) {
				// 按beanName从容器中获取bean返回
				Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
						this.owner.getBean(lo.getBeanName()));
				// Detect package-protected NullBean instance through equals(null) check
				return (bean.equals(null) ? null : bean);
			}
			else {
				//没有beanName,按照返回类型返回bean
				// Find target bean matching the (potentially generic) method return type
				ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
				return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
						this.owner.getBeanProvider(genericReturnType).getObject());
			}
		}
	}

内部类ReplaceOverrideMethodInterceptor

CGLIB MethodInterceptor重写方法,用对泛型MethodReplacer的调用替换它们。
主要实现MethodInterceptor.intercept。

	private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {

		private final BeanFactory owner;

		public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
			super(beanDefinition);
			this.owner = owner;
		}

		@Override
		public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
			// 获取对应的ReplacedOverride
			ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
			Assert.state(ro != null, "ReplaceOverride not found");
			// 获取对应的MethodReplacer
			// TODO could cache if a singleton for minor performance optimization
			MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
			// 调用MethodReplacer的reimplement方法获取结果
			return mr.reimplement(obj, method, args);
		}
	}

BeanUtils

instantiateClass(Constructor ctor, Object… args)

实例化类。

	public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		// 类构建器不能为空
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			// 设置类构建器是可访问的
			ReflectionUtils.makeAccessible(ctor);
			if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
				// kotlin java (Kotlin作为Android应用程序开的第二种官方编程语言)
				return KotlinDelegate.instantiateClass(ctor, args);
			}
			else {
				// 获得类构建器参数数量
				int parameterCount = ctor.getParameterCount();
				Assert.isTrue(args.length <= parameterCount, "Can't specify more arguments than constructor parameters");
				if (parameterCount == 0) {
					// 无参构建器直接new新实例
					return ctor.newInstance();
				}
				// 获得类构建器参数类型
				Class<?>[] parameterTypes = ctor.getParameterTypes();
				// 把传入的参数值赋给对应的参数
				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];
					}
				}
				// 有参构建新实例
				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());
		}
	}

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

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

相关文章

WEB:题目名称-文件包含

背景知识 题目 题目了文件包含&#xff0c;所以想到了php伪协议 构造payload尝试读取flag.php /?filenamephp://filter/readconvert.base64-encode/resourceflag.php 页面提示“do not hack”猜测可能是黑名单检测敏感字符串。猜测字符串哪些被禁用&#xff0c;这里输入单个…

【算法与数据结构】144、94、145LeetCode二叉树的前中后遍历(递归法、迭代法)

文章目录 一、题目二、递归算法三、迭代算法3.1 迭代算法13.2 迭代算法2 ——统一风格写法 四、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、递归算法 思路分析&#xff1a;这道题比较简单&#xff0c;不多说…

LCD—STM32液晶显示(2.使用FSMC模拟8080时序)

目录 使用STM32的FSMC模拟8080接口时序 FSMC简介 FSMC NOR/PSRAM中的模式B时序图 用FSMC模拟8080时序 重点&#xff1a;HADDR内部地址与FSMC地址信号线的转换&#xff08;实现地址对齐&#xff09; 使用STM32的FSMC模拟8080接口时序 ILI9341的8080通讯接口时序可以由STM32使…

PHP要怎么学--【强撸项目000】

强撸项目 总目录在000集 文章目录 本系列校训学习资源的选择环境的问题本人推荐 PHP视频的知识点分析总结题外话 本系列校训 用免费公开视频&#xff0c;卷飞培训班哈人&#xff01;打死不报班&#xff0c;赚钱靠狠干&#xff01; 只要自己有电脑&#xff0c;前后项目都能搞&a…

sqli-labs 堆叠注入 解析

打开网页首先判断闭合类型 说明为双引号闭合 我们可以使用单引号将其报错 先尝试判断回显位 可以看见输出回显位为2&#xff0c;3 尝试暴库爆表 这时候进行尝试堆叠注入&#xff0c;创造一张新表 ?id-1 union select 1,database(),group_concat(table_name) from informatio…

给你一个网站,你如何测试?

首先&#xff0c;查找需求说明、网站设计 等相关文档&#xff0c;分析测试需求。 制定测试计划&#xff0c;确定测试范围和测试策略&#xff0c;一般包括以下几个部分&#xff1a; 功能性测试&#xff1b;界面测试&#xff1b;性能测试&#xff1b;数据库测试&#xff1b;安全…

AD如何查看PCB完成度?快来看这篇文

在Altium Designer&#xff08;AD&#xff09;中&#xff0c;很多工程师通过使用Design Rule Check&#xff08;DRC&#xff0c;常用于检查PCB设计是否符合设计规范和要求&#xff09;功能来检查PCB设计的完成度&#xff0c;但很多小白不太熟悉怎么去使用DRC&#xff0c;下面来…

深入浅出C语言—【函数】下

目录 5. 函数的嵌套调用和链式访问5.1嵌套调用5.2 链式访问 6. 函数的声明和定义6.1 函数声明6.2 函数定义 7. 函数递归&#x1f451;7.1 什么是递归&#xff1f;7.2 递归的两个必要条件7.2.1 练习17.2.2 练习2 7.3 递归与迭代7.3.1 练习37.3.2 练习4 5. 函数的嵌套调用和链式访…

解决Missing cookie ‘JssionId‘ for method parameter of type String问题

错误描述如下所示&#xff1a; 上述错误是我在使用CookieValue注解&#xff0c;获取cookieID时出现的&#xff0c;错误原因是由于**CookieValue注解注解中的value值和浏览器中的cookie的jssionID不一致所导致的** 如下所示为浏览器中的CookieID的参数名 而我在注解中写的如下图…

浪涌保护器行业应用防雷选型方案

当今社会中&#xff0c;电气设备的使用范围越来越广泛&#xff0c;也越来越普及&#xff0c;而与之相关的浪涌保护器就显得尤为重要。在这个领域&#xff0c;有一种高品质的浪涌保护器 —— 地凯防雷SPD浪涌保护器&#xff0c;它可以为各种设备提供强大的保护&#xff0c;并在各…

YOLOv5——pytorch环境搭建

环境搭建是一个最最基础而又基本的事情&#xff0c;是一切工作开始前的基本要求。 由于YOLOv7和YOLOv5不兼容&#xff0c;这次用到了YOLOv5&#xff0c;我不得不再使用anaconda创建一个虚拟环境。 Tip&#xff1a;很多人不了解Anaconda存在的意义&#xff0c;就是为了弥补pyt…

四、DML-1.数据操作-添加

一、DML介绍 Data Manipulation Language 数据操作语言 用来对数据库中表的数据记录进行增删改操作。 二、添加数据 1、给指定字段添加数据 insert into employee(id, workno, name, gender, age, idcard,entrydate) values (1, 001,Itcast, 男, 18, 123456789012345678, 2…

kaggle新赛:学生摘要评估大赛赛题解析(NLP)

赛题名称&#xff1a;CommonLit - Evaluate Student Summaries 赛题链接&#xff1a; https://www.kaggle.com/competitions/commonlit-evaluate-student-summaries/ 赛题背景 摘要写作是所有年龄段学习者的一项重要技能。总结可以增强阅读理解能力&#xff0c;特别是在第二…

SOLIDWORKS工程图模板如何设置?

SOLIDWORKS工程图模板是非常重要的&#xff0c;它可以帮助工程师快速创建符合公司规范的工程图纸。本文将介绍SOLIDWORKS工程图模板的基本知识&#xff0c;包括如何创建和使用模板。 一、创建SOLIDWORKS工程图模板 首先&#xff0c;我们需要打开SOLIDWORKS软件&#xff0c;并选…

MySQL高阶语句之二

目录 ​编辑 一、子查询 1.1语法 1.2select 1.3insert 1.3update 1.4delete 1.5 exists 1.6别名as 二、MySQL视图 2.1功能 2.2区别 2.3联系 2.4 创建视图(单表) 2.5 创建视图(多表) 2.6修改原表数据 2.7修改视图数据 三、NULL值 一、子查询 子查询也被称作内查询…

虚拟机ubuntu1804打开联合标定工具箱的步骤(toolkit)

1、运行roscore roscore 2、进入到calibration文件夹打开终端 source devel/setup.bash3、运行rosrun打开即可 rosrun calibration_camera_lidar calibration_toolkit

iview的表格添加筛选功能需要注意的问题

给table的某列添加筛选功能 在table中通过给columns数据的项&#xff0c;设置 filters&#xff0c;可进行筛选&#xff0c;filters 接收一个数组。 然后再指定一个筛选函数 filterMethod 才可以进行筛选&#xff0c;filterMethod 传入两个参数value和 row。 如果指定 filter…

基于异步FIFO的串口回环测试

文章目录 前言一、异步FIFO简介二、串口简介2.1 数据接收模块(RX)2.1 数据发送模块(TX) 三、IP核说明与配置2.1 PLL IP核2.2 FIFO IP核 四、数据关联 前言 当涉及到串口通信的硬件设计和软件开发时&#xff0c;进行有效的测试是至关重要的。串口回环测试是一种常见的测试方法&a…

GSV6201替代方案|CS5466设计资料|CS5466原理图|typec转HDMI_8k方案芯片

GSV6201是一款高性能、低功耗、高性能的&#xff0c;USB Type-C备用模式显示端口1.4至HDMI 2.1转换器。通过集成增强型微控制器&#xff0c;GSV6201创造了一个经济高效的解决方案提供了上市时间优势。显示端口接收机支持高达32.4Gbps&#xff08;HBR3&#xff0c;4通道&#xf…

美国SaaS管理平台Zluri完成2000万美元的B轮融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;SaaS运营(SaaSOps)平台Zluri今日宣布获得2000万美元的融资&#xff0c;帮助企业管理SaaS资产并降低风险。B轮融资由Lightspeed领投&#xff0c;参与融资的其他投资者包括MassMutual Ventures、End…