Springboot扩展点之@PostConstruct

news2024/12/26 12:21:55

前言

@postContruct全限定类名是javax.annotation.PostConstruct,可以看出来其本身不是Spring定义的注解,但是Spring提供了具体的实现,所以这篇文章主要分析的是@PostConstruct在Spring项目开发中的功能特性、实现方式和基本工作原理。

功能特性

从@PostConstruct注解的注释上看,可以了解到以下内容:

1、要在依赖加载后,对象佤用前执行,并且只执行一次;

2、所有支持依赖注入的类都需要支持此方法。即使类没有请求注入任何的资源,也必须调用被@PostConstruct注解标记的方法;

3、一个类中在一个方法上使用@PostConstruct注解;

4、使用@PostConstruct注解标记的方法不能有参数,除非是拦截器,可以采用拦截器规范定义的InvocationContext对象。

5、使用@PostConstruct注解标记的方法不能有返回值,实际上如果有返回值,也不会报错,但是会忽略掉;

6、使用@PostConstruct注解标记的方法的权限,public、private、protected都可以;

7、使用@PostConstruct注解标记的方法不能被static修饰,但是final是可以的;

package javax.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

在在实际的Spring项目中Bean的生命周期里,其执行的时机是:

1、Bean的实例化;

2、Bean内依赖属性的注入 ;

3、Bean里被@PostConstruct标记的方法;

下面在实现方式里,用一个小例子来验证一下这个过程。

实现方式

1、定义一个ExampleController类,采用setter的依赖注入的方式,注入exampleService属性,另外在定义一个myPostConstruct方法用@PostConstruct注解标记;

@RestController
@Slf4j
public class ExampleController {

    private ExampleService exampleService;

    public ExampleController() {
        log.info("----ExampleController无参数构造方法被执行");
    }
    @Autowired
    public void setExampleService(ExampleService exampleService) {
        this.exampleService = exampleService;
        log.info("----ExampleController类的setExampleService方法被调用");
    }
    @PostConstruct
    public void myPostConstruct(){
        log.info("----ExampleController类的myPostConstruct方法被调用");
    }
}

2、定义ExampleService类

@Service
@Slf4j
public class ExampleService {
    public ExampleService() {
        log.info("----ExampleService的无参数构造方法被调用");
    }
}

3、定义一个单元测试,在单元测试中启动Spring容器;

@Test
public void test4(){
    log.info("----单元测试执行开始");
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
    log.info("----单元测试执行完毕");
}

单元测试验证结果:

从单元测试的执行结果来看,首先,ExampleConstroller被实例化,接着是ExampleService被实例化,然后通过setter依赖注入的方式把ExampleService对象注入到了ExampleConstroller对象中,之后才开始了被@PostConstruct注解标记的myPostConstruct方法的执行。下面就单元测试的结果分析一个@PostConstruct注解的工作原理。

工作原理

@PostConstruct的工作原理的关键问题就是:在Spring容器启动的过程,被@PostConstruct标记的方法是怎么被执行的?

在被@PostConstruct标记的方法上打上断点,待程序执行的断点的时候观察一下方法调用栈信息,这时会发现:

1、Spring容器启动过程的最后一步,即把需要提前注册的一些非懒加载的单例Bean时,如ExampleController,注意这时exampleController对象实例化完成,需要注入的exampleService的属性已经被实例化,且已经注入到exampleController对象中,在BeanPostProcessor接口的扩展方法中,被@PostConstruct标记的方法开始触发执行,入口位置在AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization。

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

那么触发被@PostConstruct注解标记的方法执行的BeanPostProcessor接口的具体是实现是哪个类呢?通过debug分析,是CommonAnnotationBeanPostProcessor类。

2、CommonAnnotationBeanPostProcessor类继承于InitDestroyAnnotationBeanPostProcessor,实际的触发@PostConstruct标记方法执行的入口是在InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization()

3、InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization()内,逻辑相对比较简洁,先查询bean中被@PostConstruct标记的方法,然后再使用java反射来执行这个方法;

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    //查询bean中被@PostConstruct标记的方法,相关的信息封在LifecycleMetadata对象的
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
   try {
    //使用java反射执行被@PostConstruct标记的方法
      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;
}

总结

从以上几步的分析来看,被@PostConstruct标记的方法是怎么被执行的,这个问题回答清楚了。那么如果面试官问你,你了解@PostContruct注解是怎么工作的吗?你就可以这么回答他:在Bean实例化、属性注入后,被@PostConstruct标记的方法是在BeanPostProcessor的扩展方法postProcessBeforeInitialization()触发执行的,具体实现类是InitDestroyAnnotationBeanPostProcessor,具体的逻辑是:先查询被@PostConstruct标记的方法,然后使用java反射去执行这个方法。回答完后,如果他不换一个问题的话,把Springboot的扩展点都给他盘一遍。

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

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

相关文章

Linux c编程之Wireshark

Wireshark是一个网络报文分析软件,是网络应用问题分析必不可少的工具软件。网络管理员可以使用wireshark排查网络问题。程序开发人员可以用来分析应用协议、定位分析应用问题。无论是网络应用程序开发人员、测试人员、部署人员、技术支持人员,掌握wireshark的使用对于分析网络…

【LeetCode】每日一题(2)

目录 题目:1138. 字母板上的路径 - 力扣(Leetcode) 题目的接口: 解题思路: 代码: 过啦!!! 写在最后: 题目:1138. 字母板上的路径 - 力扣&am…

Python-项目实战--贪吃蛇小游戏-游戏框架搭建(2)

1.游戏框架搭建介绍pygame开发图像界面游戏的几个要素,并且把贪吃蛇游戏的整体框架搭建完成本节知识点包括:pygame的初始化和退出游戏主窗口游戏循环和游戏时钟主窗口背景颜色绘制文本pygame的坐标系游戏事件监听绘制图形定时器事件1.1pygame的初始化和退…

RocketMQ5.0.0消息存储<三>_消息转发与恢复机制

目录 一、消息转发 1. ReputMessageService线程初始化 2. 消息转发更新ConsumeQueue 3. 消息转发更新IndexFile 二、恢复机制 1. Broker加载存储文件 2. Broker正常退出的文件恢复 3. Broker异常退出的文件恢复 三、参考资料 一、消息转发 消息消费队列文件、索引文件…

七大设计原则之单一职责原则应用

目录1 单一职责原则介绍2 单一职责原则应用1 单一职责原则介绍 单一职责(Simple Responsibility Pinciple,SRP)是指不要存在多于一个导致类变更的原因。假设我们有一个 Class 负责两个职责,一旦发生需求变更,修改其中…

线程池的简单实现:Java线程池初学者必读指南

"作为一名Java开发者,是否曾经遇到过多线程并发的问题?线程数量过多时,会导致资源浪费,应用性能下降,甚至发生线程死锁的情况。那么,有没有一种方法可以有效地管理线程,避免这些问题呢&…

Matlab傅里叶谱方法求解一维波动方程

傅里叶谱方法求解基本偏微分方程—一维波动方程 一维波动方程 对于一根两端固定、没有受到任何外力的弦, 若只研究其中的一段, 在不太长的时间 里, 固定端来不及对这段弦产生影响, 则可以认为固定端是不存在的, 弦的长度为无限大。 这种无界 (−∞<x<∞)(-\infty<x&…

震源机制(Focal Mechanisms)之沙滩球(Bench Ball)

沙滩球包含如下信息&#xff1a; a - 判断断层类型&#xff0c;可根据球的颜色快速判断 b - 判断断层的走向(strike)&#xff0c;倾角(dip) c - 确定滑移角/滑动角(rake) 走向 &#xff0c;倾角&#xff0c;滑移角 如不了解断层的定义&#xff0c;可以先阅读&#xff1a;震…

windows下qt设置网卡ip信息+简单案列(图形化界面设置网卡IP)。

windows设置网卡ip信息的方法 文章目录windows设置网卡ip信息的方法前言一、QProcess修改网卡ip信息1.1 代码实例二、system修改网卡ip信息2.1 代码实例三、qt修改网卡信息案例3.1 设计方法3.2 代码实例3.3 功能测试前言 方法1&#xff1a;QProcess修改网卡ip信息&#xff1b;…

四种方式的MySQL安装

mysql安装常见的方法有四种序号 安装方式 说明1 yum\rpm简单、快速&#xff0c;不能定制参数2二进制 解压&#xff0c;简单配置就可使用 免安装 mysql-a.b.c-linux2.x-x86_64.tar.gz3源码编译 可以定制参数&#xff0c;安装时间长 mysql-a.b.c.tar.gz4源码制成rpm包 把源码制…

Spring boot 实战指南(四):登录认证(OAuth、Cookie、Session、Token)、Spring Security

文章目录一、登录认证方式1.OAuth 认证颁发令牌的四种方式2.Cookie/Session 认证(1)Cookie(2)Session3.Token认证基于JWT的Token认证(spring security)二、Spring boot整合Spring Security(前后端分离)1.快速入门2.认证3.授权参考&#xff1a; 教程 登录认证简介 OAuth 2.0 的一…

Spring项目中用了这种解耦模式,老大对我刮目相看

前言不知道大家在项目中有没有遇到过这样的场景&#xff0c;根据传入的类型&#xff0c;调用接口不同的实现类或者说服务&#xff0c;比如根据文件的类型使用 CSV解析器或者JSON解析器&#xff0c;在调用的客户端一般都是用if else去做判断&#xff0c;比如类型等于JSON&#x…

Python Web开发:用Tornado框架制作一个简易的网站

前言 大家早好、午好、晚好吖 ❤ ~ 今天我们要用Python做Web开发&#xff0c;做一个简单的【表白墙】网站。 众所周知表白墙的功能普遍更多的是发布找人&#xff0c;失物招领&#xff0c;还是一个大家可以跟自己喜欢的人公开表白的平台 Tornado框架简单介绍 在Python当中&am…

SpringMVC笔记【JavaEE】

SpringMVC 1. SpringMVC概念 Spring MVC 是一个Web 框架。Spring MVC 是基于Servlet API构建的。 MVC是 Model&#xff08;模型&#xff09; View&#xff08;视图&#xff09; Controller&#xff08;控制器&#xff09; 的缩写&#xff0c;它是一种设计模式。 视图分为两种&…

2022年山东省中职组“网络安全”赛项比赛任务书正式赛题

2022年山东省中职组“网络安全”赛项 比赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 Nginx安全策略 A-3 日志监控 A-4 中间件服务加固 A-5 本地安全策略…

html的表单标签(form)

目录标题1、表单标签主要有三大类&#xff1a;2、表单标签中常见的属性3、例子代码及结果4、注意&#xff1a;5、表单中特殊的属性表单标签可以用来数据交互&#xff0c;而前面学的六个标签只能发送不能接收。 表单标签的作用就是数据交互1、表单标签主要有三大类&#xff1a; …

搭建本地私有仓库

目录 一、搭建本地私有仓库 1、首先下载registry镜像 2、在daemon.json文件中添加私有镜像仓库地址 3、运行restart容器 4、为镜像打标签 5、上传到私有仓库 6、列出私有仓库的所有镜像 7、列出私有仓库的centos镜像有哪些tag 8、删除原有的centos的镜像&#xff0c;再测试…

双目测距------双目相机V1.0,将双目相机采集到任意一点的深度数据进行串口传输(带源码)

Depth2Uart 双目测距------双目相机V1.0&#xff0c;将双目相机采集到任意一点的深度数据进行串口传输 一、项目说明/Overview 所实现的功能&#xff1a;基于Intel Realsense官方提供的SDK&#xff0c;双目深度相机能获取到相机任何一个像素点距离前方障碍物的距离&#xff0…

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(三级)答案解析

目录 一、单选题(共25题&#xff0c;共50分) 二、判断题(共10题&#xff0c;共20分) 三、编程题(共3题&#xff0c;共30分) 青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;三级&#xff09; 一、单选题(共25题&#xff0c;共50分) 1. 默认小猫角色…

FlinkCEP - Flink的复杂事件处理

版本说明 本文中以Flink 1.16.1 版本讲解说明 Note:Flink1.16.1版本相较于之前版本增强的within函数&#xff0c; 支持模式序列中相邻事件间的超时定义&#xff0c;以前版本只支持模式序列中第一个事件到最后一个事件之间的最大时间间隔。 快速开始 基于Kafka connecter 流…