资讯专栏INFORMATION COLUMN

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

wuyangnju / 970人阅读

摘要:中有两个接口能实现该功能和。首先了解一下的基本用法,可以在系统启动后执行里面的方法执行数据初始化如果有多个类的话也可以通过注解指定每个类的执行顺序。

(一)概述

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

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

(二)实现方案

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

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

2.1 CommandLineRunner

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

@Componentpublic class DataPrepare implements CommandLineRunner {    @Override    public void run(String... args) throws Exception {        System.out.println("CommandLineRunner执行数据初始化");    }}

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

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

public class DataMap {    public static Map<String, String> map = new HashMap<>();    public static void putData(String key, String value) {        map.put(key, value);    }    public static String getDataByKey(String key) {        return map.get(key);    }}

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

@Componentpublic class DataPrepare implements CommandLineRunner {    @Autowired    private DataMapper dataMapper;    @Override    public void run(String... args) throws Exception {        //从数据库中取数据        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方法。

@Componentpublic class ApplicationDataPrepare implements ApplicationRunner {    @Override    public void run(ApplicationArguments args) throws Exception {        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注解进行排序,最后遍历执行。

private void callRunners(ApplicationContext context, ApplicationArguments args) {    List<Object> runners = new ArrayList();    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());    AnnotationAwareOrderComparator.sort(runners);    Iterator var4 = (new LinkedHashSet(runners)).iterator();    while(var4.hasNext()) {        Object runner = var4.next();        if (runner instanceof ApplicationRunner) {            this.callRunner((ApplicationRunner)runner, args);        }        if (runner instanceof CommandLineRunner) {            this.callRunner((CommandLineRunner)runner, args);        }    }}

(四)总结

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/123719.html

相关文章

  • 一个网站的微服务架构实战(1)docker和 docker-compose

    摘要:文件服务器项目为文章共享社区,少不了的就是一个存储文章的文件服务器,包括存储一些图片之类的静态资源。例如数据库的数据文件的配置文件和文件服务器目录。 前言 这是一次完整的项目实践,Angular页面+Springboot接口+MySQL都通过Dockerfile打包成docker镜像,通过docker-compose做统一编排。目的是实现整个项目产品的轻量级和灵活性,在将各个模块的镜像...

    CODING 评论0 收藏0
  • 如何优雅关闭 Spring Boot 应用

    摘要:除了,还有十余种,有的是特定操作,比如转储内存日志有的是信息展示,比如显示应用健康状态。 showImg(http://ww1.sinaimg.cn/large/006tNc79gy1g5qb2coyfoj30u00k0tan.jpg); 前言 随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kil...

    xiyang 评论0 收藏0
  • SpringBoot是这么简单

    摘要:热加载代表的是我们不需要重启服务器,就能够类检测得到,重新生成类的字节码文件无论是热部署或者是热加载都是基于类加载器来完成的。验证阶段字节码文件不会对造成危害准备阶段是会赋初始值,并不是程序中的值。 一、SpringBoot入门 今天在慕课网中看见了Spring Boot这么一个教程,这个Spring Boot作为JavaWeb的学习者肯定至少会听过,但我是不知道他是什么玩意。 只是大...

    whinc 评论0 收藏0
  • Java开发 大厂面试整理

    摘要:用户态不能干扰内核态所以指令就有两种特权指令和非特权指令不同的状态对应不同的指令。非特权指令所有程序均可直接使用。用户态常态目态执行非特权指令。 这是我今年从三月份开始,主要的大厂面试经过,有些企业面试的还没来得及整理,可能有些没有带答案就发出来了,还请各位先思考如果是你怎么回答面试官?这篇文章会持续更新,请各位持续关注,希望对你有所帮助! 面试清单 平安产险 飞猪 上汽大通 浩鲸科...

    Scorpion 评论0 收藏0
  • 超详细,新手都能看懂 !使用SpringBoot+Dubbo 搭建一个简单的分布式服务

    Github 地址:https://github.com/Snailclimb/springboot-integration-examples ,欢迎各位 Star。 目录: 使用 SpringBoot+Dubbo 搭建一个简单分布式服务 实战之前,先来看几个重要的概念 什么是分布式? 什么是 Duboo? Dubbo 架构 什么是 RPC? 为什么要用 Dubbo? 开始实战 1 ...

    chengtao1633 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<