SpringBoot程序预装载数据的实现方法及实践

2023-01-21 0 4,768

目录

简介

项目实际的开发过程中,有时候会遇到需要在应用程序启动完毕对外提供服务之前预先将部分数据装载到缓存的需求。本文就总结了常见的数据预装载方式及其实践。

适用场景

  • 预装载应用级别数据到缓存:如字典数据、公共的业务数据
  • 系统预热
  • 心跳检测:如在系统启动完毕访问一个外服务接口等场景

常用方法

ApplicationEvent

应用程序事件,就是发布订阅模式。在系统启动完毕,向应用程序注册一个事件,监听者一旦监听到了事件的发布,就可以做一些业务逻辑的处理了。

既然是发布-订阅模式,那么订阅者既可以是一个,也可以是多个。

定义event

import org.springframework.context.ApplicationEvent;
public class CacheEvent   extends ApplicationEvent {
    public CacheEvent(Object source) {
        super(source);
    }
}

定义listener

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Component
public class CacheEventListener implements ApplicationListener<CacheEvent> {
    @Autowired
    private MaskingService maskingService;
    @Autowired
    private RedisCache redisCache;
    @Override
    public void onApplicationEvent(CacheEvent cacheEvent) {
        log.debug(\"CacheEventListener-start\");
        List<SysMasking> maskings = maskingService.selectAllSysMaskings();
        if (!CollectionUtils.isEmpty(maskings)) {
            log.debug(\"CacheEventListener-data-not-empty\");
            Map<String, List<SysMasking>> cacheMap = maskings.stream().collect(Collectors.groupingBy(SysMasking::getFieldKey));
            cacheMap.keySet().forEach(x -> {
                if (StringUtils.isNotEmpty(x)) {
                    log.debug(\"CacheEventListener-x={}\", x);
                    List<SysMasking> list = cacheMap.get(x);
                    long count = redisCache.setCacheList(RedisKeyPrefix.MASKING.getPrefix() + x, list);
                    log.debug(\"CacheEventListener-count={}\", count);
                } else {
                    log.debug(\"CacheEventListener-x-is-empty\");
                }
            });
        } else {
            log.debug(\"CacheEventListener-data-is-empty\");
        }
        log.debug(\"CacheEventListener-end\");
    }
}

注册event

@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class BAMSApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(BAMSApplication.class, args);
        log.debug(\"app-started\");
        context.publishEvent(new CacheEvent(\"处理缓存事件\"));
    }
}

CommandLineRunner

通过实现 CommandLineRunner 接口,可以在应用程序启动完毕,回调到指定的方法中。

package com.ramble.warmupservice.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class CacheCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.debug(\"CacheCommandLineRunner-start\");
        log.debug(\"CacheCommandLineRunner-参数={}\", args);
        // 注入业务 service ,获取需要缓存的数据
        // 注入 redisTemplate ,将需要缓存的数据存放到 redis 中
        log.debug(\"CacheCommandLineRunner-end\");
    }
}

ApplicationRunner

同CommandLineRunner 类似,区别在于,对参数做了封装。

package com.ramble.warmupservice.runner;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class CacheApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug(\"CacheApplicationRunner-start\");
        log.debug(\"CacheApplicationRunner-参数={}\", JSON.toJSONString(args));
        // 注入业务 service ,获取需要缓存的数据
        // 注入 redisTemplate ,将需要缓存的数据存放到 redis 中
        log.debug(\"CacheApplicationRunner-end\");
    }
}

测试

上述代码在idea中启动,若不带参数,输出如下:

2022-04-28 15:44:00.981  INFO 1160 --- [           main] c.r.w.WarmupServiceApplication           : Started WarmupServiceApplication in 1.335 seconds (JVM running for 2.231)
2022-04-28 15:44:00.982 DEBUG 1160 --- [           main] c.r.w.runner.CacheApplicationRunner      : CacheApplicationRunner-start
2022-04-28 15:44:01.025 DEBUG 1160 --- [           main] c.r.w.runner.CacheApplicationRunner      : CacheApplicationRunner-参数={"nonOptionArgs":[],"optionNames":[],"sourceArgs":[]}
2022-04-28 15:44:01.025 DEBUG 1160 --- [           main] c.r.w.runner.CacheApplicationRunner      : CacheApplicationRunner-end
2022-04-28 15:44:01.025 DEBUG 1160 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-start
2022-04-28 15:44:01.026 DEBUG 1160 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-参数={}
2022-04-28 15:44:01.026 DEBUG 1160 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-end
2022-04-28 15:44:01.026 DEBUG 1160 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-start
2022-04-28 15:44:01.026 DEBUG 1160 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-参数=ApplicationEvent-->缓存系统数据
2022-04-28 15:44:01.029 DEBUG 1160 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-end
Disconnected from the target VM, address: '127.0.0.1:61320', transport: 'socket'
Process finished with exit code 130

若使用 java -jar xxx.jar --server.port=9009 启动,则输入如下:

2022-04-28 16:02:05.327  INFO 9916 --- [           main] c.r.w.WarmupServiceApplication           : Started WarmupServiceApplication in 1.78 seconds (JVM running for 2.116)
2022-04-28 16:02:05.329 DEBUG 9916 --- [           main] c.r.w.runner.CacheApplicationRunner      : CacheApplicationRunner-start
2022-04-28 16:02:05.393 DEBUG 9916 --- [           main] c.r.w.runner.CacheApplicationRunner      : CacheApplicationRunner-参数={"nonOptionArgs":[],"optionNames":["server.port"],"sourceArgs":["--server.port=9009"]}
2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheApplicationRunner      : CacheApplicationRunner-end
2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-start
2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-参数=--server.port=9009
2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-end
2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-start
2022-04-28 16:02:05.396 DEBUG 9916 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener- 参数=ApplicationEvent-->缓存系统数据
2022-04-28 16:02:05.396 DEBUG 9916 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-end

执行顺序

从上面测试的输出,可以看到三种方式执行的顺序为:
ApplicationRunner--->CommandLineRunner--->ApplicationEvent

另外,若同时定义多个runner,可以通过order来指定他们的优先级。

代码

https://gitee.com/naylor_personal/ramble-spring-cloud/tree/master/warmup-service

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 SpringBoot程序预装载数据的实现方法及实践 http://www.20zxx.cn/463406/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务