【Spring】@PostConstruct详解

news2025/3/13 22:11:28

在 Java 开发中,尤其是在基于 Spring 框架的项目里,我们常常会遇到需要在对象创建并完成依赖注入后,执行一些初始化操作的场景。@PostConstruct注解正是为解决此类问题而诞生的,它为我们提供了一种便捷且优雅的方式来处理对象的初始化逻辑。@PostConstruct是JSR-250规范定义的注解,用于标记在对象构造完成且依赖注入完成后执行的初始化方法。在Spring框架中的执行顺序为:构造函数 -> @Autowired依赖注入 -> @PostConstruct方法 -> Bean初始化完成

一、@PostConstruct 基础概念

@PostConstruct 是 Java EE 提供的JSR-250规范注解,的注解,作用是标记一个方法,该方法会在对象被创建并且依赖注入完成之后,在构造函数执行完毕后自动调用,无需手动调用。这使得我们能够在对象可用之前,完成一些必要的初始化工作,比如加载配置文件、建立数据库连接、初始化缓存等。

在这里插入图片描述

根据官方代码的注释我们可以看出

  1. @PostConstruct 注解用于需要在完成依赖注入后执行以执行任何初始化的方法。
  2. 所有支持依赖关系注入的类都必须支持此注解。就算注解所在的类不请求注入任何资源,也必须调用带有 @PostConstruct 注释的方法。

使用条件:

  • 只有一个方法可以被@PostConstruct 标注注解(经测试,在Springboot环境中不生效,可以多个方法标记)
  • @PostConstruct 注解的方法不能有参数,除非是在拦截器类中,在这种情况下,它采用 Interceptors 规范定义的 InvocationContext 对象。
    如果是拦截器类上定义的话,方法必须具有以下签名:
    1. void <METHOD>(InvocationContext)

    2. Object <METHOD>(InvocationContext) throws Exception

      注意:PostConstruct 拦截器方法不得引发应用程序异常,但如果相同的拦截器方法除了生命周期事件之外还插入到业务或超时方法上,则可以声明它抛出检查异常,包括 java.lang.Exception。如果 PostConstruct 拦截器方法返回一个值,则容器将忽略该值。

  • 在非拦截器的类上@PostConstruct 注解定义的方法返回值必须是void
  • @PostConstruct 注解的方法访问修饰符可以是 public、protected、package private 或 private,即所有访问级别都可以。
  • @PostConstruct 注解的方法不能用static修饰,除了在Application客户端中。
  • @PostConstruct 注解的方法可以final修饰
  • @PostConstruct 注解的方法不能抛出未经检查的异常(unchecked exception)

二、核心原理与执行顺序

执行顺序

在这里插入图片描述

@PostConstruct用于标记在对象构造完成且依赖注入完成后执行的初始化方法。在Spring框架中的执行顺序为:
构造函数 -> @Autowired依赖注入 -> @PostConstruct方法 -> Bean初始化完成 -> destory方法

源码分析

进入@PostConstruct的源码中,发现只有CommonAnnotationBeanPostProcessor这个类的下面方法用到
在这里插入图片描述

这个方法也很简单,就是把这个注解赋值到CommonAnnotationBeanPostProcessor的父类InitDestroyAnnotationBeanPostProcessor中的initAnnotationType字段
在这里插入图片描述

那么字段又在哪里使用呢? 很巧,只有InitDestroyAnnotationBeanPostProcessor中使用,那我们直接看使用的方法

在这里插入图片描述
buildLifecycleMetadata 方法主要做了

  1. 先判断这个类或类中方法或字段是否有initAnnotationTypedestroyAnnotationType注解
  2. 将该类以及所有父类的所有方法initAnnotationTypedestroyAnnotationType注解的方法,作为参数创建LifecycleElement对象并存入currInitMethodscurrDestroyMethods
  3. 把上面的初始化和销毁方法方法作为参数创建LifecycleMetadata对象

通过上面步骤,我们就可以发现,在Spring中有多个初始化方法是不会报错的,相反而是全部存入currInitMethods集合中,并且所有的父类都会存入这个集合,
在这里插入图片描述

其中在第二步创建LifecycleElement对象时,可以神奇的发现这里,如果方法的参数数量不为0就会抛出异常,这就和使用条件中的@PostConstruct 注解的方法不能有参数相对应了。

那么buildLifecycleMetadata方法又在哪里被使用?
在这里插入图片描述

可以看到这个方法主要是从lifecycleMetadataCache中获取某个类的LifecycleMetadata,如果lifecycleMetadataCache为空,那么就调用最开始的方法,否则就会从lifecycleMetadataCache尝试获取,如果获取不到则通过大名鼎鼎的Double-Check方式,也就是双重检索单例模式,并且使用了ConcurrentHashMap,来防止并发问题,ConcurrentHashMap如何防止并发可看相关文章。

三、使用示例

以下通过一个简单的 Spring Boot 项目示例来展示@PostConstruct的用法。

首先,创建一个普通的 Java 类,并在其中定义一个带有@PostConstruct注解的方法:

@Component
@Slf4j
public class PostConstructTest {
    @Autowired
    private UserMapper userMapper;

    public PostConstructTest() {
        log.info("Constructor");
    }

    @PostConstruct
    public void demo1() {
        if (userMapper != null) {
            log.info("autowired");
        }
        log.info("PostConstruct1");
    }

    @PostConstruct
    public void demo2() {
        log.info("PostConstruct2");
    }
}

然后,启动 Spring Boot 应用程序,观察控制台输出:

2025-03-12 22:40:48.529   c.a.mpdemo1010.config.PostConstructTest  : Constructor
2025-03-12 22:40:49.378   c.a.mpdemo1010.config.PostConstructTest  : autowired
2025-03-12 22:40:49.378  c.a.mpdemo1010.config.PostConstructTest  : PostConstruct1
2025-03-12 22:40:49.378   c.a.mpdemo1010.config.PostConstructTest  : PostConstruct2

从输出结果可以清晰地看到,构造函数先被调用,随后@PostConstruct注解的方法被调用。这表明@PostConstruct注解的方法确实是在对象创建和依赖注入完成之后执行的。

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

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

相关文章

OEM SQL Details and Session Details 5s 或者parallel 才会在sql monitor显示

从企业管理器 13.4 版本更新 10 (RU10) 开始&#xff0c;ASH Analytics 的 SQL 详细信息和会话详细信息深入屏幕已更新为使用 Oracle JET UI。 在 Ash Analytics 中&#xff0c;单击左下角区域中“热门 SQL”中的 SQL ID 即可深入了解 SQL 详细信息。 单击右下角“热门会话”区…

JSAR 基础 1.2.1 基础概念_空间小程序

JSAR 基础 1.2.1 基础概念_空间小程序 空间空间自由度可嵌入空间空间小程序 最新的技术进展表明&#xff0c;官网之前的文档准备废除了&#xff0c;基于xsml的开发将退出历史舞台&#xff0c;three.js和普通web结合的技术将成为主导。所以后续学习请移步three.js学习路径&#…

Spring Security的作用

一、概述 Spring Security是一个框架&#xff0c;提供认证&#xff08;authentication&#xff09;、授权&#xff08;authorization&#xff09;和保护&#xff0c;以抵御常见攻击。对 常见漏洞 的保护提供了全面的支持&#xff0c;它对保护命令式和响应式应用程序有一流的支…

数据结构与算法效率分析:时间复杂度与空间复杂度详解(C语言)

1. 算法效率 1.1 如何衡量一个算法的好坏&#xff1f; 在计算机程序设计中&#xff0c;衡量算法优劣的核心标准是效率。但效率不仅指运行速度&#xff0c;还需要综合以下因素&#xff1a; 时间因素&#xff1a;算法执行所需时间 空间因素&#xff1a;算法运行占用的内存空间…

数据类设计_图片类设计之4_规则类图形混合算法(前端架构)

前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 接续上一篇,讨论图片类型设计出来后在场景中如何表达,以及图片的混合算法.前面的内容属于铺垫和基础,这篇内容和实际联系起来了. 背景图和前景图 这里笔者想先…

从零使用docker并安装部署mysql8.3.0容器

在开始使用docker到完成mysql的安装部署&#xff0c;中间有很多的坑等着 安装docker并配置 sudo yum install docker-ce 启动docker并设置开机启动项 sudo systemctl start docker sudo systemctl enable docker查看docker是否启动 sudo systemctl status docker 或者直接…

cpu 多级缓存L1、L2、L3 与主存关系

现代 CPU 的多级缓存&#xff08;L1、L2、L3&#xff09;和主存&#xff08;DRAM&#xff09;构成了一个层次化的内存系统&#xff0c;旨在通过减少内存访问延迟和提高数据访问速度来优化计算性能。以下是对多级缓存和主存的详细解析&#xff1a; 1. 缓存层次结构 现代 CPU 通…

基于Python+SQLite实现校园信息化统计平台

一、项目基本情况 概述 本项目以清华大学为预期用户&#xff0c;作为校内信息化统计平台进行服务&#xff0c;建立网页端和移动端校内信息化统计平台&#xff0c;基于Project_1的需求实现。 本项目能够满足校内学生团体的几类统计需求&#xff0c;如活动报名、实验室招募、多…

[多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现

标题&#xff1a;[多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现 水墨不写bug 文章目录 一、生产者消费者模型特点&#xff1a;二、实现2.1详细解释1. 成员变量2. 构造函数3. Isfull 和 Isempty4. Push 函数5. Pop 函数6. 析构函数7. GetSize 函数 三、总结与多线…

vue组件库el-menu导航菜单设置index,地址不会变更的问题

请先确认 1.路由已配置好 route-index.js如下&#xff0c; 2.view-ProHome.vue中已预留路由展示位 3.导航菜单复制组件库&#xff0c;并做修改 其中index与路由配置的地址一致 运行后发现点击菜单&#xff0c;url地址还是不变&#xff0c;查看组件库 Element - The worlds …

MySQL 优化方案

一、MySQL 查询过程 MySQL 查询过程是指从客户端发送 SQL 语句到 MySQL 服务器&#xff0c;再到服务器返回结果集的整个过程。这个过程涉及多个组件的协作&#xff0c;包括连接管理、查询解析、优化、执行和结果返回等。 1.1 查询过程的关键组件 连接管理器&#xff1a;管理…

智能对话小程序功能优化day1-登录鉴权

目录 1.数据库表构建。 2.完善登录相关的实例对象。 3.登录相关功能实现。 4.小程序效果。 最近尝试下trae加入claude3.7后的读图生成代码功能&#xff0c;可以看到简单的页面一次性生成确实准确率高了不少&#xff0c;想起来之前笔记中开发的智能问答小程序功能还是有些简…

MinIO的预签名直传机制

我们传统使用MinIo做OSS对象存储的应用方式往往都是在后端配置与MinIO的连接和文件上传下载的相关接口&#xff0c;然后我们在前端调用这些接口完成文件的上传下载机制&#xff0c;但是&#xff0c;当并发量过大&#xff0c;频繁访问会对后端的并发往往会对服务器造成极大的压力…

Qt开源控件库(qt-material-widgets)的编译及使用

项目简介 qt-material-widgets是一个基于 Qt 小部件的 Material Design 规范实现。 项目地址 项目地址&#xff1a;qt-material-widgets 本地构建环境 Win11 家庭中文版 VS2019 Qt5.15.2 (MSVC2019) 本地构建流程 克隆后的目录结构如图&#xff1a; 直接使用Qt Crea…

用python批量生成文件夹

问题描述 当批量生成文件夹时&#xff0c;手动右键创建文件夹是一个繁琐的过程&#xff0c;尤其是文件夹的命名过程。假设从3月10日到3月19日&#xff0c;每天要为某个日常工作创建一个名为2025031x的文件夹&#xff0c;手动创建文件夹并命名费时费力。 百度给出了以下四种方法…

【MySQL】基本操作 —— DDL

目录 DDLDDL 常用操作对数据库的常用操作查看所有数据库创建数据库切换、显示当前数据库删除数据库修改数据库编码 对表的常用操作创建表数据类型数值类型日期和时间类型字符串类型 查看当前数据库所有表查看指定表的创建语句查看指定表结构删除表 对表结构的常用操作给表添加字…

游戏引擎学习第152天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾昨天的内容 这个节目展示了我们如何从零开始制作一款完整的游戏。我们不使用任何游戏引擎或库&#xff0c;而是从头开始创建一款游戏&#xff0c;整个开发过程都会呈现给大家。你将能够看到每一行代码的编写&#xff0c;了解…

考研数学非数竞赛复习之Stolz定理求解数列极限

在非数类大学生数学竞赛中&#xff0c;Stolz定理作为一种强大的工具&#xff0c;经常被用来解决和式数列极限的问题&#xff0c;也被誉为离散版的’洛必达’方法&#xff0c;它提供了一种简洁而有效的方法&#xff0c;使得原本复杂繁琐的极限计算过程变得直观明了。本文&#x…

故障诊断——neo4j入门

文章目录 neo4jQuickStartDemo neo4j QuickStart 详情可见博客&#xff1a;https://www.cnblogs.com/nhdlb/p/18703804&#xff0c;使用docker拉取最近的一个版本进行创建 docker run -it -d -p 7474:7474 -p 7687:7687 \ -v /disk5/neo4j_docker/data:/data \ -v /disk5/ne…

【JavaWeb】快速入门——HTMLCSS

文章目录 一、 HTML简介1、HTML概念2、HTML文件结构3、可视化网页结构 二、 HTML标签语法1、标题标签2、段落标签3、超链接4、换行5、无序列表6、路径7、图片8、块1 盒子模型2 布局标签 三、 使用HTML表格展示数据1、定义表格2、合并单元格横向合并纵向合并 四、 使用HTML表单收…