首页 > 其他分享 >在@KafkaListener启动之前需要做数据的预加载,该在Spring生命周期的哪个阶段做这个事情?

在@KafkaListener启动之前需要做数据的预加载,该在Spring生命周期的哪个阶段做这个事情?

时间:2024-01-30 21:55:18浏览次数:28  
标签:拦截器 SmartLifecycle Spring KafkaListener RestTemplate public 加载

背景说明

1、在Spring中消费Kafka数据时,最便捷的方法就是给方法加@KafkaListener注解。在数据消费逻辑中,需要先把一些配置信息预加载到内存中。有同事就提了一个问题:如果保证在消费者执行前,预加载数据的代码一定能执行完? 也就是说,要等待数据预加载完成之后,再执行消费逻辑。

大部分时候,我们在Bean属性赋值之后(afterPropertiesSet)进行数据预加载都是不会有问题的,但是也有特例。特例参考我前面的一篇文章: https://www.cnblogs.com/xushengbin/p/17961565

具体场景

我的数据预加载,是通过RestTemplate调用一个Http接口,请求到数据之后,存入内存中。
RestTemplate结合ribbon实现负载均衡:

@Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.setConnectTimeout(Duration.ofMillis(1000))
                .setReadTimeout(Duration.ofMillis(30000)).build();
    }

如前述文章中所描述:
@LoadBalanced 的原理:在所有bean都初始化完成之后,再给RestTemplate添加一个拦截器。在拦截器中,把URL中的serviceName替换成真实的实例地址。

关键信息:所有bean都初始化完成之后,才会添加拦截器。
也就是说,如果在afterPropertiesSet()中调用RestTemplate,就无法用到负载均衡的效果。因为这时候拦截器还没添加呢。

解决方案

因此,我的问题就变成了: 如何确保在Kafka消费者执行之前,完成“通过@LoadBalanced注解添加拦截器的操作”。

本质就是Spring生命周期的问题。 (现在体会到:不吃透Spring生命周期,你就不能说你掌握了Spring框架)

1、Spring Kafka Consumer的启动时机,是在SmartLifecycle阶段完成的。(https://blog.csdn.net/huangdi1309/article/details/122097034)

2、“通过@LoadBalanced注解添加拦截器的操作” 是在SmartInitializingSingleton阶段(所有Bean实例化完成之后)完成的。

因此呢,我要在这两个阶段之间操作数据预加载操作才行。原因:
1、需要保证在“通过@LoadBalanced注解添加拦截器的操作”之后,调用RestTemplate
2、需要保证在Kafka消费者启动之前,完成数据预加载。

找寻了挺久,通过控制多个SmartLifecycle优先级的方式,可以满足该需求:

@Component
public class ConfigPreLoad implements SmartLifecycle {
    @Autowired
    RestTemplate restTemplate;

    /**
     * 一定要保证该方法在loadBalancedRestTemplateInitializerDeprecated之后执行,并且在@KafkaListener之前执行(通过getPhase()定义优先级)。
     */
    @Override
    public void start() {
        // 调用RestTemplate进行数据预加载
    }

    @Override
    public void stop() {

    }

    @Override
    public boolean isRunning() {
        return false;
    }

    @Override
    public boolean isAutoStartup() {
        return SmartLifecycle.super.isAutoStartup();
    }

    @Override
    public void stop(Runnable callback) {
        SmartLifecycle.super.stop(callback);
    }

    @Override
    public int getPhase() {
        return Integer.MIN_VALUE;
    }
}

关键点是上面的getPhase() 方法,给它设定一个最小的值,就能保证它在Kafka消费者启动之前执行。 由于SmartLifecycle这个阶段是同步的,也就是说,只有等一个SmartLifecycle执行完,才会执行另外一个SmartLifecycle。

补充说明: ApplicationRunner 就是异步的。多个ApplicationRunner会同时执行,不会等待前一个结束。

标签:拦截器,SmartLifecycle,Spring,KafkaListener,RestTemplate,public,加载
From: https://www.cnblogs.com/xushengbin/p/17998070

相关文章

  • Mybatis-plus分页查询(SpringBoot)
    2024-01-30OS:Windows10 22H2IDE:IDEA2022.2.5JDKversion:19Mavenversion:3.6.3数据库:MySQL8.1.0mybatis-plus:3.5.3.1 一、在springBoot启动类中将分页插件加入到ioc容器里面启动类 @SpringBootApplication@MapperScan("com.ssm.mapper")publicclassMain{......
  • springboot集成mqtt
    SpringBoot集成MQTT(简单版)一、docker安装emqx环境(Linux系统)emqx:mqtt服务器(broker)version:'3'services:emqx:image:emqx/emqxcontainer_name:emqxrestart:alwaysports:-8001:18083-8002:1883-8003:8083-8004......
  • springboot项目启动时候初始化一些数据
    最近在看缓存预热的问题的时候,其中有一种解决方法,就是在项目启动的时候就自动加载到缓存中那缓存我就不说了,就关于项目启动的时候,可以初始化一些数据,以下为两种初始化的方式,可以参考1、编写类去实现ApplicationRunner接口,实现run()方法。2、编写类去实现CommandLineRunner接口,......
  • 7000字详解Spring Boot项目集成RabbitMQ实战以及坑点分析
    本文给大家介绍一下在SpringBoot项目中如何集成消息队列RabbitMQ,包含对RibbitMQ的架构介绍、应用场景、坑点解析以及代码实战。最后文末有免费领取龙年红包封面以及腾讯云社区答题领奖福利,欢迎大家领取。我将使用waynboot-mall项目作为代码讲解,项目地址:https://github.co......
  • Java 系统学习 | Springboot 数据验证
    本篇使用Springboot3框架,IDEA2022编辑器,java17版本。在上一篇的基础上进行优化添加依赖在pom.xml中添加依赖,记得更新maven<!--validation依赖--><dependency><groupId>org.springframework.boot</groupId><artifactI......
  • Springboot开发者的福音!免费好用的一站式IDE解决方案来了!SpringToolSuite4登场!
    SpringToolSuite4介绍最近由于工作原因,需要自己编写springboot应用(不是特别复杂),代码量不是很大,但是在选择IDE上却浪费了我很多时间!如果大家跟我一样,在开发springboot应用的过程中遇到如下两个问题:苦于Idea的版权问题讨厌在VisualStudio中安装各种令人头疼的插件那么我们不妨试一下......
  • SpringBoot实现分页的四种方式
    一自己封装Page对象实现二使用sql实现分页2.1场景分析前段传递给给后台什么参数?当前页码currentPage每页显示条数pageSize后台给前端返回什么数据?当前页数据List总记录数totalCount、2.2前段代码<template><el-pagination@size-change="handleSizeChan......
  • SpringBootTest
    引入依赖pom文件中添加以下依赖<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><scope>test</scope>&l......
  • [转]解决Visual Studio 调试时加载符号慢的问题 - zhaotianff - 博客园
    什么是调试符号编译程序时生成的一组特殊字符,并包含有关变量和函数在生成的二进制文件中的位置以及其他服务信息的信息。该数据集可用于逐步调试程序或检查第三方代码。调试符号可以添加到可执行文件或库中,但是大多数现代编译器将它们存储为单独的对象。例如,VisualStudio将调......
  • SpringBoot中集成Minio高性能分布式存储文件服务入门
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662参考上面搭建项目。MinioMinio是基于Go语言编写的对象存储服务,适合于存储大容量非结构化的数据,例如图片、音频、视频、日志文件、备份数据和容器/......