quarkus依赖注入之十:学习和改变bean懒加载规则

这篇具有很好参考价值的文章主要介绍了quarkus依赖注入之十:学习和改变bean懒加载规则。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本篇是《quarkus依赖注入》系列的第十篇,来看一个容易被忽略的知识点:bean的懒加载,咱们先去了解quarkus框架下的懒加载规则,然后更重要的是掌握如何改变规则,以达到提前实例化的目标
  • 总的来说本篇由以下内容构成
  1. 关于懒加载
  2. 编码体验懒加载
  3. 改变懒加载规则的第一种手段
  4. 改变懒加载规则的第二种手段(居然和官方资料有出入)
  5. 小结

关于懒加载(Lazy Instantiation)

  • CDI规范下的懒加载规则:
  1. 常规作用域的bean(例如ApplicationScoped、RequestScoped),在注入时,实例化的是其代理类,而真实类的实例化发生在bean方法被首次调用的时候
  2. 伪作用域的bean(Dependent和Singleton),在注入时就会实例化
  • quarkus也遵循此规则,接下来编码验证

编码验证懒加载

  • 为了验证bean的懒加载,接下来会写这样一些代码
  1. NormalApplicationScoped.java:作用域是ApplicationScoped的bean,其构造方法中打印日志,带有自己的类名
  2. NormalSingleton.java:作用域是Singleton的bean,其构造方法中打印日志,带有自己的类名
  3. ChangeLazyLogicTest.java:这是个单元测试类,里面注入了NormalApplicationScoped和NormalSingleton的bean,在其ping方法中依次调用上面两个bean的方法
  • 以上就是稍后要写的代码,咱们根据刚刚提到的懒加载规则预测一下要输出的内容和顺序:
  1. 首先,在ChangeLazyLogicTest的注入点,NormalSingleton会实例化,NormalApplicationScoped的代理类会实例化
  2. 然后,在ChangeLazyLogicTest#ping方法中,由于调用了NormalApplicationScoped的方法,会导致NormalApplicationScoped的实例化
  • 接下来开始写代码,第一个bean,NormalApplicationScoped.java
package com.bolingcavalry;

import com.bolingcavalry.service.impl.NormalApplicationScoped;
import com.bolingcavalry.service.impl.NormalSingleton;
import io.quarkus.logging.Log;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;

@QuarkusTest
class ChangeLazyLogicTest {

    @Inject
    NormalSingleton normalSingleton;

    @Inject
    NormalApplicationScoped normalApplicationScoped;

    @Test
    void ping() {
        Log.info("start invoke normalSingleton.ping");
        normalSingleton.ping();
        Log.info("start invoke normalApplicationScoped.ping");
        normalApplicationScoped.ping();
    }
}
  • 第二个bean,NormalSingleton.java
package com.bolingcavalry.service.impl;

import io.quarkus.logging.Log;
import javax.inject.Singleton;

@Singleton
public class NormalSingleton {

    public NormalSingleton() {
        Log.info("Construction from " + this.getClass().getSimpleName());
    }

    public String ping() {
        return "ping from NormalSingleton";
    }
}
  • 然后是单元测试类ChangeLazyLogicTest,可见NormalApplicationScoped构造方法的日志应该在start invoke normalApplicationScoped.ping这一段之后
package com.bolingcavalry;

import com.bolingcavalry.service.impl.NormalApplicationScoped;
import com.bolingcavalry.service.impl.NormalSingleton;
import io.quarkus.logging.Log;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;

@QuarkusTest
class ChangeLazyLogicTest {

    @Inject
    NormalSingleton normalSingleton;

    @Inject
    NormalApplicationScoped normalApplicationScoped;

    @Test
    void ping() {
        Log.info("start invoke normalSingleton.ping");
        normalSingleton.ping();
        Log.info("start invoke normalApplicationScoped.ping");
        normalApplicationScoped.ping();
    }
}
  • 编码完成,运行单元测试类,验证我们之前的预测,控制台输出结果如下图所示,符合预期

quarkus依赖注入之十:学习和改变bean懒加载规则

  • 至此,懒加载基本规则咱们已经清楚了,聪明的您应该想到了此规则的弊端:如果在构造方法中有一些耗时操作,必须等到第一次调用bean的方法时才会执行,这可能不符合我们的预期,有时候我们希望应用初始化的时候把耗时的事情做完,这样执行bean方法的时候就没有影响了
  • 显然,quarkus也意识到了这个问题,于是,给出了两中改变懒加载规则的方法,使得bean的实例化可以更早完成,接下来咱们逐个尝试

改变懒加载规则的第一种手段

  • 让bean尽早实例化的第一种手段,是让bean消费StartupEvent事件,这是quarkus框架启动成功后发出的事件,从时间上来看,此事件的时间比注入bean的时间还要早,这样消费事件的bean就会实例化

  • 咱们给NormalApplicationScoped增加下图红框中的代码,让它消费StartupEvent事件

quarkus依赖注入之十:学习和改变bean懒加载规则
  • 运行代码前,先预测一下修改后的结果
  1. 首先应该是NormalApplicationScoped的实例化
  2. NormalApplicationScoped实例收到StarttupEvent事件,打印日志
  3. 开始注入bean到ChangeLazyLogicTest,引发NormalApplicationScoped代理类和NormalSingleton的实例化
  4. 简单地说:原本最晚实例化的NormalApplicationScoped,由于消费StarttupEvent事件,现在变成了最早实例化的
  • 现在运行代码验证,如下图,符合预期
quarkus依赖注入之十:学习和改变bean懒加载规则

改变懒加载规则的第二种手段(居然和官方资料有出入)

  • 第二种方法更简单了:用StartupEvent修饰类,下图是完整NormalApplicationScoped代码,可见改动仅有红框位置
quarkus依赖注入之十:学习和改变bean懒加载规则
  • 在运行代码前,先预测一下运行结果,理论上应该和第一种手段的结果差不多:NormalApplicationScoped、NormalApplicationScoped代理、NormalSingleton,
  • 上述推测的依据来自Startup源码中的注释,如下图,官方表示StartupEvent和Startup效果一致
quarkus依赖注入之十:学习和改变bean懒加载规则
  • 官方都这么说了,我岂敢不信,不过流程还是要完成的,把修改后的代码再运行一遍,截个图贴到文中,走走过场...

  • 然而,这次运行的结果,却让人精神一振,StartupEvent和Startup效果是不一样的!!!

  • 运行结果如下图,最先实例化的居然不是被Startup注解修饰的NormalApplicationScoped,而是它的代理类!

quarkus依赖注入之十:学习和改变bean懒加载规则
  • 由此可见,Startup可以将bean的实例化提前,而且是连带bean的代理类的实例化也提前了
  • 回想一下,虽然结果与预期不符合,而预期来自官方注释,但这并不代表官方注释有错,人家只说了句functionally equivalent,从字面上看并不涉及代理类的实例化
  • 另外Startup也有自己的独特之处,一共有以下两点
  1. Startup注解的value属性值,是bean的优先级,这样,多个bean都使用Startup的时候,可以通过value值设置优先级,以此控制实例化顺序(实际上控制的是事件observer的创建顺序)
  2. 如果一个类只有Startup注解修饰,而没有设置作用域的时候,quarkus自动将其作用域设置为ApplicationScoped,也就是说,下面这段代码中,ApplicationScoped注解写不写都一样
@ApplicationScoped
@Startup
public class NormalApplicationScoped {

小结

  • 懒加载、StartupEvent、Startup这三种情况下的实例化顺序各不相同,最好是有个对比让大家一目了然,方便选择使用
  • 接下来就画个对比图,图中有懒加载、StartupEvent、Startup三个场景,每个场景都是三个阶段:quarkus框架初始化、注入bean、bean的方法被调用,每个阶段都有哪些对象被实例化就是它们最大的区别,如下所示
quarkus依赖注入之十:学习和改变bean懒加载规则
  • 至此,懒加载相关的知识点学习完毕,个人认为这是个很重要的技能,用好了它对业务有不小的助力,希望能给您一些参考吧

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...文章来源地址https://www.toymoban.com/news/detail-634304.html

到了这里,关于quarkus依赖注入之十:学习和改变bean懒加载规则的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • quarkus依赖注入之三:用注解选择注入bean

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第三篇,前文咱们掌握了创建bean的几种方式,本篇趁热打铁,学习一个与创建bean有关的重要知识点:一个接口如果有多个实现类时,bean实例应该如何选择其中的一个

    2024年02月14日
    浏览(46)
  • quarkus依赖注入之四:选择注入bean的高级手段

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第四篇,在应用中,一个接口有多个实现是很常见的,那么依赖注入时,如果类型是接口,如何准确选择实现呢?前文介绍了五种注解,用于通过配置项、profile等手

    2024年02月14日
    浏览(41)
  • quarkus依赖注入之九:bean读写锁

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇是《quarkus依赖注入》的第九篇,目标是在轻松的气氛中学习一个小技能:bean锁 quarkus的bean锁本身很简单:用两个注解修饰bean和方法即可,但涉及到多线程同步问题,欣宸愿意花更多篇幅与各位

    2024年02月14日
    浏览(39)
  • quarkus依赖注入之二:bean的作用域

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 官方资料:https://lordofthejars.github.io/quarkus-cheat-sheet/#_injection 作为《quarkus依赖注入》系列的第二篇,继续学习一个重要的知识点:bean的作用域(scope),每个bean的作用域是唯一的,不同类型的作用域

    2024年02月15日
    浏览(42)
  • quarkus依赖注入之七:生命周期回调

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇的知识点是bean的生命周期回调:在bean生命周期的不同阶段,都可以触发自定义代码的执行 触发自定义代码执行的具体方式,是用对应的注解去修饰要执行的方法,如下图所示: 有两种模式可以

    2024年02月14日
    浏览(39)
  • quarkus依赖注入之八:装饰器(Decorator)

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇是《quarkus依赖注入》系列的第八篇,目标是掌握quarkus实现的一个CDI特性:装饰器(Decorator) 提到装饰器,熟悉设计模式的读者应该会想到装饰器模式,个人觉得下面这幅图很好的解释了装饰器

    2024年02月14日
    浏览(43)
  • quarkus依赖注入之六:发布和消费事件

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第六篇,主要内容是学习事件的发布和接收 如果您用过Kafka、RabbitMQ等消息中间件,对消息的作用应该不会陌生,通过消息的订阅和发布可以降低系统之间的耦合性,

    2024年02月14日
    浏览(35)
  • quarkus依赖注入之五:拦截器(Interceptor)

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本文是《quarkus依赖注入》系列的第五篇,经过前面的学习,咱们熟悉了依赖注入的基本特性,接下来进一步了解相关的高级特性,先从本篇的拦截器开始 如果您熟悉spring的话,对拦截器应该不会陌

    2024年02月14日
    浏览(52)
  • Springboot依赖注入Bean的三种方式,final+构造器注入Bean

    @Autowired注解的一大使用场景就是Field Injection。 通过Java的反射机制实现,所以private的成员也可以被注入具体的对象 优点 代码少,简洁明了。 新增依赖十分方便,不需要修改原有代码 缺点 容易出现空指针异常。Field 注入允许构建对象实例时依赖的对象为空,导致空指针异常

    2024年02月02日
    浏览(53)
  • 基于Xml方式Bean的配置-Bean的依赖注入以及·自动装配

    Bean的依赖注入方式 注入方式 配置方式 通过Bean的set方法注入 通过构造Bean的方法进行注入 其中,ref是reference的缩写形式,翻译为:涉及,参考的意思,用于引用其它Bean的id,value用于指定属性值 注入数据类型 普通数据类型:String、int、boolean,通过value属性指定 引用数据类型

    2024年02月07日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包