springboot启动加载数据库数据到内存

news/2024/7/24 10:10:07 标签: spring boot, 数据库, 后端

1、概述

一般来说,springboot工程环境配置放在properties文件中,启动的时候将工程中的properties/yaml文件的配置项加载到内存中。但这种方式改配置项的时候,需要重新编译部署,考虑到这种因素,今天介绍将配置项存到数据库表中,在工程启动时把配置项加载到内存中。

springboot提供了两个接口: CommandLineRunner 和 ApplicationRunner 。实现其中接口,就可以在工程启动时将数据库中的数据加载到内存。使用的场景有:加载配置项到内存中;启动时将字典或白名单数据加载到内存(或缓存到Redis中)。

ApplicationRunner 与CommandLineRunner工作方式相同,唯一的区别在于两种方法入参方式不同,实现这两个接口就可以让应用程序代码在启动完成后,接收流量前被调用。如果实现了多次,则必须实现org.springframework.core.Ordered或者使用org.springframework.core.annotation.Order注解来定义他们之间的顺序,@Order(1)数字越小优先级越高

不使用注解@Order执行顺序:

静态代码块 > 构造代码块 > 构造方法(Constructor) > @Autowired > @PostConstruct  > ApplicationRunner > CommandLineRunner

推荐使用: ApplicationRunner 或者 CommandLineRunner方式

springbean初始化流程

st=>start: 开始
op1=>operation: Spring容器加载
op2=>operation: 调用构造函数
op3=>operation: @PostConstruct方法调用
op4=>operation: init()调用
op5=>operation: 其他代码
op6=>operation: destroy()调用
op7=>operation: @PreDestroy方法调用
e=>end: 结束

st->op1->op2->op3->op4->op5->op6->op7->e

静态代码块:仅在类加载时执行一次。

构造代码块:创建一次对象,执行一次

静态方法里不能调用类的实例方法,但可以调用构造方法(因为不需要实例)

2、加载方式

2.1、ApplicationRunner接口

package com.example.demo.config;
 
import com.example.demo.service.ICodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
@Component
@Order(1) // 初始化加载优先级,数字越小优先级越高
public class InitData implements ApplicationRunner {
 
    private static Map<String,Dictionary> dataMap = new HashMap<>();
 
    @Autowired
    private DictionaryDao dictionaryDao;
 
    @Override
    public void run(ApplicationArguments args) throws Exception {
		// 字典信息放到map中
		List<Dictionary> dicList = dictionaryDao.findAllDictionary();
		for(Dictionary dic : dicList){
			dataMap.put(dic.getKey,dic);
		}
    }
	
	// 获取字典信息的具体方法
	public static String getDicDataByKey(String key){
		Dictionary dictionary = dataMap.get(dataMap);
        return dictionary ;
	}
}

 2.2、CommandLineRunner接口

package com.example.demo.config;
 
import com.example.demo.service.ICodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
@Component
@Order(1) // 初始化加载优先级,数字越小优先级越高
public class InitDicData implements CommandLineRunner {
 
    private static Map<String,Dictionary> dataMap = new HashMap<>();
 
    @Autowired
    private DictionaryDao dictionaryDao;
 
    @Override
    public void run(String... args) throws Exception {
		// 字典信息放到map中
        List<Dictionary> dicList = dictionaryDao.findAllDictionary();
		for(Dictionary dic : dicList){
			dataMap.put(dic.getKey,dic);
        }
    }
	
	// 获取字典信息的具体方法
	public static String getDicDataByKey(String key){
		Dictionary dictionary = dataMap.get(dataMap);
        return dictionary ;
	}
}

2.3、@PostConstruct注解

很多人滥用该注解,并且认为该注解是基于Spring的。其实不然,@PostConstruct和@PreDestroy是在Java EE 5引入并且基于Servlet规范, 位于javax.annotation包下,Java最初的设计者认为,这些功能并不是Java核心API,因此就放到了扩展包中。该注解执行的优先级很高,在ApplicationRunner接口之前执行。 

@PostConstruct注解修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的init()方法,被@PostConstruct注解修饰的方法会在构造函数之后,init()方法执行之前执行

被@PreDestroy注解修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法,被@PreDestroy注解修饰的方法会在destroy()方法之后、在Servlet被彻底卸载之前执行

@Component
@Slf4j
public class CacheDicUtils {

    private static Map<String, Dictionary> dataMap = new HashMap<>();

    @Autowired
    private DictionaryDao dictionaryDao;
 
    @PostConstruct
    public void init() { 
        List<Dictionary> list = dictionaryDao.findAllDictionary();
        for (Dictionary dictionary : list) {
            dataMap.put(dictionary.getName(), dictionary);
        }
    }

    @PreDestroy
    public void destroy() {
        log.info("系统启动成功,dataMap加载完成!");
    }
 
    public static Dictionary getDictDataByName(String name) {
        Dictionary dictionary = dataMap.get(name);
        return sysDictionary ;
    }
}

2.4、static静态代码块

public class DicMap {
    @Autowired
    private static DictionaryDao dictionaryDao;
	
    private static HashMap<String,Dictionary> dataMap = new HashMap<>();
	
    static {
        // 在这里我们不能使用注入进来的dictionaryDao,因为它此时还没有被创建出来,所以我们要在系统
        // 运行的时候获取项目的上下文手动去获取这个bean
        dictionaryDao = SpringUtil.getBean(DictionaryDao.class);
        queryDic();
    }
	
    // 把字典信息放到map中
    public static void queryDic(){
        List<Dictionary> dicList = dictionaryDao.findAllDictionary();
		for(Dictionary dic : dicList){
			dataMap.put(dic.getKey,dic);
        }
    }

    // 获取字典信息的具体方法
    public static String getDicDataByKey(String key){
		Dictionary dictionary = dataMap.get(dataMap);
        return dictionary ;
	}

}


http://www.niftyadmin.cn/n/5321391.html

相关文章

双亲委派机制[人话版]

本篇文章仅作为记录学习之用,不具有参考价值. 如果您想系统学习,请移步最下方参考资料. 介绍 今天逛了一下牛客网, 看到有面试问到了双亲委派机制是什么, tomcat有没有打破双亲委派 , 瞬间懵逼, 听都没听过的名字, 听着就稀奇古怪. 然后翻了一下网上的答案,大概了解怎么回事.…

Leetcode202快乐数(java实现)

今天分享的题目是快乐数&#xff1a; 快乐数的定义如下&#xff1a; 快乐数&#xff08;Happy Number&#xff09;是指一个正整数&#xff0c;将其替换为各个位上数字的平方和&#xff0c;重复这个过程直到最后得到的结果为1&#xff0c;或者无限循环但不包含1。如果最终结果为…

操作系统期末提纲

操作系统期末提纲 文章目录 操作系统期末提纲第一章 计算机系统概述第二章 操作系统概述第三章 进程描述和控制第四章 线程第五章 并发性: 互斥和同步第六章 并发性:死锁和饥饿第七章 内存管理第八章 虚拟内存第九章 单处理器调度第十一章 I/O管理和磁盘调度第十二章 文件管理 …

K8S Nginx Ingress Controller client_max_body_size 上传文件大小限制

现象 k8s集群中&#xff0c;上传图片时&#xff0c;大于1M就会报错 413 Request Entity Too Large Nginx Ingress Controller 的版本是 0.29.0 解决方案 1. 修改configmap kubectl edit configmap nginx-configuration -n ingress-nginx在 ConfigMap 的 data 字段中设置参数…

LeetCode 2182. 构造限制重复的字符串,贪心模拟,把控细节

一、题目 1、题目描述 给你一个字符串 s 和一个整数 repeatLimit &#xff0c;用 s 中的字符构造一个新字符串 repeatLimitedString &#xff0c;使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。 返回 字典序最大的 repeatLimitedString 。 …

JavaScript数组全攻略

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ 目录 ✨ 前言 数组的定义 创建数组 1. 数组字面量 2. Array构造函数 3. Array.of() 4. Arra…

小程序适配IOS底部小黑条

1、IOS底部小黑条高34px进行适配 <view class"container-px" style"padding-bottom: {{isIOS ? 68rpx : 0}};"><view class"container-wrap"></view> </view>2、使用css 兼容ios<11.2 padding-bottom: constant(s…

用通俗易懂的方式讲解:如何用大语言模型构建一个知识问答系统

传统搜索系统基于关键字匹配&#xff0c;在面向&#xff1a;游戏攻略、技术图谱、知识库等业务场景时&#xff0c;缺少对用户问题理解和答案二次处理能力。 本文探索使用大语言模型&#xff08;Large Language Model, LLM&#xff09;&#xff0c;通过其对自然语言理解和生成的…