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

网友投稿 338 2022-08-01


目录简介适用场景ApplicationEvent定义event定义listener注册eventCommandLineRunnerApplicationRunner测试执行顺序代码

简介

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

适用场景

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

常用方法

ApplicationEventCommandLineRunnerApplicationRunner

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 {

@Autowired

private MaskingService maskingService;

@Autowired

private RedisCache redisCache;

@Override

public void onApplicationEvent(CacheEvent cacheEvent) {

log.debug("CacheEventListener-start");

List maskings = maskingService.selectAllSysMaskings();

if (!CollectionUtils.isEmpty(maskings)) {

log.debug("CacheEventListener-data-not-empty");

Map> cacheMap = maskings.stream().collect(Collectors.groupingBy(SysMasking::getFieldKey));

cacheMap.keySet().forEach(x -> {

if (StringUtils.isNotEmpty(x)) {

log.debug("CacheEventListener-x={}", x);

List 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.sSvQMhepringframework.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-start2022-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-end2022-04-28 15:44:01.025 DEBUG 1160 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-start2022-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-end2022-04-28 15:44:01.026 DEBUG 1160 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-start2022-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-endDisconnected 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-start2022-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-end2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-start2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-参数=--server.port=90092022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.runner.CacheCommandLineRunner      : CacheCommandLineRunner-end2022-04-28 16:02:05.395 DEBUG 9916 --- [           main] c.r.w.listener.CacheEventListener        : CacheEventListener-start2022-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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring事务的七种传播行为(spring的事务的传播机制)
下一篇:Java实现斗地主与猜数字游戏详细流程(Java实现斗地主)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~