如何在SpringBoot启动时执行初始化操作,两个简单接口就可以实现

简介: 最近遇到一个功能点,数据库中一张很简单的表有一千多条数据,这里的数据主要做到了值域映射的作用,简单来讲就是我可以通过中文名拿到数据库中对应的code值。原本的实现方式是每次用到之后去查一次sql,虽然不会有什么问题,但是只要是走了网络io,都会消耗时间。所以这个方案需要想办法优化。优化的方式其实很简单,数据量不多,一千多条数据放在内存里也占不了多少空间。因此完全可以把一次性把数据加载到内存中,后面只需要每次去内存里调用就可以了。

听说微信搜索《Java鱼仔》会变更强哦!


本文收录于githubgitee ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)概述


最近遇到一个功能点,数据库中一张很简单的表有一千多条数据,这里的数据主要做到了值域映射的作用,简单来讲就是我可以通过中文名拿到数据库中对应的code值。原本的实现方式是每次用到之后去查一次sql,虽然不会有什么问题,但是只要是走了网络io,都会消耗时间。所以这个方案需要想办法优化。


优化的方式其实很简单,数据量不多,一千多条数据放在内存里也占不了多少空间。因此完全可以把一次性把数据加载到内存中,后面只需要每次去内存里调用就可以了。


(二)实现方案


方案想好了就要想实现方式了,想个最直接的方案,在Spring容器初始化时就把这些数据从数据库拿到内存中,后面就直接调用。


SpringBoot中有两个接口能实现该功能:CommandLineRunner和ApplicationRunner。

2.1 CommandLineRunner


首先了解一下CommandLineRunner的基本用法,CommandLineRunner可以在系统启动后执行里面的run方法


@ComponentpublicclassDataPrepareimplementsCommandLineRunner {
@Overridepublicvoidrun(String... args) throwsException {
System.out.println("CommandLineRunner执行数据初始化");
    }
}

如果有多个类的话也可以通过@Order注解指定每个类的执行顺序。


接着就可以写代码的实现了,首先定义一个类用来将Mysql的数据存到内存里,通过静态的Map存储

publicclassDataMap {
publicstaticMap<String, String>map=newHashMap<>();
publicstaticvoidputData(Stringkey, Stringvalue) {
map.put(key, value);
    }
publicstaticStringgetDataByKey(Stringkey) {
returnmap.get(key);
    }
}

接着在DataPrepare类中将数据都存入到静态到Map中。

@ComponentpublicclassDataPrepareimplementsCommandLineRunner {
@AutowiredprivateDataMapperdataMapper;
@Overridepublicvoidrun(String... args) throwsException {
//从数据库中取数据List<DataDO>dataDOS=dataMapper.selectList(Wrappers.emptyWrapper());
//写入到DataMap中dataDOS.forEach(item->DataMap.putData(item.getName(), item.getCode()));
    }
}

要使用到时候,只需要调用DataMap.getDataByKey()方法就可以直接使用了。


2.2 ApplicationRunner


ApplicationRunner和CommandLineRunner的功能十分相似,实现方式也基本相同。同样继承接口,并实现接口的run方法。


@ComponentpublicclassApplicationDataPrepareimplementsApplicationRunner {
@Overridepublicvoidrun(ApplicationArgumentsargs) throwsException {
System.out.println("ApplicationRunner执行数据初始化");
    }
}

在不指定@Order注解的情况下,ApplicationRunner会优先于CommandLineRunner执行。


两者的区别


CommandLineRunner和ApplicationRunner的功能几乎是相同的,最大的区别在于两者run方法中的入参有所不同,CommandLineRunner通过String数组 来接收启动参数,而ApplicationRunner通过一个ApplicationArguments对象来接收。


在使用时,不管是String数组还是ApplicationArguments都可以拿到JVM的启动参数。


(三)源码分析


为什么通过实现一个接口,重写run方法就能达到启动程序后就自动执行代码的功能呢?我们可以通过SpringBoot的源码去看:


点进SpringApplication.run()方法,一直进入到public

ConfigurableApplicationContext run(String... args)方法中,在执行完一系列初始化方法之后,执行了this.callRunners(context, applicationArguments)方法


网络异常,图片无法展示
|


callRunners的方法比较简单,首先定义了一个runners集合,并将需要执行的Bean放进去。可以看到ApplicationRunner和CommandLineRunner在这里被放入了runners中,接着对Order注解进行排序,最后遍历执行。


privatevoidcallRunners(ApplicationContextcontext, ApplicationArgumentsargs) {
List<Object>runners=newArrayList();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
Iteratorvar4= (newLinkedHashSet(runners)).iterator();
while(var4.hasNext()) {
Objectrunner=var4.next();
if (runnerinstanceofApplicationRunner) {
this.callRunner((ApplicationRunner)runner, args);
        }
if (runnerinstanceofCommandLineRunner) {
this.callRunner((CommandLineRunner)runner, args);
        }
    }
}

(四)总结


一个小小的细节可以节约多次的Sql调用。本章主要通过一个简单的例子引出ApplicationRunner和CommandLineRunner,实际在使用时也可以通过懒加载,在第一次使用时将数据塞到静态的Map里,也能实现类似缓存的效果。

相关文章
|
3月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
551 3
|
6月前
|
算法 网络协议 Java
Spring Boot 的接口限流算法
本文介绍了高并发系统中流量控制的重要性及常见的限流算法。首先讲解了简单的计数器法,其通过设置时间窗口内的请求数限制来控制流量,但存在临界问题。接着介绍了滑动窗口算法,通过将时间窗口划分为多个格子,提高了统计精度并缓解了临界问题。随后详细描述了漏桶算法和令牌桶算法,前者以固定速率处理请求,后者允许一定程度的流量突发,更符合实际需求。最后对比了各算法的特点与适用场景,指出选择合适的算法需根据具体情况进行分析。
513 56
Spring Boot 的接口限流算法
|
6月前
|
Java API 网络架构
基于 Spring Boot 框架开发 REST API 接口实践指南
本文详解基于Spring Boot 3.x构建REST API的完整开发流程,涵盖环境搭建、领域建模、响应式编程、安全控制、容器化部署及性能优化等关键环节,助力开发者打造高效稳定的后端服务。
860 1
|
10月前
|
监控 Java Spring
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
353 16
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
372 0
|
存储 算法 安全
SpringBoot 接口加密解密实现
【10月更文挑战第18天】
|
SQL JSON Java
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
本文为Spring Boot增删改查接口的小白入门教程,介绍了项目的构建、配置YML文件、代码编写(包括实体类、Mapper接口、Mapper.xml、Service和Controller)以及使用Postman进行接口测试的方法。同时提供了SQL代码和完整代码的下载链接。
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
389 1
|
前端开发 小程序 Java
【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅
本文详细介绍了如何在SpringBoot项目中统一处理接口返回结果及全局异常。首先,通过封装`ResponseResult`类,实现了接口返回结果的规范化,包括状态码、状态信息、返回信息和数据等字段,提供了多种成功和失败的返回方法。其次,利用`@RestControllerAdvice`和`@ExceptionHandler`注解配置全局异常处理,捕获并友好地处理各种异常信息。
6730 1
【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅

热门文章

最新文章