Spring扩展点系列-InitializingBean

news2024/11/26 1:51:57

文章目录

    • 简介
    • 应用场景
    • 代码示例
    • 运行示例

简介

这篇文章主要介绍了Spring中InitializingBean的使用详细解析,InitializingBean是Spring提供的拓展性接口,提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

spring容器中Bean的生命周期内所有可扩展的点的调用顺序
扩展接口 实现接口
ApplicationContextlnitializer initialize
AbstractApplicationContext refreshe
BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor postProcessBeanFactory
BeanFactoryPostProcessor postProcessBeanFactory
instantiationAwareBeanPostProcessor postProcessBeforelnstantiation
SmartlnstantiationAwareBeanPostProcessor determineCandidateConstructors
MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition
InstantiationAwareBeanPostProcessor postProcessAfterlnstantiation
SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference
BeanFactoryAware postProcessPropertyValues
ApplicationContextAwareProcessor invokeAwarelnterfaces
BeanNameAware setBeanName
InstantiationAwareBeanPostProcessor postProcessBeforelnstantiation|
BeanNameAware setBeanName
@PostConstruct
InitializingBean afterPropertiesSet
FactoryBean getobject
SmartlnitializingSingleton afterSingletonslnstantiated
CommandLineRunner run
DisposableBeandestroy
## 源码分析 我们大概看一下初始化涉及的源码部分,主要为这两个方法, org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory``#initializeBean`` 和``#invokeInitMethods ``
/**
	 * @return the initialized bean instance (potentially wrapped)
	 * @see BeanNameAware
	 * @see BeanClassLoaderAware
	 * @see BeanFactoryAware
	 * @see #applyBeanPostProcessorsBeforeInitialization
	 * @see #invokeInitMethods
	 * @see #applyBeanPostProcessorsAfterInitialization
	 */
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//执行BeanPostProcessor接口实现类的postProcessBeforeInitialization方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//如果bean实现了InitializingBean或者自定义了initMethod,
       		//会在这里执行InitializingBean#afterPropertiesSet和initMethod方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//执行BeanPostProcessor接口实现类的postProcessAfterInitialization方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
		//判断bean是否实现了InitializingBean
		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			if (System.getSecurityManager() != null) {
				try {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				//如果实现了InitializingBean,真接调用afterPropertiesSet(),
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		if (mbd != null && bean.getClass() != NullBean.class) {
			//获取bean自定义的init-method方法
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
				//如果自定义了init-method方法,在这里开始执行;
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

看完源码部分,我们可以很清楚地知道InitializingBean#afterPropertiesSet方法和init-method是什么时候用什么方式来调用的( 通过反射调用init-method),且InitializingBean#afterPropertiesSet方法的执行时机要稍早于init-method。另外,如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法

应用场景

这个扩展点是比较有用的一个扩展点,可以用于

  • 修改默认设置的属性
  • 添加补充额外的属性值
  • 或者针对关键属性做校验
  • spring MVC内容有一个经典的实现场景,RequestMappingHandlerMapping完成URL与controller的映射工作
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}	

	protected void initHandlerMethods() {
		//循环所有的bean
		for (String beanName : getCandidateBeanNames()) {
			//如果bean名字不是以scopedTarget.开头
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				processCandidateBean(beanName);
			}
		}
		//日志输出
		handlerMethodsInitialized(getHandlerMethods());
	}
	
	protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
			beanType = obtainApplicationContext().getType(beanName);
		}
		catch (Throwable ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
			}
		}
		//他们是否是Handler(类上标注@Controller注解或者@RequestMapping注解)
		if (beanType != null && isHandler(beanType)) {
			//获取这个类上所有标注@RequestMapping的方法信息,以RequestMappingInfo形式把他们储存到MappingRegistry中
			detectHandlerMethods(beanName);
		}
	}

代码示例

完成一个rsa对象的初始化,方便该类方法调用使用

@Slf4j
@Configuration
public class ExtendInitializingBean implements InitializingBean {

    private RSA rsa;

    @Override
    public void afterPropertiesSet() {
        String priv = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJzDhvCJBIIuZzNu\n" +
                "+dHWY5inSAN6d/yqWOTl/5rWofT2+m59qjKoFuJ9kkuYUCkIpoEtLhu5PfOAdR9R\n" +
                "bsVnfXThgwOQFHx1/v4URXwOBrBHRYhPy8fApJSfdBWgKMs9GZ5WbDWVkPm7xhvJ\n" +
                "t716Wtx/leCjvq87jWVg8oo83uKtAgMBAAECgYAW77bNInG3QxHUy9kf03XpY8Rc\n" +
                "xJeiBMyShSJjuyFMMFy45jMM9rIOe8qiu+DdTXI14UXnRtsNHHpGgEmBoYrl4IZ9\n" +
                "Wgbxn0fkrcHaw4F8GoAapyqAgNkyU3kAf8of6G+ZeMulcZtbb7NXVkwTaRHOkzBg\n" +
                "2a44HCSQ2n/fHPxfwwJBANFhUKWMOV3SqEN7RjsxWNAk8P25xHzIWq6KCyhOx5Vm\n" +
                "KLIttnYUiA3UA3q5RJK8Hqh0a2JGcg8O9HawOuMWAAsCQQC/qxNG08pX8dm5mh5B\n" +
                "9d/Wc09U9V7Xni9gqqS5adjxChm97t5h8k3wRxTqDWHCJyZTkezy7pmZvaFWqwLO\n" +
                "xkMnAkBLEbIBeNIEkoejkiovBNVL40LIJXeOKaNhmrq/W+dw6CzFHWCi21+gXZhV\n" +
                "wuEUHwB68yqhFJLGVV1OxIaIbpXbAkBBY0WiRiKjuhiDHzbvXchNSu1nmIYQnSCg\n" +
                "o9aqgpfGM6HwkAtB8v3v2PAjoQkWyXBj1ka14fx43J6sCI9ep3jFAkBDi3wnlIzc\n" +
                "LpJxumw84P8f3pVJ1xKx9tchAh1W+hhcaq+/S+u3rIJcXfXWLojUp7yMyKjzy2lU\n" +
                "PNC8Qke0R/qC";
        String pub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcw4bwiQSCLmczbvnR1mOYp0gD\n" +
                "enf8qljk5f+a1qH09vpufaoyqBbifZJLmFApCKaBLS4buT3zgHUfUW7FZ3104YMD\n" +
                "kBR8df7+FEV8DgawR0WIT8vHwKSUn3QVoCjLPRmeVmw1lZD5u8Ybybe9elrcf5Xg\n" +
                "o76vO41lYPKKPN7irQIDAQAB";
        rsa = new RSA(priv, pub);
        log.info("afterPropertiesSet--Extend--run");
    }

	private void init(){
        log.info("init------run");
    }

    @Bean(initMethod = "init")
    public ExtendInitializingBean execInit(){
        return new ExtendInitializingBean();
    }

}

运行示例

在这里插入图片描述

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

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

相关文章

8G 显存玩转书生大模型

1. 启动demo 输出300字小故事 2. Streamlit Web Demo 部署InternLM2-Chat-1.8B 模型 安装依赖 让他输出helloworld

java基础 之 接口

文章目录 前言接口浅浅理解下接口抽象类与接口的爱恨情仇特点接口的回调 抽象类和接口相同之处区别 前言 前文回顾 戳这里→java基础 之 抽象类 因为接口是对抽象类的一种延伸&#xff0c;所以请先了解一下抽象类会更好的理解接口哦 子类对抽象类叫继承&#xff0c;使用关键字e…

Python 从入门到实战3(列表的简单操作)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们通过python小栗子来学习python基础知识语法&#xff…

怎样还原空白试卷?2024快速空白试卷还原软件合集

怎样还原空白试卷&#xff1f;2024快速空白试卷还原软件合集 在教育和考试过程中&#xff0c;有时需要将已经填写过的试卷还原为空白状态&#xff0c;以便重新使用或进行复印。通过使用特定的软件&#xff0c;你可以轻松地去除试卷上的手写内容或标记&#xff0c;恢复试卷的空…

【网络安全 | 虚拟机】VMware Workstation Pro下载安装使用教程(免费版)

未经许可,不得转载。 文章目录 下载安装使用(Centos)下载 进入官网页面,注册账户: https://profile.broadcom.com/web/registration注册后登录(用户名为邮箱),选择My Downloads: 如图选择: 如图选择: 如图选择: 如图选择:

嵌入式Linux C应用编程指南-进程、线程(速记版)

第九章 进程 9.1 进程与程序 9.1.1 main()函数由谁调用&#xff1f; C 语言程序总是从 main 函数开始执行&#xff0c;main()函数的原型是&#xff1a; int main(void) 或 int main(int argc, char *argv[])。 操作系统下的应用程序在运行 main()函数之前需要先执行一段引导代…

性能炸裂的数据可视化分析工具:DataEase!【送源码】

今天分享一款开源的数据可视化分析工具&#xff0c;帮助用户快速分析数据并洞察业务趋势&#xff0c;从而实现业务的改进与优化。支持丰富的数据源连接&#xff0c;能够通过拖拉拽方式快速制作图表&#xff0c;并可以方便地与他人分享。 技术栈 前端&#xff1a;Vue.js、Elemen…

【网络基础】探索 NAT 技术:IP 转换、NAPT、NAT穿越及代理服务器

文章目录 1. 前言2. IP 转换过程3. NAPT① 基本概念② 工作原理③ 优缺点④ 实际应用 4. 缺陷5. NAT 穿越① 概述② 示例 6. NAT 与 代理服务器① 代理服务器与NAT的区别&#xff1a;② 正向代理 / 反向代理 服务器 1. 前言 NAT&#xff08;网络地址转换&#xff09;是一种常见…

路由策略工具

1.产生背景 a.保证数据访问的安全性 b.提高链路带宽利用率 c.流量路径不优 2.解决方案: 解决方案一:路由策略:可通过修改路由条目(即对接收和发布的路由进行过滤)来控制流量可达性 解决方案二:流量过滤:可使用Traffic-Filter工具对数据直接进行过滤 3.路由策略工具 a.可利…

登录究竟有多少种花样?

写在最前面&#xff1a; 大家好&#xff0c;我是小....小白不黑&#xff0c;现在的app以及任何一个系统&#xff0c;都离不开登录。其中最常见的估计就是密码登录&#xff0c;二维码登录&#xff0c;第三方账号登录以及单点登录了。 现在&#xff0c;让我们来捋一捋&#xff…

【virtuoso】INV 原理图+前仿真 + 版图 + 后仿真

采用SMIC工艺&#xff0c;不同工艺版图窗口可能有差异 1. 原理图&前仿真 1.1 绘制原理图 PMOS: NMOS宽长比2&#xff1a;1 PMOS开启导通电阻大一点&#xff0c;这样设置&#xff0c;可以使得阈值电压是VDD/2 按 i&#xff0c;可以插入器件按p&#xff0c;可以放置端口 1.2…

AXIS接口教程

免责声明&#xff1a; 本文所提供的信息和内容仅供参考。作者对本文内容的准确性、完整性、及时性或适用性不作任何明示或暗示的保证。在任何情况下&#xff0c;作者不对因使用本文内容而导致的任何直接或间接损失承担责任&#xff0c;包括但不限于数据丢失、业务中断或其他经济…

Unity3D安卓游戏第三方SDK接入

PS&#xff1a;持续更新... 什么是SDK&#xff1f; SDK&#xff08;Software Development Kit&#xff0c;软件开发工具包&#xff09;是一个用于构建应用程序的工具集&#xff0c;包含开发特定软件的必要工具、库、文档和示例代码。SDK通常由软件或硬件厂商提供&#xff0c;帮…

MySQL高阶练习题1- 寻找面试候选人

目录 题目 准备数据 分析数据 实现代码 总结 题目 返回 所有面试候选人 的姓名 name 和邮件 mail 。当用户满足以下两个要求中的 任意一条 &#xff0c;其成为 面试候选人 : 该用户在 连续三场及更多 比赛中赢得 任意 奖牌。该用户在 三场及更多不同的 比赛中赢得 金牌&…

Linux——用户和权限

root用户&#xff08;超级管理员&#xff09; root用户拥有最大的系统操作权限&#xff0c;而普通用户在许多地方的权限是受限的。 ****************** 使用普通用户在根目录下创建文件夹 切换到root用户后&#xff0c;继续尝试 普通用户的权限&#xff0c;一般在其HOME目录…

【linxu】虚拟环境中Python 版本错乱:深入探究 Linux 虚拟环境的识别问题

【linxu】虚拟环境中Python 版本错乱&#xff1a;深入探究 Linux 虚拟环境的识别问题 问题描述&#xff1a;在服务器上&#xff0c;我配置了一个虚拟环境&#xff0c;明确指定使用 Python 3.8 版本。然而&#xff0c;当我激活该环境并检查 Python 版本时&#xff0c;意外地发现…

IO练习--随机点名

随机点名器1 需求: 有一个文件里面存储了班级同学的信息&#xff0c;每一个信息占一行。 格式为:张三-男-23 要求通过程序实现随机点名器。 运行效果: 第一次运行程序:随机同学姓名1(只显示名字) 第二次运行程序:随机同学姓名2(只显示名字) 第三次运行程序:随机同学姓名3(只显…

数学建模强化宝典(2)linprog

一、介绍 linprog 是 MATLAB 中用于解决线性规划问题的函数。线性规划是一种优化方法&#xff0c;它尝试在满足一组线性等式或不等式约束的条件下&#xff0c;找到一个线性目标函数的最大值或最小值。linprog 函数适用于求解形如以下问题的线性规划问题&#xff1a; minimizecT…

Native开发与逆向第六篇 -字符串加密与hook

开发demo 写一个简单的字符串加密处理&#xff0c;将字符串字符转成ASCII十六进制值 std::string StrToHex(std::string str){unsigned char c;char buf[3];std::string result "";std::stringstream ss;ss << str;while (ss.read((char *)(&c), sizeof…

Python数据类型转换背后的逻辑

文末赠免费精品编程资料~~ 今天让我们深入浅出地探索Python数据类型转换的奥秘。Python&#xff0c;作为一门灵活的编程语言&#xff0c;其强大的数据类型转换能力是日常编码中不可或缺的一部分。今天&#xff0c;我们将一步步揭开类型转换背后的逻辑&#xff0c;让你从新手进…