如何在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里,也能实现类似缓存的效果。

相关文章
|
4月前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
96 0
|
1月前
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
50 1
|
2月前
|
存储 安全 Java
|
2月前
|
存储 算法 安全
SpringBoot 接口加密解密实现
【10月更文挑战第18天】
|
2月前
|
监控 Java 开发者
掌握SpringBoot扩展接口:提升代码优雅度的16个技巧
【10月更文挑战第20天】 SpringBoot以其简化配置和快速开发而受到开发者的青睐。除了基本的CRUD操作外,SpringBoot还提供了丰富的扩展接口,让我们能够更灵活地定制和扩展应用。以下是16个常用的SpringBoot扩展接口,掌握它们将帮助你写出更加优雅的代码。
90 0
|
3月前
|
SQL JSON Java
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
本文为Spring Boot增删改查接口的小白入门教程,介绍了项目的构建、配置YML文件、代码编写(包括实体类、Mapper接口、Mapper.xml、Service和Controller)以及使用Postman进行接口测试的方法。同时提供了SQL代码和完整代码的下载链接。
springboot 如何编写增删改查后端接口,小白极速入门,附完整代码
|
3月前
|
存储 前端开发 Java
springboot文件上传和下载接口的简单思路
本文介绍了在Spring Boot中实现文件上传和下载接口的简单思路。文件上传通过`MultipartFile`对象获取前端传递的文件并存储,返回对外访问路径;文件下载通过文件的uuid名称读取文件,并通过流的方式输出,实现文件下载功能。
springboot文件上传和下载接口的简单思路
|
4月前
|
前端开发 小程序 Java
【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅
本文详细介绍了如何在SpringBoot项目中统一处理接口返回结果及全局异常。首先,通过封装`ResponseResult`类,实现了接口返回结果的规范化,包括状态码、状态信息、返回信息和数据等字段,提供了多种成功和失败的返回方法。其次,利用`@RestControllerAdvice`和`@ExceptionHandler`注解配置全局异常处理,捕获并友好地处理各种异常信息。
1905 0
【规范】SpringBoot接口返回结果及异常统一处理,这样封装才优雅
|
3月前
|
存储 数据采集 Java
Spring Boot 3 实现GZIP压缩优化:显著减少接口流量消耗!
在Web开发过程中,随着应用规模的扩大和用户量的增长,接口流量的消耗成为了一个不容忽视的问题。为了提升应用的性能和用户体验,减少带宽占用,数据压缩成为了一个重要的优化手段。在Spring Boot 3中,通过集成GZIP压缩技术,我们可以显著减少接口流量的消耗,从而优化应用的性能。本文将详细介绍如何在Spring Boot 3中实现GZIP压缩优化。
444 6
|
2月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
58 0
下一篇
DataWorks