Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(自定义BeanPostProcessor)

news2024/11/24 22:36:27

序言

之前文章有介绍采用FactoryBean的方式创建对象,以及使用反射创建对象。
这篇文章继续介绍Spring中创建Bean的形式之一——自定义BeanPostProcessor。
之前在介绍BeanPostProcessor的文章中有提到,BeanPostProcessor接口的实现中有一个InstantiationAwareBeanPostProcessor接口
而在Spirng源码中的doGetBean方法中就有针对该接口的判断逻辑,如果有类实现了InstantiationAwareBeanPostProcessor则可以在对应的方法中进行Bean对象的创建。
在这里插入图片描述
源码
去除无用代码,我们这里主要看resolveBeforeInstantiation方法。如果通过resolveBeforeInstantiation创建了Bean示例,则return该Bean 不在继续往下走其他流程。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		RootBeanDefinition mbdToUse = mbd;
		//锁定class,根据设置的class属性或者根据className来解析class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}
		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 给BeanPostProcessors一个机会来返回代理来替代真正的实例,
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
	}

resolveBeforeInstantiation
如果满足if条件,则会走applyBeanPostProcessorsBeforeInstantiation方法进行对象的创建。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		//如果beforeInstantiationResolved值为null或者true,那么表示尚未被处理,进行后续的处理
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			// 确保Bean确实在此处进行处理
			// 判断当前mbd是否是合成的,只有在实现aop的时候synthetic的值才为true,并且是否实现了InstantiationAwareBeanPostProcessor接口
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				//确定目标类型
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

applyBeanPostProcessorsBeforeInstantiation
获取所有实现了BeanPostProcessors的类,并强转成InstantiationAwareBeanPostProcessor 类型,调用postProcessBeforeInstantiation方法进行Bean的创建。

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

测试类

我们针对上面的源码流程,扩展自定义的BeanPostProcessor进行类的创建。我们这里依然采用上篇文章提到的Cglib动态代理的方式创建我们的对象。

BeforeInstantiation
BeforeInstantiation 是我们想要最终创建的实例对象。

public class BeforeInstantiation {

    public void doSomeThing(){
        System.out.println("执行do some thing....");
    }
}

MyMethodInterceptor
拦截器类,对目标方法进行中间拦截,上篇文章在讲lookup-method标签时,里面采用Cglib动态代理生成对象的固定写法,创建Enhancer对象并设置CallBack。
因为我们这里也采用Cglib的方式进行对象的创建,所以也需要设置CallBack。

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("目标方法执行之前:" + method);
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("目标方法执行之后:" + method);
        return o1;
    }
}

MyInstantiationAwareBeanPostProcessor
自定义InstantiationAwareBeanPostProcessor接口的扩展类,调用postProcessBeforeInstantiation方法,采用Cglib的固定写法实现对BeforeInstantiation 对象的创建。
其余方法因为用不到,所以直接return对应类型,没有具体业务逻辑。

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

		if (beanClass == BeforeInstantiation.class) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(beanClass);
			enhancer.setCallback(new MyMethodInterceptor());
			BeforeInstantiation beforeInstantiation = (BeforeInstantiation) enhancer.create();
			return beforeInstantiation;
		}
		return null;
	}


	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
		return pvs;
	}

	@Override
	public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
		return pvs;
	}

resolveBeforeInstantiation.xml
xml中声明MyInstantiationAwareBeanPostProcessor对象和BeforeInstantiation对象。

<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="myInstantiationAwareBeanPostProcessor" class="org.springframework.resolveBeforeInstantiation.MyInstantiationAwareBeanPostProcessor" />

	<bean id="beforeInstantiation" class="org.springframework.resolveBeforeInstantiation.BeforeInstantiation"/>
</beans>

main
执行refresh()主流程调用registerBeanPostProcessors方法创建MyInstantiationAwareBeanPostProcessor后,会调用addBeanPostProcessor方法将hasInstantiationAwareBeanPostProcessors()变量设置为true,当beforeInstantiation创建时,if 判断 整体为 true,调用我们自定义的扩展类创建beforeInstantiation对象。

	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("resolveBeforeInstantiation.xml");
		BeforeInstantiation beanInstantiation = (BeforeInstantiation)ac.getBean("beforeInstantiation");
		beanInstantiation.doSomething();
	}

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

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

相关文章

Proxmox VE 超融合集群扩容后又平稳运行了170多天--不重启的话,488天了

五个节点的Proxmox VE 超融合集群&#xff0c;扩从了存储容量&#xff0c;全NVMe高速盘&#xff0c;单机4条3.7TB容量&#xff08;扩容前是两块NVMe加两块16TB的慢速SATA机械盘&#xff0c;拔掉机械盘&#xff0c;替换成两块NVMe&#xff09;&#xff0c;速度那叫一个快啊。 当…

秋招突击——6/16——复习{(单调队列优化DP)——最大子序和,背包模型——宠物小精灵收服问题}——新作{二叉树的后序遍历}

文章目录 引言复习&#xff08;单调队列优化DP&#xff09;——最大子序和单调队列的基本实现思路——求可移动窗口中的最值总结 背包模型——宠物小精灵收服问题思路分析参考思路分析 新作二叉树的后续遍历加指针调换 总结 引言 复习 &#xff08;单调队列优化DP&#xff09…

Qt实现单例模式:Q_GLOBAL_STATIC和Q_GLOBAL_STATIC_WITH_ARGS

目录 1.引言 2.了解Q_GLOBAL_STATIC 3.了解Q_GLOBAL_STATIC_WITH_ARGS 4.实现原理 4.1.对象的创建 4.2.QGlobalStatic 4.3.宏定义实现 4.4.注意事项 5.总结 1.引言 设计模式之单例模式-CSDN博客 所谓的全局静态对象&#xff0c;大多是在单例类中所见&#xff0c;在之前…

使用ant-design/cssinjs向plasmo浏览器插件的内容脚本content中注入antd的ui组件样式

之前写过一篇文章用来向content内容脚本注入antd的ui&#xff1a;https://xiaoshen.blog.csdn.net/article/details/136418199&#xff0c;但是方法就是比较繁琐&#xff0c;需要将antd的样式拷贝出来&#xff0c;然后贴到一个单独的css样式文件中&#xff0c;然后引入到内容脚…

20个超实用的VS Code扩展(2024年版)

大家好&#xff0c;今天小程给大家带来一篇关于 VS Code 扩展的文章。VS Code 这几年做得是风生水起&#xff0c;可以算得上是微软的良心产品&#xff0c;其最大的优势就是拥有众多高质量的扩展。在本文中&#xff0c;将向大家推荐一些我认为在 2024 年对开发者来说又实用又好用…

分布式技术导论 — 探索分析从起源到现今的巅峰之旅(分布式协议)

探索分析从起源到现今的巅峰之旅2 前提回顾最终一致性Clock时钟机制局限性 CAP协议CAP理论的三要素A和C机制的保障P分区容错性AP机制的保障CP机制的保障 分布式系统方向 分布式系统之ZookeeperZK的作用和职责协调服务命名服务构建高可靠服务 ZK的常见用法ZK基本原理ZK的顺序一致…

将粘贴文本进输入框中时不带有任何格式(包括背景颜色和字体)解决办法

只需要四行代码解决&#xff0c;这里用到vue3里面的事件 paste"" 代码块&#xff1a; <div paste"handlePaste"></div>//粘贴文本时不带有任何格式&#xff08;包括背景颜色和字体&#xff09;function handlePaste(event) {event.preventDef…

【计算机毕业设计】234基于微信小程序的中国各地美食推荐平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【数据分析】用Python做事件抽取任务-快速上手方案

目录 方法一&#xff1a;使用OmniEvent库安装OmniEvent使用OmniEvent进行事件抽取OmniEvent优点缺点 方法二&#xff1a;使用大模型使用GPT网页版进行事件抽取事件类型列表 大模型优点缺点 总结 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;事件抽取是一项关键任…

多组学双疾病串扰怎么做?PAN-AD九个机器学习+MR+单细胞,工作量不少

说在前面 “串扰”这个名词听起来高级了一个level&#xff0c;其实就是MR-通路的双疾病联合分析。虽然是筛选标志物的思路&#xff0c;但是工作量不小&#xff0c;作者还收集了13个不同AD自身免疫疾病数据集用于验证自己的机器学习模型&#xff0c;分析就是一些常规的WGCNA、P…

基于sass模式Java语言+MySQL + MyCat开发的his系统源码 HIS系统住院业务流程 HIS系统住院流程化管理

基于sass模式Java语言MySQL MyCat开发的his系统源码 HIS系统住院业务流程 HIS系统住院流程化管理 HIS系统住院业务&#xff0c;该系统为医院提供了一套完整的住院业务流程解决方案&#xff0c;旨在提高住院管理的效率和精确度。通过HIS系统&#xff0c;医院工作人员可以某轻理…

DzzOffice集成功能最丰富的开源PHP+MySQL办公系统套件

DzzOffice是一套开源办公套件&#xff0c;旨在为企业和团队提供类似“Google企业应用套件”和“微软Office365”的协同办公平台。以下是对DzzOffice的详细介绍&#xff1a; 主要功能和应用&#xff1a; 网盘&#xff1a;支持企业、团队文件的集中管理&#xff0c;提供文件标签…

Oracle 是否扼杀了开源 MySQL

Oracle 是否无意中扼杀了开源 MySQL Peter Zaitsev是一位俄罗斯软件工程师和企业家&#xff0c;曾在MySQL公司担任性能工程师。大约15年前&#xff0c;当甲骨文收购Sun公司并随后收购MySQL时&#xff0c;有很多关于甲骨文何时“杀死MySQL”的讨论。他曾为甲骨文进行辩护&#…

攻防演练“轻装上阵” | 亚信安全信舱ForCloud 打造全栈防护新策略

网络世界攻防实战中&#xff0c;攻击风险已经从代码到云横跨全栈技术点&#xff0c;你准备好了吗 云服务器&#xff0c;攻击众矢之的 2022年超过38万个Kubernetes API服务器暴露公网&#xff0c;成为攻击者目标。云服务器&#xff0c;尤其是开源设施&#xff0c;一直以来不仅是…

物理隔离后数据怎么导入和导出?安全U盘一键解决

政府单位、军工和科研所、航空航天企业、金融机构、医疗单位、电力企业、生物制药实验室等企业及单位&#xff0c;因研发和生产过程、或日常经营中涉及大量敏感信息和技术&#xff0c;需要通过物理隔离来确保网络的安全性。因此&#xff0c;多采用物理隔离的方式进行网络建设。…

【Unity实战篇】| 快速制作一个简易时钟,包括2D和3D时钟

前言 【Unity实战篇】| 快速制作一个时钟&#xff0c;包括2D和3D时钟一、2D时钟制作1.1 钟表盘制作1.2 指针制作1.3 钟表搭建1.4 设置时钟的中心点1.5 时钟旋转逻辑 二、3D时钟制作2.1 搭建表盘和指针2.2 调整指针的位置和节点2.3 时钟旋转逻辑 总结 前言 时钟 这个东西想必不…

租房项目之并发缺失数据问题

前奏&#xff1a;本项目是一个基于django的租房信息获取项目。本次博客牵扯到两个版本&#xff0c;集中式分布以及分布式部署&#xff08;两个版本的ui不同&#xff0c;集中式用的是老版ui&#xff0c;分布式使用的是新版ui&#xff09;&#xff1b; 项目链接&#xff1a;http…

Peewee,一个既小巧又强大的 Python 库-轻松实现数据库的增删改查

目录 01初识 Peewee 为什么选择 Peewee? 02安装与配置 安装 Peewee 配置 Peewee 03定义模型 定义简单模型 定义复杂模型 04基本操作 创建记录 查询记录 更新记录 删除记录 05高级操作 复杂查询 事务处理 使用信号 模型迁移 06实战案例 简单博客系统 任务管…

2024年金地杯山西省大学生数学建模竞赛B题D题论文代码分析

2024金地杯数学建模B题和金地杯数学建模D题32页论文和代码已完成&#xff0c;代码为B题D题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求…