Spring中你应该要知道的initMethod

文章目录

  • 功能
  • 源码

功能

之前的文章中由解析过@PostConstruct/@PreDestroy,他们也是initMethod的一种形式,注解方式是后来才加入的,在源码中他们的命名都是一样的名字,都叫initMethod,不过他们却是有着很大的差别,并且他们的执行顺序也不相同,@PostConstruct > afterPropertiesSet >initMethod

xml配置方式,例如:

<bean id="xx" class="xxxxx" init-method="" destroy-method="">

注解配置

@Component
public class CustomConfig7 {

    @PostConstruct
    public void t() {
        System.out.println("customConfig7 init");
    }
    
    @PostConstruct
    public void t2() {
        System.out.println("customConfig7 init2");
    }

    @PreDestroy
    public void d() {
		System.out.println("customConfig7 destroy");
    }
    
    @PreDestroy
    public void d2() {
		System.out.println("customConfig7 destroy2");
    }
}

或者是

@Configuration
public class CustomConfig8 {

    @Bean(initMethod = "initTest", destroyMethod = "destroyTest")
    public CustomTest4 get() {
        return new CustomTest4();
    }
    public static class CustomTest4{

        public void initTest() {
            System.out.println("init 初始化。");
        }

        public void destroyTest() {
            System.out.println("destroy exec");
        }
    }
}

而在之前的文章中,还有一种方式,就是手动构建beanDefinition对象,然后手动设置到定义里面,如:

@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition customBean = new GenericBeanDefinition();
        customBean.setBeanClassName(CustomTest4.class.getName());
        // 设置初始化方法
        customBean.setInitMethodName("initTest");
        // 设置销毁方法
        customBean.setInitMethodName("destroyTest");
        // 设置自定义bean的class
        customBean.setBeanClass(CustomTest4.class);
        // 设置自动注入
        customBean.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        ((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("customTestBean4", customBean);
        // 提前实例化
        Object customTestBean = beanFactory.getBean("customTestBean4");
        System.out.println("自定义bean:" + customTestBean);
    }
}

这最后这一种方法虽然用不到,但是可以作为了解,可以尝试不一样的方法去完成也是不错的。

源码

同样还是bean初始化方法,位置:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

在这里插入图片描述

image-20231222213821105

initMethod方法调用和@PostConstruct是并不是同一个入口,它是在afterPropertiesSet方法调用之后执行的。

if (mbd != null && bean.getClass() != NullBean.class) {
    // 获取initMethod,
    // 就是:customBean.setInitMethodName("initTest");
    // 或者:@Bean(initMethod = "initTest", destroyMethod = "destroyTest")
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
                // 这里排除 InitializingBean.afterPropertiesSet 方法
               
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                 // 和 @PostConstruct 方法
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}

这里的逻辑含义是:

这些初始化回调方法只能执行一次,多次初始化能力赋予,也只能执行一次,且生效的是第一次。

下面进入真正执行的地方:

protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
			throws Throwable {
// 获取设置的initMethod
		String initMethodName = mbd.getInitMethodName();
		Assert.state(initMethodName != null, "No init method set");
    // 获取initMethod的方法对象,因为后面要进行反射操作
    // 这里不管它怎么校验,它都能获取私有方法(private)
    // 总感觉这有点多此一举,可能我没理解到
		Method initMethod = (mbd.isNonPublicAccessAllowed() ?
				BeanUtils.findMethod(bean.getClass(), initMethodName) :
				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));

		if (initMethod == null) {
			if (mbd.isEnforceInitMethod()) {
				throw new BeanDefinitionValidationException("Could not find an init method named '" +
						initMethodName + "' on bean with name '" + beanName + "'");
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("No default init method named '" + initMethodName +
							"' found on bean with name '" + beanName + "'");
				}
				// Ignore non-existent default lifecycle methods.
				return;
			}
		}

		if (logger.isTraceEnabled()) {
			logger.trace("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
		}
    // 这个反射工具是获取更加详细的方法信息,
    // 如果你的这个初始化方法是一个接口方法,那么他会找到你的接口类,这在后面接口判断中可能会有用
		Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);

    // 又是AccessController.doPrivileged ,用于访问特权
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				ReflectionUtils.makeAccessible(methodToInvoke);
				return null;
			});
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
						methodToInvoke.invoke(bean), getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				InvocationTargetException ex = (InvocationTargetException) pae.getException();
				throw ex.getTargetException();
			}
		}
		else {
			try {
                // 一般是走这里的,两边都一样
                // makeAccessible 等效于 initMethod.setAccessible(true)
				ReflectionUtils.makeAccessible(methodToInvoke);
                // 直接反射调用
				methodToInvoke.invoke(bean);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}
	}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java期末复习题之GUI

点击返回标题->23年Java期末复习-CSDN博客 第1题. 一、利用Swing包创建一个窗口&#xff0c;窗口位置为(220,160)、大小为320240&#xff0c;并在窗口(20,80)、(120,80)、(220,80)处各设置一个按钮&#xff0c;按钮大小为80 X 40。 点击左按钮将窗口背景的红色分量增加10&am…

C++哈希表的实现

C哈希表的实现 一.unordered系列容器的介绍二.哈希介绍1.哈希概念2.哈希函数的常见设计3.哈希冲突4.哈希函数的设计原则 三.解决哈希冲突1.闭散列(开放定址法)1.线性探测1.动图演示2.注意事项3.代码的注意事项4.代码实现 2.开散列(哈希桶,拉链法)1.概念2.动图演示3.增容问题1.拉…

互联网+建筑工地源码,基于微服务+Java+Spring Cloud +Vue+UniApp开发

一、智慧工地概念 智慧工地就是互联网建筑工地&#xff0c;是将互联网的理念和技术引入建筑工地&#xff0c;然后以物联网、移动互联网技术为基础&#xff0c;充分应用BIM、大数据、人工智能、移动通讯、云计算、物联网等信息技术&#xff0c;通过人机交互、感知、决策、执行和…

【YOLOV8预测篇】使用Ultralytics YOLO进行检测、分割、姿态估计和分类实践

目录 一 安装Ultralytics 二 使用预训练的YOLOv8n检测模型 三 使用预训练的YOLOv8n-seg分割模型 四 使用预训练的YOLOv8n-pose姿态模型 五 使用预训练的YOLOv8n-cls分类模型 <

序列化和反序列化对比分析,序列化和反序列化输出十个学生信息截图

序列化和反序列化是数据处理中的两个相对的概念&#xff0c;通常用于对象的存储和传输。下面是对这两个过程的对比分析&#xff1a; 序列化&#xff08;Serialization&#xff09; 定义 目的&#xff1a; 将对象的状态信息转换成可以存储或传输的形式&#xff08;如XML, JSO…

算数平均数、调和平均数、几何平均数的计算方法与应用场合

一 定义 1、算数平均数&#xff1a;又称均值&#xff0c;是统计学中最基本&#xff0c;最常用的一种平均指标&#xff0c;分为简单算术平均数、加权算术平均数。 2、调和平均数&#xff1a;又称倒数平均数&#xff0c;是总体各统计变量倒数的算数平均数的倒数。分为数学调和平…

Yolov5水果分类识别+pyqt交互式界面

Yolov5 Fruits Detector Yolov5 是一种先进的目标检测算法&#xff0c;可以应用于水果分类识别任务。结合 PyQT 框架&#xff0c;可以创建一个交互式界面&#xff0c;使用户能够方便地上传图片并获取水果分类结果。以下将详细阐述 Yolov5 水果分类识别和 PyQT 交互式界面的实现…

什么是网络工程师? 就业前景好吗?

互联网发展日渐成熟&#xff0c;所有企业都依赖于网络管理&#xff0c;有企业的地方就需要网络工程师。 在一般人的概念里&#xff0c;网络工程师不过就是通过拨号上网&#xff0c;发个Email&#xff0c;聊聊天&#xff0c;计算机组装与维护&#xff0c;组建局域网就以为是网络…

Node.js安装部署

Node.js安装部署 在 Windows 上安装 Node.js1.使用安装程序2.使用包管理器 Chocolatey 安装 在 macOS 上安装 Node.js1.使用 Homebrew 安装 在 Linux 上安装 Node.js1.使用包管理器安装2.使用 Node.js 官方二进制包 安装完成验证 Node.js 是一个基于 Chrome V8 引擎的 JavaScri…

threejs中修改鼠标cursor不生效的问题修复

需求&#xff1a; 当鼠标hover一个元素时&#xff0c;cursor为自定义的图标 问题描述&#xff1a; threejs中修改canvas的鼠标cursor为自定义的图标不生效。 问题原因&#xff1a; 引入了dragcontrols&#xff0c;查看dragControls的代码&#xff0c;可以看到代码中有对cur…

XPM_CDC_PULSE

MACRO_GROUP: XPM MACRO_SUBGROUP: XPM_CDC 1、Introduction 此宏将源时钟域中的脉冲同步到目标时钟域。源时钟域中任何大小的脉冲&#xff0c;如果正确启动&#xff0c;将生成单个目标时钟周期大小的脉冲。 为了正确操作&#xff0c;输入数据必须由目标时钟采样两次或…

饥荒Mod 开发(二一):超大便携背包,超大物品栏,永久保鲜

饥荒Mod 开发(二十)&#xff1a;显示打怪伤害值 源码 游戏中的物品栏容量实在太小了&#xff0c;虽然可以放在箱子里面但是真的很不方便&#xff0c;外出一趟不容易看到东西都不能捡。实在是虐心。 游戏中的食物还有变质机制&#xff0c;时间长了就不能吃了&#xff0c;玩这个游…

如何在Portainer部署一个web站点到Nginx容器并结合内网穿透远程访问

文章目录 前言1. 安装Portainer1.1 访问Portainer Web界面 2. 使用Portainer创建Nginx容器3. 将Web静态站点实现公网访问4. 配置Web站点公网访问地址4.1公网访问Web站点 5. 固定Web静态站点公网地址6. 固定公网地址访问Web静态站点 前言 Portainer是一个开源的Docker轻量级可视…

大语言模型的三种主要架构 Decoder-Only、Encoder-Only、Encoder-Decoder

现代大型语言模型&#xff08;LLM&#xff09;的演变进化树&#xff0c;如下图&#xff1a; https://arxiv.org/pdf/2304.13712.pdf 基于 Transformer 模型以非灰色显示&#xff1a; decoder-only 模型在蓝色分支&#xff0c; encoder-only 模型在粉色分支&#xff0c; encod…

国际站店铺装修外贸平台alibaba鼠标经过渐变的效果功能代码代码生成器店铺装修旺铺旺铺装修生成器阿里巴巴国际站店铺怎么装修首页进入装修后台自定义内容模块

国际站店铺装修外贸平台alibaba鼠标经过渐变的效果功能代码代码生成器店铺装修旺铺旺铺装修生成器阿里巴巴国际站店铺怎么装修首页进入装修后台自定义内容模块 鼠标经过有个渐变的效果功能

寒风中,新能源汽车续航严重打折,消费者重投燃油车怀抱

统计数据显示&#xff0c;12月12日至12月17日这一周&#xff0c;燃油车销量大幅反弹&#xff0c;燃油车的环比增速远高于新能源汽车领军者比亚迪&#xff0c;似乎显示出消费者再度青睐燃油车&#xff0c;导致如此结果在于新能源汽车在寒冬中的表现让人失望。 一、燃油车销量增速…

python读取Excel内容并展示成json

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 伙伴们&#xff0c;又是许久未曾见面了。最近也是在忙着加班&#xff0c;加上没有新技术的输入和产出&…

Linux Centos-7.5_64bit 系统等保测评内容

一、身份鉴别 a) 应对登录的用户进行身份标识和鉴别&#xff0c;身份标识具有唯一性&#xff0c;身份鉴别信息具有复杂度要求并定期更换 指引&#xff1a;1.观察管理员登录方式。2.查看系统配置&#xff0c;记录配置参数。&#xff08;more /etc/pam.d/system-auth、more /et…

C语言:差分

【模板】差分_牛客题霸_牛客网 (nowcoder.com) 上图中[1,2]4d[0]4,d[1]4,d[2]4,d[3]4...d[2]-4,d[3]-4... [3,3]-2d[2]-2,d[3]-2,d[4]-2....d[3]2,d[4]2... 通过求前缀和操作&#xff0c;相当于用另一个数组完成了差分操作&#xff0c;再将原数组加上该数组&#xff0c;即可得…

HTML+CSS做一个时尚柿子造型计时器

文章目录 💕效果展示💕代码展示HTMLJS💕效果展示 💕代码展示 HTML <!DOCTYPE html> <html lang