Spring扩展点系列-@PostConstruct

简介

spring的Bean在创建的时候会进行初始化,而初始化过程会解析出@PostConstruct注解的方法,并反射调用该方法。
@PostConstruct 的使用和特点

  • 只有一个非静态方法能使用此注解;
  • 被注解的方法不得有任何参数;
  • 被注解的方法返回值必须为void;
  • 被注解的方法不得抛出已检查异常;
  • 被注解的方法只会被执行一次;
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|
@PostConstruct
InitializingBean afterPropertiesSet
FactoryBean getobject
SmartlnitializingSingleton afterSingletonslnstantiated
CommandLineRunner run
DisposableBeandestroy

源码分析

在Bean创建完成后,进行初始化的过程中,主要包含了初始化的前置、后置处理,以及初始化方法的调用。@PostConstruct注解将在applyBeanPostProcessorsBeforeInitialization这个前置处理

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;//遍历了在spring启动过程中被注册的BeanPostProcessor接口,for (BeanPostProcessor processor : getBeanPostProcessors()) {//调用其前置方法。Object current = processor.postProcessBeforeInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}

@PostConstruct注解是会被一个专门的BeanPostProcessor接口的具体实现类来处理的InitDestroyAnnotationBeanPostProcessor

//org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 元数据解析  注解的初始化方法也会在这里被找到LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {// 触发初始化方法metadata.invokeInitMethods(bean, beanName);}catch (InvocationTargetException ex) {throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());}catch (Throwable ex) {throw new BeanCreationException(beanName, "Failed to invoke init method", ex);}return bean;
}
public void invokeInitMethods(Object target, String beanName) throws Throwable {Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;Collection<LifecycleElement> initMethodsToIterate =(checkedInitMethods != null ? checkedInitMethods : this.initMethods);if (!initMethodsToIterate.isEmpty()) {for (LifecycleElement element : initMethodsToIterate) {if (logger.isTraceEnabled()) {logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());}//  调用element.invoke(target);}}
}

注意:在CommonAnnotationBeanPostProcessor这个后置处理器的构造方法中,@PostConstruct注解被设置为了initAnnotationType的值

//org.springframework.context.annotation.CommonAnnotationBeanPostProcessorpublic CommonAnnotationBeanPostProcessor() {setOrder(Ordered.LOWEST_PRECEDENCE - 3);setInitAnnotationType(PostConstruct.class);setDestroyAnnotationType(PreDestroy.class);ignoreResourceType("javax.xml.ws.WebServiceContext");// java.naming module present on JDK 9+?if (jndiPresent) {this.jndiFactory = new SimpleJndiBeanFactory();}
}

应用场景

@PostConstruct不算一个扩展点,但是也有比较实用的应用场景,主要在Servlet初始化之前加载一些缓存数据,比如

  • 数据字典,
  • 读取properties配置文件

代码示例

@Component
@Slf4j
public class TagPostConstruct {@Autowiredprivate TestAutowired testAutowired;public TagPostConstruct(){log.info("TagPostConstruct构造方法------run");}@PostConstructpublic void myPostConstruct() {log.info("PostConstruct------run");}
}@Slf4j
@Component
public class TestAutowired {public TestAutowired(){log.info("TestAutowired构造方法------run");}
}

运行示例

可以看出@PostConstruct注解在整个Bean初始化中执行的顺序:@Constructor(构造方法)-> @Autowired(依赖注入)-> @PostConstruct(注解的方法);
在这里插入图片描述

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

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

相关文章

行为型设计模式-中介者(mediator)模式-python实现

设计模式汇总&#xff1a;查看 通俗示例 想象一下你正在参与一个团队项目&#xff0c;团队成员包括设计师、前端开发者、后端开发者、测试工程师等。每个团队成员都需要与其他成员沟通协作&#xff0c;比如设计师完成设计后需要通知前端开发者开始开发&#xff0c;前端开发者完…

实际开发中git在IDEA中的使用

相信搜索这个的同学代码都已经拉取到本地了&#xff0c;并且已经在idea中打开了。 1.一般我们从远程colone下来的代码默认是在主分支下的&#xff0c;也就是说我们从远程的主分支拉取的代码并且在本地创建了一个主分支。 2.一般主分支是不允许修改的&#xff0c;所以我们可以基…

Logistic分类算法原理及Python实践

一、Logistic分类算法原理 Logistic分类算法&#xff0c;也称为逻辑回归&#xff08;Logistic Regression&#xff09;&#xff0c;是机器学习中的一种经典分类算法&#xff0c;主要用于解决二分类问题。其原理基于线性回归和逻辑函数&#xff08;Sigmoid函数&#xff09;的组…

SpringBoot2:配置绑定与自动配置功能源码解读

一、配置绑定 1、作用说明 我们在开发springboot项目时&#xff0c;会有个配置文件&#xff0c;application.properties文件。 我们知道&#xff0c;像什么访问端口、上传功能的相关配置&#xff0c;都会在这里进行配置。 而这些&#xff0c;都是springboot自带的或者第三方j…

Linux | 匿名管道和命名管道:进程间通信数据流的桥梁

目录 1、进程间通信目的 2、管道——匿名管道和命名管道 匿名管道 匿名管道的示例代码&#xff1a;将数据写入管道、子进程从管道读取数据并将其输出到bash中 父子进程通过匿名管道建立通信 重点&#xff1a;管道的五个特点 命名管道&#xff08;也称为FIFO&#xff09;…

每日一题,零基础入门FPGA——工程师在线精讲,直播预告

题目传送门&#xff1a;F学社 zzfpga.com/StudentPlatform/Sheet/QuestionBankhttp://zzfpga.com/StudentPlatform/Sheet/QuestionBank 【第Ⅰ期题目 * 5】 请使用D触发器和必要的逻辑门实现此同步时序电路&#xff0c;用Verilog语言描述。 【第Ⅰ期题目 * 4】 请设计一个0…

观测云核心技术揭秘:基于时间的半结构化数据模型

前言 众所周知&#xff0c;真正意义上的统一监控观测平台本质上是一个超大的数据湖&#xff0c;其存储了大量的来自监控指标&#xff0c;各种各样的日志&#xff0c;各种各样的链路追踪以及包括用户访问行为等海量的可观测性数据。 这些海量数据有什么特点呢&#xff1f; 首先…

【网络安全】逻辑漏洞:绕过应用程序重要功能

未经许可,不得转载。 文章目录 正文漏洞影响正文 目标:xxx.com 一个流行的汽车平台,允许用户为经销商留下评论。该平台有一个功能,用户可以点赞评论,并且它限制每个用户对每个评论只能点赞一次。 然而,我找到了绕过的方法(并不是并发)。 在点击“点赞”按钮时拦截请…

新手指南 | 研发人员奖金激励方案步骤实操

研发团队是一个非常独特的存在。在研发人员的薪酬、激励方案设计上也是很多HR的痛点。 毕竟工作变化大&#xff0c;职责变化快、个体能力差异大、投入了不一定会有产出、多线程并行&#xff0c;贡献难判定、知识密度高&#xff0c;价值难衡量等等... 基于以上难点&#xff0c…

【系统架构设计】嵌入式系统设计(1)

【系统架构设计】嵌入式系统设计&#xff08;1&#xff09; 嵌入式系统概论嵌入式系统的组成硬件嵌入式处理器总线存储器I/O 设备与接口 软件 嵌入式开发平台与调试环境交叉平台开发环境交叉编译环境调试 嵌入式系统概论 嵌入性、专用性、计算机系统是嵌入式系统的三个基本的核…

0基础轻松玩转.NET Web API 8.0【CICD】项目实战

1.背景 最近在学习CI/CD&#xff0c;为了加快熟悉CI/CD&#xff0c;我实操了下基于.Net 8.0的CI/CD项目实战。Ci/CD就是自动化作业&#xff0c;实现项目自动编译、发布、执行等&#xff0c;也有用于拉取推送数据的场景。本文主要介绍了在win 11下搭建CI/CD&#xff0c;实现自动…

UEFI——PCD的简单使用

一、PCD的定义及概念 在UEFI固件接口中&#xff0c;PCD&#xff08;Platform Configuration Database&#xff09;是一个用于存储和访问平台特定配置信息的机制。PCD允许UEFI驱动程序和应用程序在运行时获取和设置平台相关的参数&#xff0c;而无需硬编码这些值。PCD变量可以被…

加速电商物流效率:推荐几款实用的快递批量查询工具

做电商必不可少的快递批量查询平台分享&#xff1a;固乔快递查询助手使用全攻略 在电商行业日益竞争的今天&#xff0c;高效管理物流信息成为了商家们不可或缺的一环。面对每天成百上千的订单和快递单号&#xff0c;如何快速、准确地查询并跟踪物流状态&#xff0c;成为了电商…

mysql高可用之组复制

MySQL Group Replication( 简称 MGR ) 是 MySQL 官方于 2016 年 12 月推出的一个全新的高可用与高扩展的解决方案组复制是 MySQL 5.7.17 版本出现的新特性&#xff0c;它提供了高可用、高扩展、高可靠的 MySQL 集群服务MySQL 组复制分单主模式和多主模式&#xff0c;传统的…

请解释Java中的装箱拆箱操作对性能的影响,并讨论其最佳实践。什么是Java中的值传递和引用传递?它们在函数调用中的表现有何不同?

请解释Java中的装箱拆箱操作对性能的影响&#xff0c;并讨论其最佳实践。 在Java中&#xff0c;装箱&#xff08;Boxing&#xff09;和拆箱&#xff08;Unboxing&#xff09;操作是Java自动类型转换机制的一部分&#xff0c;主要用于基本数据类型&#xff08;如int, double, c…

stun和trun

在 WebRTC 中&#xff0c;STUN&#xff08;Session Traversal Utilities for NAT&#xff09;和 TURN&#xff08;Traversal Using Relays around NAT&#xff09;是用于NAT穿透的两种不同的技术&#xff0c;它们解决的问题不同&#xff0c;因此在某些情况下需要同时使用。 ST…

产品需求过程管理重要性

产品需求过程管理重要性 背景 以下都是真实事项经历回顾&#xff0c;在产品开发过程中&#xff0c;产品经理与研发团队之间的沟通至关重要。然而&#xff0c;沟通不畅或信息缺失常常导致需求无法准确传达&#xff0c;最终影响产品的成功。以下是一些常见的问题&#xff1a; 1.需…

C++基础【字符串】(Ac-Wing)

字符串加空格 #include <iostream> #include <cstring> #include <algorithm>using namespace std;int main() {string s;getline (cin, s);for (int i 0; i < s.size(); i )cout << s[i] << " "; }字符串插入 #include<bits/…

js处理echarts tooltip定时轮播

echarts tooltip定时轮播 /*** echarts tooltip轮播* param chart ECharts实例* param chartOption echarts的配置信息* param options object 选项* {* interval 轮播时间间隔&#xff0c;单位毫秒&#xff0c;默认为3000* true表示循环所有series的tooltip…

Electron基础(二) 进程通信的ipcMain、contextBridge、ipcRenderer

1.什么是ipcMain 在 Electron 中&#xff0c;ipcMain是一个非常重要的模块&#xff0c;它负责处理从渲染器进程&#xff08;即 Web 页面&#xff09;发送到主进程&#xff08;即 Electron 应用的后台进程&#xff09;的进程间通信&#xff08;IPC&#xff0c;Inter-Process Co…