Spring的Bean生命周期+bean注入+项目启动时正确姿势初始化数据的五种方式

2023-11-09

Spring的Bean生命周期

在Java中万物皆对象,既然是一个实例对象,那么就会有生命历程:被创建–>被使用–>被销毁…但是这说的太过于简洁了,以至于我们根本不能从本质上认清它具体的执行流程、生命历程,今天就来简单了解下Spring中的Bean生命周期具体流程。

我们知道,spring的ioc是创建和管理对象的关键容器,那么项目启动时,一定是spring容器先被创建出来,然后紧接着就是要放入spring容器中管理的各个组件bean,根据机制(是否为懒加载模式)来确定某些bean是否需要在spring容器被创建后立即创建出来进行管理。

总览图

在这里插入图片描述

那么Bean被创建的时候

  1. IOC通过反射机制调用Bean的构造函数(创建完Bean对象)

  2. 进行属性填充,set方法注入等属性注入

  3. 处理各种实现自xxxAware的实现类

  4. 如果bean中设置了@PostConstruct方法,那么开始执行

  5. BeanPostProcessor的postProcessBeforeInitialization()方法执行,前置处理器

  6. 如果bean实现了InitializingBean,重写了afterPropertiesSet(),那么开始执行

  7. 自定义的init方法,如创建Bean时指定的init-method

  8. BeanPostProcessor的postProcessAfterInitialization()方法执行,后置处理器

  9. bean对象被使用

  10. Spring容器销毁

  11. 实现自DisposableBean的bean执行重写的destroy方法

  12. 自定义的销毁方法,destroy-method执行

详解

前两条估计不用说了,先是调用对象的构造函数,然后属性注入执行set方法。

xxxAware

那么第3条,来自xxxAware的实现类目的其实就是让bean获取spring容器中的组件,当我们需要从spring中获取一些组件时可以使用

  • BeanNameAware:获取容器中bean名称
  • BeanFactorAware:获取BeanFactory容器
  • ApplicationContextAware:获取应用上下文

比如有个BeanUtil工具类,通过这个工具类的getBean方法能获取spring中的组件

@Component
public class BeanUtil implements ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    // 对外方法
    public <T> T getBean (Class<T> clazz) {
        return context.getBean(clazz);
    }
}

BeanPostProcessor处理器

BeanPostProcessor的前置和后置处理器:

  • postProcessBeforeInitialization(Object bean, String beanName):当前要被初始化的对象会被传递进来,我们可以对它进行些操作,前置处理
  • postProcessAfterInitialization(Object bean, String beanName):当前已经初始化的对象被传递进来,我们可以对它进行些操作,后置处理

spring中的所有bean在初始化前后都会执行前置和后置的处理器,有点类似是全局方式,比如我创建一个类实现了BeanPostProcessor接口,重写了前置和后置的处理,那么所有的bean初始化前后都会执行它,且方法的返回值可以是bean本身,亦可以是bean的包装类对象(代理对象等),一般使用较少,还是要看项目的实际情况使用

其实像实现一些xxxAwareBeanPostProcessor在bean初始化过程中横插一脚,多数情况下是没有必要的,除非是项目情况需求万不得已,而且实现这些接口将会使我们应用层的代码耦合到spring框架中,会增加耦合度。

项目启动初始化数据+注入bean

上面大概了解下了Bean的整个生命周期流程,再来详细介绍下项目启动时要进行一些初始化数据或者注意一些bean的正确用法。

如何注入bean

刚开始学习spring时,注入一些属性,基本类型多用了@Value,引用类型基本就是在用@Autowired,而在spring中现在已经不建议去使用@Autowired方式了,先来复习下属性注入的几种方式:

  • 属性注入:@Autowired/@Resource
  • 构造函数注入(推荐使用)
  • set方法注入

官方不推荐使用属性注入,属性注入其实有一个显而易见的缺点,那就是对于 IOC 容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。因为该类没有提供该属性的 set 方法或者相应的构造方法来完成该属性的初始化。换言之,要是使用属性注入,那么你这个类就只能在 IOC 容器中使用,要是想自己 new 一下这个类的对象,那么相关的依赖无法完成注入。

当然,他不推荐归为不推荐,各位想用他也拦住啊,O(∩_∩)O哈哈~

个人目前构造方法注入用的多一些,配合lombok的注解,用的嘎嘎爽,给个例子

@RestController
@RequestMapping("/snow/score")
@AllArgsConstructor
public class SnowScoreController {

    private final SnowRefereeService refereeService;
}

项目启动的初始化操作

介绍个场景:项目启动时,需要将数据库中的一些配置信息数据读取出来加载到java的配置类中,完成初始化数据的操作。

列举下可以使用的方式:

  • @PostConstruct: bean中可以使用@PostConstruct来完成初始化,注意:此bean必须被spring管理,且方法必须是无返回值的

    // 翻转到spring中
    @Component
    public class AliyunConfig {
        private String endpoint;
        private String accessKeyId;
        private String accessKeySecret;
        private String bucketName;
        // 阿里云域名(bucket域名或者自定义域名)
        private String aliyunDomain;
    
        @Autowired
        private SystemConfigService configService;
    
        @PostConstruct
        void initProperties() {
            configService.list();
            // 以下完成初始化数据操作
        }
    }
    
  • 也阔以将此Bean通过不同的方式反转到ioc中

    @Data
    class BeanTest {
        private String name;
        @Autowired
        private SystemConfigService configService;
    
        private void setConfigName() {
            System.out.println(configService);
            System.out.println("BeanTest初始化数据");
        }
    }
    
    @Configuration
    @Slf4j
    public class AliyunConfig {
        
        @Bean(initMethod = "setConfigName")
        public BeanTest beanTest () {
            return new BeanTest();
        }
        
    }
    
  • 还可以实现InitializingBean,重写方法

    @Data
    @Component
    class BeanTest implements InitializingBean {
        private String name;
    
        @Autowired
        SystemConfigService systemConfigService;
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("BeanTest初始化");
            System.out.println(systemConfigService);
        }
    }
    
  • 还可以实现ApplicationRunner或者CommandLineRunner,这两个是springboot启动流程中最后被执行的runner,有兴趣可以了解下我的一篇文章Springboot启动流程(源码解析)、自动装配流程(源码解析)、总结、SrpringBoot初始化数据扩展

    @Component
    public class MyInitRunner1 implements ApplicationRunner {
    
        @Autowired
        private DispatcherService dispatcherService;
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println("我是runner1");
            System.out.println(dispatcherService);
        }
    }
    
  • 实现CommandLineRunner

    @Component
    public class MyInitRunner2 implements CommandLineRunner {
    
        @Autowired
        private DispatcherService dispatcherService;
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("我是runner2");
            System.out.println(dispatcherService);
        }
    }
    

最后贴一下几个的优先级:

@PostConstruct > 实现InitializingBean接口 > 实现ApplicationRunnerCommandLineRunner接口

按源码来看,ApplicationRunner的子类执行是优先于CommandLineRunner的子类的,可以通过@Order设置类的加载顺序。

介绍了5种springboot项目启动初始化数据的方式,基本开发中差不多是够用的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring的Bean生命周期+bean注入+项目启动时正确姿势初始化数据的五种方式 的相关文章

  • 查询 MongoDB 集合中的字段。

    我正在尝试查询 mongodb 集合中的特定字段 这是我的代码和输出 Mongo m new Mongo DB db m getDB mydb DBCollection coll db getCollection student addin
  • 迭代函数可以调用自身吗?

    当观看下面的 MIT 6 001 课程视频时 讲师在 28 00 将此算法标记为迭代 但是 在 30 27 他说这个算法和实际的 递归 算法都是递归的 该函数正在使用基本情况调用自身 那么这次迭代情况如何 private int itera
  • 使用 Spring 控制器处理错误 404

    I use ExceptionHandler处理我的网络应用程序抛出的异常 在我的例子中我的应用程序返回JSON回应HTTP status用于对客户端的错误响应 但是 我正在尝试弄清楚如何处理error 404返回与处理的类似的 JSON
  • 无法访问“不安全”java方法的java表达式语言

    我正在开发一个项目 让用户向服务器提交小 脚本 然后我将执行这些脚本 有很多脚本语言可以嵌入到Java程序中 例如mvel ognl uel clojure rhino javascript等 但是 据我所知 它们都允许脚本编写者调用Jav
  • 我需要在 JFileChooser(打开模式)中显示不带扩展名的文件名。如何?

    我在打开模式下使用 JFileChooser 我需要显示不带扩展名的 文件名 字段 如何 我知道文件视图 它删除文件系统文件中的扩展名 但将所选文件中的扩展名保留在 文件名 字段中解释 http saveimg ru show image
  • JavaFX使节点覆盖父节点边框颜色

    我有一个如下所示的节点 仅使用 css 我希望标签覆盖其父边框颜色 因此标签下方的边框颜色部分变得不可见 我用来制作这个边框的CSS代码 fx border color black fx border width 3 fx border r
  • 在java中将字符串日期转换为美国格式

    我有下面的代码 其中日期为字符串类型 我必须将其设置为美国格式 所以下面我已经展示了它 private static final SimpleDateFormat usOutputDate new SimpleDateFormat MM d
  • 确定序列化对象的类型

    我需要通过套接字发送消息 从用户到引擎的请求 以及从引擎到用户的响应 所以流程本质上是 serialized request Server lt network gt Client serialized response request r
  • 纱线上的火花,连接到资源管理器 /0.0.0.0:8032

    我正在我的开发机器 Mac 上编写 Spark 程序 hadoop的版本是2 6 spark的版本是1 6 2 hadoop集群有3个节点 当然都在linux机器上 我在idea IDE中以spark独立模式运行spark程序 它运行成功
  • 在尝试使用 GPS 之前如何检查 GPS 是否已启用

    我有以下代码 但效果不好 因为有时 GPS 需要很长时间 我该如何执行以下操作 检查GPS是否启用 如果启用了 GPS 请使用 GPS 否则请使用网络提供商 如果 GPS 时间超过 30 秒 请使用网络 我可以使用时间或 Thread sl
  • 正确签名的 JNLP 应用程序无法在 Java 7 中运行

    我有一个 JNLP 应用程序 由于证书过期需要更新 我有一个经过 CA 验证的新证书 我已将新证书导入到我的密钥库中 我已导入完整的证书链 我的构建文件对构建中的 jar 进行签名和时间戳
  • 嵌套字段的 Comparator.comparing(...)

    假设我有一个这样的域模型 class Lecture Course course getters class Course Teacher teacher int studentSize getters class Teacher int
  • Java 中 JButton 的击键/热键

    最初我使用 JMenu 并建立热键以使用加速器工作 它运行得很好 现在我想在 JButton 中实现相同的行为 但我陷入困境 这是我编写的代码 请分享您的想法 以便我可以走上正确的道路 import javax swing import j
  • C 与 C++ 中的 JNI 调用不同?

    所以我有以下使用 Java 本机接口的 C 代码 但是我想将其转换为 C 但不知道如何转换 include
  • 当底层连接是有状态时如何使用 Apache HttpClient?

    我在谷歌上搜索了很多关于如何使用 HttpClient 进行多线程处理的信息 他们中的大多数人建议使用 ThreadSafeClientConnManager 但我的应用程序必须登录某个主机 登录表单页面 以便 HttpClient 获得底
  • 如何使用Gson仅从Json反序列化某些特定字段?

    我有以下 JSON 字符串 channel bvmt initValues data value instrumentIds TN0007250012 TN0007500010 instruments mnemonic ADWYA marc
  • 升级到 Spring boot 1.4 后服务无法启动

    我刚刚升级了所有 Spring Boot 服务1 3 6 RELEASE to 1 4 0 RELEASE 现在它们都在启动时崩溃 Caused by java lang NoClassDefFoundError org springfra
  • 在实现使用原始类型的接口时如何避免警告?

    我正在实施流程工厂 http help eclipse org ganymede index jsp topic org eclipse platform doc isv reference api org eclipse debug co
  • 如何建立与 FileZilla Server 1.2.0 的 FTPS 数据连接

    使用 Apache commons net 的 Java FTPSClient 进行会话恢复是一个已知问题 会话恢复是 FTPS 服务器数据连接所需的一项安全功能 Apache FTPSClient 不支持会话恢复 并且 JDK API 使
  • java中void的作用是什么?

    返回类型 方法返回值的数据类型 如果方法不返回值 则返回 void http download oracle com javase tutorial java javaOO methods html http download oracle

随机推荐

  • 服务器虚拟化和桌面虚拟化

    服务器虚拟化和桌面虚拟化依托的都是KVM架构 两者的底层的东西是一样的 只不过是人为的将这个底层系统二次开发成不同的系统版本 有些功能做了限制 有些做了优化 这样的好处是 不同的场景可以使用不同的虚拟化系统 更好的满足客户的需求和发挥不同系
  • 织梦搜索时因关键词标红而导致页面样式错乱的解决方法

    使用织梦默认的搜索功能时 发现搜索某一关键词时 搜索展示页面样式错乱了 经过排查 确定是关键词标红引起的 出现此问题的原因 织梦搜索页面会将搜索关键词进行标红 字体颜色改为红色 处理 在代码中体现出来就是将关键词文字替换为套上font标签的
  • 对华为路由器配置DHCP实现IP地址的自动分配

    目录 0 题目 1 首先按照题意建立如下拓扑图 并划分子网 2 为路由器AR1进行基础设置 1 将系统名称改为r1 2 设置超时时长为0 永不超时 3 为路由器AR1两个接口配置IP地址 1 GE 0 0 0 2 GE 0 0 1 3 检查
  • 处理不同的请求--设置content-type

    content type的作用 在http协议中 content type用来告诉对方本次传输的数据的类型是什么 在请求头中设置content type来告诉服务器 本次请求携带的数据是什么类型的 在响应头中设置content type来告
  • 写在28岁,回看3年前的自己,庆幸当时入了软件测试这行

    为什么会学习软件测试 已经28岁了 算一下快过去3年了 刚毕业那会工作了一年 因为自己当时很迷茫 觉得自己挺废的 所以就没去工作就一直在家 家里固定每个月给点生活费 但还是没钱 但家里给了我一套房子 出门300米左右就是地铁站 自己一个人住
  • Java框架--Spring(轻量级容器框架)(入门+ioc)

    目录 一 概念 海绵hong对于ioc的理解 二 spring快速入门 1 最基本的spring实例 1 1javabean类 1 2beans xml 1 3 ioc容器使用 2 spring 容器结构 机制 2 1beanDefinit
  • kmalloc使用相关

    Kmalloc内存分配和malloc相似 除非被阻塞否则他执行的速度非常快 而且不对获得空间清零 Flags参数 include
  • swin-transformer训练自己的数据集<自留>

    使用swin transformer训练自己的数据集 lt 自留 gt 前期准备 数据处理 标注数据集 一 结构目录 二 要修改的地方 三 开始训练 四 训练过程结果 前期准备 数据处理 标注数据集 LabelMe gt COCO Labe
  • 24岁,月入15000:真正优秀的人,都在做一件事

    昨天 一位经常来转载我文章的编辑朋友找我聊了会 聊完之后 很想写篇文章来谈谈我内心的感受 他告诉我 下个月就要去深圳了 那边有一家公司希望他过去 毕业两年 24岁 月收入稳定在15000 用 年轻有为 来形容他 我觉得并不为过 和他相比起来
  • 服务器系统水星无线网卡,水星设置远程服务器

    水星设置远程服务器 内容精选 换一换 本章节介绍Dubbo框架下DTM使用的demo 使得Dubbo框架下的项目可以通过TCC模式快速接入DTM 其中 Dubbo的样例代码在导入样例工程过程中准备的dtm demo的dtm dubbo项目中
  • Tomcat安装及基本使用

    1 什么是Web服务器 Web服务器是一种应用程序 软件 它封装了对HTTP协议的操作 使得开发人员无需直接操作协议 从而简化了Web开发 其主要功能是提供网上信息浏览服务 Web服务器安装在服务器端 我们可以将自己编写的Web项目部署到W
  • 概率与统计之一 标准差(standard deviation)和标准误(standard error)

    标准差和标准误差 标准差 standard deviation 和标准误差 standard error of mean 根据国际标准化组织 ISO 的定义 标准差 是方差 2的正平方根 而方差是随机变量期望的二次偏差的期望 什么是标准误差
  • 使用Scrapy爬取励志名句————祝万千学子高考顺利

    6月7日 2021年全国高考正式拉开大幕 1078万考生将赶赴考场 迎接人生路上的一次大考 在此 我将使用Scrapy爬取一些励志名句献给广大的高考考生 祝他们高考顺利 学业有成 流程分析 创建项目 创建爬虫程序 进行初始化设置 分析网页并
  • java oj 1035-1045

    1037 四则运算 Switch总是忘记break 输入一个字符 String s input next char ch s charAt 0 除数是0 用 s2 1e 10 即10的 10次方 判断 if Math abs b lt 1e
  • 激光雷达远距离灰尘扬尘烟雾粉尘检测

    最近对激光检测粉尘产生了一点兴趣 于是使用已有的雷达做了检测思路的验证 检测范围可以和雷达的扫描范围一致 约为 0 260m 验证过程使用面粉抛洒 场景如下 红色框就是粉尘的位置 俯视图如下 检测结果如下 绿色范围是检测算法自动框出来的结果
  • 升级Ubuntu18.04的linux kernel(修复小米游戏本的触摸板驱动问题)

    前言 前一段时间换电脑 置换了小米的游戏本 装了ubuntu18 04的系统 demesg发现一直报一个关于i2c接口的错误 473 518316 i2c hid i2c CUST0001 00 i2c hid get input inco
  • 小程序协议篇

    前言 采用的是uniapp的开发框架 引入了mp html的插件做富文本显示插件 操作 打开 富文本编辑 复制粘贴对应的协议文本 直接从word文档或者在线文档复制出来 要带样式的 点击F12或者右键点击检查 进入到Console下面 输入
  • python实现基数排序

    思路 先比较个位数 得到一个新的序列 再按照十位数排序 在上一个新序列的基础上又得到 一个新的序列 然后再按照百位数排序 在上一个新序列的基础上又得到一新的序列 只到排到所有数中的最高位 依次输出列表 排序结束 栗子 例 li 12 90
  • LeetCode 热题 HOT 100:二叉树专题

    LeetCode 热题 HOT 100 https leetcode cn problem list 2cktkvj 文章目录 94 二叉树的中序遍历 递归与非递归 补充 144 二叉树的前序遍历 递归与非递归 补充 145 二叉树的后序遍
  • Spring的Bean生命周期+bean注入+项目启动时正确姿势初始化数据的五种方式

    Spring的Bean生命周期 在Java中万物皆对象 既然是一个实例对象 那么就会有生命历程 被创建 gt 被使用 gt 被销毁 但是这说的太过于简洁了 以至于我们根本不能从本质上认清它具体的执行流程 生命历程 今天就来简单了解下Spri