【一篇文章理解Java中多级缓存的设计与实现】
文章目录
- 一.什么是多级缓存?
- 1.本地缓存
- 2.远程缓存
- 3.缓存层级
- 4.加载策略
- 二.适合/不适合的业务场景
- 1.适合的业务场景
- 2.不适合的业务场景
- 三.Redis与Caffine的对比
- 1. 序列化
- 2. 进程关系
- 四.各本地缓存性能测试对比报告(官方)
- 五.本地缓存Caffine如何使用
- 1. 引入maven依赖:
- 2.关于Caffine的各api操作介绍
- 六.多级缓存方案与实现思路
- 七.小结
一.什么是多级缓存?
多级缓存技术是一种通过多个层次的缓存来提高数据访问速度和降低延迟的策略。多级缓存通过在不同层次上缓存数据来减少对底层存储系统的访问次数,提高系统的整体性能。在Java中,常见的多级缓存结构包括:本地缓存与远程缓存。
1.本地缓存
Caffeine/Guava/jdk下的线程安全Map等等,因为Caffine性能最高,我这里本地缓存都代指Caffine。在应用程序的内存中存储数据,访问速度极快,但容量有限。
Caffeine是一个基于Java 8的高性能缓存库,它提供了高性能、高命中率、低内存占用的特性,被誉为最快的缓存之一
Caffeine是一个基于Java 8的高性能缓存库,它提供了高性能、高命中率、低内存占用的特性,被誉为最快的缓存之一。
JDK内置的Map可作为缓存的一种实现方式,然而严格意义来讲,其不能算作缓存的范畴。原因如下:一是其存储的数据不能主动过期;二是无任何缓存淘汰策略。
2.远程缓存
如Redis/Memcached:在网络中存储数据,容量大,但访问速度相对较慢。因为我没用过Memcached,这里远程缓存代指Redis。
3.缓存层级
- 一级缓存(本地缓存):直接与应用程序关联,适合频繁访问的数据。
- 二级缓存(远程缓存):作为一级缓存的补充,存储相对较不常访问的数据。
4.加载策略
- 先从本地缓存获取数据,如果不存在,再去远程缓存获取,最后如仍不存在,则从数据库获取并缓存到远程和本地。
这种多级缓存结构能有效提高应用程序性能,降低数据库压力。
二.适合/不适合的业务场景
1.适合的业务场景
Caffeine 适合需要快速访问、短期存储的数据场景,如频繁查询的热点数据、计算结果缓存等,尤其是在高并发环境下表现优异。
它特别适用于以下业务场景:
- 常用数据的枚举值:例如类目数据,这类数据变更频率低,且对实时性要求不高,适合使用Caffeine进行缓存。
- 依赖第三方系统的一些不频繁变更的键值对:先在本地缓存中查找,如果存在则直接返回,不存在则调用第三方系统获取数据并存入本地缓存中。这种模式适用于那些不是经常变化的数据,可以减少对外部系统的依赖,提高系统响应速度。
2.不适合的业务场景
Caffeine不适合实时性要求高或数据变更频繁的场景,对于需要持久存储的数据,或是数据更新频繁且需要实时一致性的场景,就不太适合,因为 Caffeine 的数据是保存在内存中的,可能会导致数据丢失或不一致。因为这些场景对数据的实时性和准确性要求极高,而Caffeine的设计初衷是为了提供高性能的本地缓存,而不是实时同步外部数据源的变化。此外,Caffeine也不适合需要强一致性保证的数据存储,因为它主要关注性能和命中率,而不是数据的一致性。
总的来说,Caffeine适合那些对数据变更频率不高、对实时性要求不是特别严格的应用场景,通过减少对外部数据源的访问次数,提高系统的整体性能和响应速度。
个人认为:其实不单单是我们本地缓存,就是分布式缓存Redis也不适合数据变更频繁的业务场景。引入缓存的本质是为了提高性能减少db操作,但是面对db修改频繁的场景又是引入本地缓存又是分布式缓存,又用其他中间件去解决这个不一致性(更何况哪天你们公司真正高并发起来这个不一致性还无法完全解决,这就是系统的一个坑埋在这了),所以个人觉得db修改频繁就不应该使用缓存!!!
网上人家经常说什么高并发下如何保证缓存与数据库一致性: 比如1.通过延时双删。2.使用canal(增量日志并提供增量数据的订阅与消费)获取到变更数据则更新缓存, 3.使用消息队列等等一系列措施。个人觉得这本来就是个伪命题,高并发下你对数据变更频繁的场景使用缓存真的就合适吗?真正高并发下用了这些,但凡一丁点中间件的网络波动一致性也是无法完全保证的,高并发下缓存与数据库一致性就是个无法完全解不了的问题,只能减少不一致。 当然如果并发量少使用上述的方案基本不会有问题,但是想想我们这个使用缓存+ 中间件的成本真的就比查询一次db低吗。
三.Redis与Caffine的对比
从横向对常用的缓存进行对比,有助于加深对缓存的理解,有助于提高技术选型的合理性。下面对比缓存:Redis、Caffeine。
1. 序列化
- Redis必须实现序列化。进程间数据传输,因此必须实现序列化。大多数情况下涉及内网网络传输;作为缓存数据库使用,持久化是标配。
- Caffeine不需要实现序列化。Map对象的改进型接口,不涉及任何形式的网络传输和持久化,因此完全不需要实现序列化接口。
2. 进程关系
- Redis与业务进程独立,业务系统重启对缓存服务无影响,Redis服务与业务服务独立,互相影响较小
- Caffeine附着于业务进程,业务系统重启缓存数据会全部丢失,纯内存型缓存与业务系统属于同一个JVM
四.各本地缓存性能测试对比报告(官方)
以下是Caffeine官方给出的基准测试结果,在与其他的本地缓存性能对比中身居第一位!。Caffeine的读写性能要远好于Guava,甚至超过不带缓存特性的ConcurrentHashMap。
具体详见官方给出的基本测试报告:https://github.com/ben-manes/caffeine/wiki/Benchmarks-zh-CN
生成计算
在这个 基准测试 中,缓存是无界且被完全填充的,并且生成计算的结果将返回一个常量。这个基准测试体现了生成计算元素的时候将当前元素加锁产生的开销。如果调用不存在,Caffeine 首先会进行一次无锁的预筛选,在进行原子操作。绘图的场景是所有线程对(“sameKey”)进行查询,并基于Zipf在各个线程中查询不同的key(“spread”)。
读 (100%)
在这个基准测试中, 8 线程对一个配置了最大容量的缓存进行并发读。
读 (75%) / 写 (25%)
在这个基准测试 中,对一个配置了最大容量的缓存,6 线程 进行并发读,2 线程进行并发写。
写 (100%)
在这个基准测试 中,8 线程对一个配置了最大容量的缓存进行并发写。
五.本地缓存Caffine如何使用
通过官方的基准测试,所以我们既然要用到本地缓存机制(例如需要用到缓存过期、过期监听、淘汰策略)等,选型那就用性能最厉害的Caffine,它支持多种缓存策略,如基于大小、时间的过期策略等。下面是一些常用的操作 API 及其示例代码。
1. 引入maven依赖:
<!-- 本地缓存 --><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>2.9.3</version></dependency>
2.关于Caffine的各api操作介绍
1. 创建缓存import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;Cache<String, String> cache = Caffeine.newBuilder()// 设置最大缓存条目数.maximumSize(100) // 设置写入后的过期时间.expireAfterWrite(10, TimeUnit.MINUTES) // 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).removalListener(((key,value,cause)->{log.info("缓存失效通知,key:{},原因:{}",key,cause);})).build();
2. 基本的缓存操作,添加、查询、删除缓存值// 存入缓存
cache.put("key1", "value1");// 获取缓存值
String value = cache.getIfPresent("key1");
System.out.println(value); // 输出: value1// 缓存中有key2则返回缓存中的值,缓存中没有key2的值,则通过loadFromDatabase方法从数据库或其他来源加载数据并存入缓存。
String value = cache.get("key2", key -> loadFromDatabase(key));
// 输出从数据库加载的值
System.out.println(value); // 删除某个缓存项
cache.invalidate("key1"); // 清空所有缓存项
cache.invalidateAll(); 3. 异步加载缓存
Caffeine 也支持异步加载缓存,当缓存项不存在时,异步调用加载方法。AsyncCache<String, String> asyncCache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(10, TimeUnit.MINUTES).buildAsync();// 异步获取缓存值
CompletableFuture<String> futureValue = asyncCache.get("key3", key -> loadFromDatabaseAsync(key));// 异步处理获取结果
futureValue.thenAccept(value -> System.out.println("Value: " + value));4. 基于时间的过期策略
Caffeine 支持基于时间的缓存过期机制,如写入后的过期、访问后的过期等。写入后过期
Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES) // 写入后 5 分钟过期.build();访问后过期
Cache<String, String> cache = Caffeine.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES) // 访问后 5 分钟过期.build();
5. 基于缓存大小的淘汰策略
你可以通过 maximumSize 或 maximumWeight 方法设置缓存的大小限制。按照缓存项的数量限制
Cache<String, String> cache = Caffeine.newBuilder().maximumSize(100) // 最多存储 100 条记录.build();按照缓存项的权重限制
Cache<String, String> cache = Caffeine.newBuilder().maximumWeight(1000) // 总权重限制为 1000.weigher((key, value) -> value.length()) // 以值的长度为权重.build();6. 基于软引用或弱引用的缓存
Caffeine 支持使用软引用或弱引用存储缓存值,当 JVM 内存不足时可以自动回收这些缓存。使用弱引用存储键
Cache<String, String> cache = Caffeine.newBuilder().weakKeys() // 使用弱引用存储键.build();使用软引用存储值
Cache<String, String> cache = Caffeine.newBuilder().softValues() // 使用软引用存储值.build();7. 统计缓存命中率
Caffeine 支持记录缓存的命中率、加载时间等统计信息。
Cache<String, String> cache = Caffeine.newBuilder().maximumSize(100).recordStats() // 启用统计信息.build();// 获取统计信息
System.out.println(cache.stats());8. 与 LoadingCache 的结合
LoadingCache 是 Caffeine 提供的一个更高级的缓存操作类,它支持自动同步加载数据的功能。LoadingCache<String, String> loadingCache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(10, TimeUnit.MINUTES).build(key -> loadFromDatabase(key)); // 自动加载缓存// 直接获取缓存值,如果缓存中没有则调用 `loadFromDatabase`
String value = loadingCache.get("key1");
System.out.println(value);
总结:Caffeine 提供了丰富的 API 来满足不同业务场景的缓存需求。它不仅支持基本的缓存操作,还提供了多种淘汰策略、异步缓存以及统计功能,适用于多种场景。
从上面8点中,有没人发现第8点:loadingCache.get(“key1”)与第2点 cache.get(“key2”, key -> loadFromDatabase(key)); 功能基本一致?都是实现缓存中有则从缓存中取,缓存中没有则从db查询并存入缓存中。 只不过是加载逻辑的定义不同,一个是在 build() 时预定义,一个是每次 get() 时传递加载逻辑。
- 何时选择 LoadingCache ?
如果所有的键加载逻辑相同,你可以事先定义加载方式,并希望缓存缺失时自动加载数据,LoadingCache 是理想的选择。它提供了简洁的接口和良好的同步处理。 - 何时选择 Cache.get(key, keyMapper) ?
如果每个键的加载逻辑不同,或你希望在每次获取时灵活指定加载方式,那么 Cache.get(key, keyMapper) 更加合适。它提供了更大的灵活性来动态处理不同的缓存加载需求。 - 两种方案实现缓存中有?从缓存中取 :db查询再塞入缓存,总结:
LoadingCache 适用于需要统一加载策略、且不需要每次都指定加载逻辑的场景。Cache.get(key, keyMapper) 适用于需要根据具体情况动态指定加载逻辑的场景,更加灵活但相对复杂。你可以根据自己的业务场景选择合适的缓存操作方式。
六.多级缓存方案与实现思路
下面是一个简单的多级缓存实现示例,结合了Caffeine作为本地缓存和Redis作为远程缓存。我们在项目里面可以把缓存定义成配置bean, redis可以使用RedisTemplate。 这样一个多级缓存机制就实现啦,是不是很简单。
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import redis.clients.jedis.Jedis;import java.util.concurrent.TimeUnit;public class MultiLevelCache {private final Cache<String, String> localCache;private final Jedis remoteCache;public MultiLevelCache() {// 创建本地缓存CaffinelocalCache = Caffeine.newBuilder()// 设置最大缓存条目数.maximumSize(100) // 设置写入后的过期时间.expireAfterWrite(10, TimeUnit.MINUTES) // 初始的缓存空间大小.initialCapacity(20)// 缓存的最大条数.maximumSize(100).removalListener(((key,value,cause)->{log.info("缓存失效通知,key:{},原因:{}",key,cause);})).build();// Redis连接remoteCache = new Jedis("localhost"); }public String getData(String key) {// 先从本地缓存获取String value = localCache.getIfPresent(key);if (value != null) {return value;}// 本地缓存未命中,尝试从远程缓存获取value = remoteCache.get(key);if (value != null) {// 更新本地缓存localCache.put(key, value); return value;}// 最后从数据库获取(假设为getDataFromDatabase方法)value = getDataFromDatabase(key);// 更新远程和本地缓存remoteCache.set(key, value);localCache.put(key, value);return value;}private String getDataFromDatabase(String key) {// 模拟数据库查询return "DatabaseValueFor:" + key;}
}
七.小结
- 主要介绍了什么是多级缓存:什么是本地缓存、什么是分布式缓存,本地缓存比分布式缓存快的原因。各本地缓存的性能对比中Caffine的性能是最高的,Caffine的Api使用,多级缓存的设计与实现等等。
- 谈到接口性能优化,我们除了sql调优还能从哪些方面优化?ok,当然是多级缓存技术方案啦!合适的业务场景下使用redis配合本地缓存,效率又能提升些。
- 除了缓存技术呢? ok,比如使用数据传输上的压缩,像请求参数,或者使用OpenFeign进行rpc调用响应值等等这些都可以使用GZIP压缩数据传输。 像OpenFeign底层http连接是通过jdk下的URLConnection,我们可以引入Apach 下的HttpClient, 或者okhttp 等,这些底层有用到连接池,可以复用连接等等。这些全都是我们接口性能的一些优化手段。
相关文章:
【一篇文章理解Java中多级缓存的设计与实现】
文章目录 一.什么是多级缓存?1.本地缓存2.远程缓存3.缓存层级4.加载策略 二.适合/不适合的业务场景1.适合的业务场景2.不适合的业务场景 三.Redis与Caffine的对比1. 序列化2. 进程关系 四.各本地缓存性能测试对比报告(官方)五.本地缓存Caffine如何使用1. 引入maven依…...
OpenSource - 开源WAF_SamWaf
文章目录 PreSafeLine VS SamWaf开发初衷软件介绍架构界面主要功能 使用说明下载最新版本快速启动WindowsLinuxDocker 启动访问升级指南自动升级手动升级 在线文档 代码相关代码托管介绍和编译已测试支持的平台测试效果 安全策略问题反馈许可证书贡献代码 Pre Nginx - 集成Mod…...
旅游避坑指南
1.火车站旁白的小摊贩,还有周边的小饭店百分之百是黑店,不仅难吃要死而且巨黑!!! 可以地图上搜索附近的大型商超,例如泰安市的银座商超,里面的东西不仅好吃而且价格透明,还有很多当…...
矩阵系统源码搭建的具体步骤,支持oem,源码搭建
一、前期准备 明确需求 确定矩阵系统的具体用途,例如是用于社交媒体管理、电商营销还是其他领域。梳理所需的功能模块,如多账号管理、内容发布、数据分析等。 技术选型 选择适合的编程语言,如 Python、Java、Node.js 等。确定数据库类型&…...
正则表达式调试工具实战
正则表达式调试工具实战 1、新建工程QWidget工程工程名RegexTool 如果QT不会配置,请参考我的博客,QT配置 Widget.cpp 默认内容如下 2、主界面设计 三行两列,每行采用HBoxLayout作为行布局控件,内部一个Lable控件和一个TextEdit控件,采用VBoxLayout 控件包裹三个HBoxLa…...
SQL:函数以及约束
目录 介绍 函数 字符串函数 数值函数 日期函数 流程函数 约束 总结 介绍 说到函数我们都不陌生,在C,C,java等语言中都有库函数,我们在平时也是经常使用,函数就是一段代码,我们既可以自定义实现,又可以使用库里内置的函数;从来更加简洁方便的完成业务;同样的在SQL中也有…...
在Linux中将设备驱动的地址映射到用户空间
本期主题: MMU的简单介绍,以及如何实现设备地址映射到用户空间 往期链接: Linux内核链表零长度数组的使用inline的作用嵌入式C基础——ARRAY_SIZE使用以及踩坑分析Linux下如何操作寄存器(用户空间、内核空间方法讲解)…...
电脑自带dll修复在哪里,dll丢失的6种解决方法总结
在现代科技日新月异的时代,电脑已经成为我们生活中不可或缺的一部分。然而,在使用电脑的过程中,我们常常会遇到一些常见的问题,其中之一就是dll文件丢失或损坏。当这些dll文件丢失或损坏时,可能会导致某些应用程序无法…...
k8s基于nfs创建storageClass
首先安装nfs #服务端安装 yum install -y nfs-utils rpcbind #客户端安装 yum install -y nfs-utils #启动服务 并设置开启启动 systemctl start rpcbind && systemctl enable rpcbind systemctl start nfs && systemctl enable nfs #创建共享目录 mkdir -p /…...
Chrome无法拖入加载.crx扩展文件(以IDM为例)
问题原因:新版本的Chrome浏览器已不支持加载.crx文件 解决办法:将.crx文件压缩为.zip文件,解压缩后再加载到Chrome中 以IDM的.crx文件作为示例; IDM的.crx文件位于C:\Program Files (x86)\Internet Download Manager; 将IDMGCE…...
数字教学时代:构建高效在线帮助中心的重要性
在数字化教学日益普及的今天,教育领域正经历着前所未有的变革。随着在线课程、虚拟教室、智能学习平台等数字化工具的广泛应用,教育资源的获取方式和学习模式发生了深刻变化。然而,这种变革也带来了新的挑战,其中之一便是如何确保…...
828华为云征文|华为云弹性云服务器FlexusX实例下的Nginx性能测试
本文写的是华为云弹性云服务器FlexusX实例下的Nginx性能测试 目录 一、华为云弹性云服务器FlexusX实例简介二、测试环境三、测试工具四、测试方法五、测试结果 下面是华为云弹性云服务器FlexusX实例下的Nginx性能测试。 一、华为云弹性云服务器FlexusX实例简介 华为云弹性云服…...
知识图谱入门——2:技术体系基本概念:知识表示与建模、知识抽取与挖掘、知识存储与融合、知识推理与检索
知识图谱是通过构建“实体”和“关系”来描述世界的信息网络,它不仅是数据的存储方式,还可以支持推理与查询,帮助系统更好地理解、整合和利用数据。 文章目录 1. 知识表示与建模2. 知识抽取与挖掘3. 知识存储与融合4. 知识推理与检索总结 1.…...
【不看会后悔系列】排序之——文件归并【史上最全详解】~
文章目录 前言一、何为文件归并?二、文件归并思路分析三、创造多数据文件四、前置准备——堆排序五、两个文件写入到第三个文件六、读 N 个数据返回给文件,并返回读到数据的个数七、文件归并八、文件归并完整代码总结1. 运行代码2. 运行截图 总结 前言 学习了归并排…...
安全点的应用场景及其原理详解
引言 在Java虚拟机(JVM)运行的过程中,有些时刻,系统需要暂停所有正在运行的线程,以执行某些全局操作或确保数据的一致性。这些暂停线程的时刻被称为**“安全点”**(Safepoint)。尽管安全点最广…...
计算机各专业2025毕业设计选题推荐【各专业 | 最新】
计算机各专业2025毕业设计选题推荐 Java、Python、Vue、PHP、小程序、安卓、大数据、爬虫、可视化、机器学习、深度学习 文末有联系方式~~~ 1.Java 基于Java的在线购物系统设计与实现Java开发的图书管理系统基于Spring Boot的社交媒体平台Java实现的移动健康应用在线学习平…...
【Python报错已解决】IndexError: index 0 is out of bounds for axis 1 with size 0
🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…...
SpringGateway(网关)微服务
一.启动nacos 1.查看linux的nacos是否启动 docker ps2.查看是否安装了nacos 前面是你的版本,后面的names是你自己的,我们下面要启动的就是这里的名字。 docker ps -a3.启动nacos并查看是否启动成功 二.创建网关项目 1.创建idea的maven项目 2.向pom.x…...
jQuery面试题:(第三天)
8.你在jQuery中使用过哪些插入节点的方法,它们的区别是什么? 答:append(),appendTo(),prepend(),prependTo(),after(),insertAfter() before(),insertBefore() 内添加 1.append()在文档内添加元素 2.appendTo()把匹配的元素添加到对象里 3.prepend()…...
聊聊国内首台重大技术装备(2)
上次,介绍了《首台(套)重大技术装备推广应用指导目录(2024年版)》中介绍的硅外延炉,湿法清洗机,氧化炉,见文章: 《聊聊国内首台重大技术装备(1)》…...
python 实现rayleigh quotient瑞利商算法
rayleigh quotient瑞利商算法介绍 瑞利商(Rayleigh Quotient)算法在多个领域,如线性代数、计算机视觉和机器学习等,都有重要的应用。瑞利商定义为函数 R ( A , x ) ( x H A x ) / ( x H x ) R(A, x) (x^H Ax) / (x^H x) R(A,x)…...
Java Web应用升级故障案例解析
在一次Java Web应用程序的优化升级过程中,从Tomcat 7.0.109版本升级至8.5.93版本后,尽管在预发布环境中验证无误,但在灰度环境中却发现了一个令人困惑的问题:新日志记录神秘“失踪”。本文深入探讨了这一问题的排查与解决过程&…...
Java类和对象、自定义包、static、代码块、方法重写
目录 1.类和对象 2.this指针 3.对象的构造和初始化 3.1默认初始化 3.2就地初始化 3.3构造初始化 3.4IDEA快速填充 3.5使用this简化 3.6初始化的总结 4.包的引入 4.1包的概念 4.2导入包中的类 4.3自定义包 5.static修饰 6.代码块的划分 7.方法重写 1.类和对象 使…...
【系统代码】招投标采购一体化管理系统,JAVA+vue
前言: 随着互联网和数字技术的不断发展,企业采购管理逐渐走向数字化和智能化。数字化采购平台作为企业采购管理的新模式,能够提高采购效率、降低采购成本、优化供应商合作效率,已成为企业实现效益提升的关键手段。系统获取在文末…...
基于yolov8深度学习的120种犬类检测与识别系统python源码+onnx模型+评估指标曲线+精美GUI界面目标检测狗类检测犬类识别系统
【算法介绍】 基于YOLOv8深度学习的120种犬类检测与识别系统是一款功能强大的工具,该系统利用YOLOv8深度学习框架,通过21583张图片的训练,实现了对120种犬类的精准检测与识别。 该系统基于Python与PyQt5开发,具有简洁的UI界面&a…...
UNI-APP_iOS开发技巧之:跳转到TestFlight或者App Store
有的时候我们的应用可能需要上TestFlight或者App Store,更新升级就需要跳到TestFlight里面。方法如下: 跳转到TestFlight: itms-beta://itunes.apple.com/app/你的AppID 跳转到AppStore: itms-apps://itunes.apple.com/app/你的AppIDhttps://airp…...
基于SSM+Vue技术的定制式音乐资讯平台
文未可获取一份本项目的java源码和数据库参考。 一、选题的背景与意义: 随着个人计算机的普及和互联网技术的日渐成熟,网络正逐渐成为人们获取信息及消费的主要渠道。然而在当前这个信息时代,网络中的信息种类和数量呈现爆炸性增长的趋势&a…...
Spring依赖注入和注解驱动详解和案例示范
在 Spring 框架中,依赖注入(Dependency Injection, DI)和注解驱动(Annotation-Driven)是其核心机制,它们为 Spring 应用提供了灵活性和可扩展性。依赖注入简化了对象间的依赖管理,而注解驱动则通…...
网络通信——OSPF协议(基础篇)
这里基础是因为没有讲解OSPF中的具体算法过程,以及其中很多小细节。后续会更新。 目录 一.OSPF的基础信息 二.认识OSPF中的Router ID 三.OSPF中的三张表 四.OSPF中的度量方法(计算开销值) 五. OSPF选举DR和BDR(就是这个区域…...
Kubernetes从零到精通(15-安全)
目录 一、Kubernetes API访问控制 1.传输安全(Transport Security) 2.认证(Authentication) 2.1 认证方式 2.2 ServiceAccount和普通用户的区别 2.3 ServiceAccount管理方式 自动ServiceAccount示例 手动ServiceAccount示例 3.鉴权 (Authorization) 3.1鉴权方式 3.2 …...
做伊瑞尔竞技场的网站/网络营销的概述
解决方案: 1、尝试用绝对函数方法调用: 如 local a A.a or {}; function a:Max(pa, pb) end--使用方法: A.a:Max(1,2); 2.那就还说明一个问题,该函数没注册上,看看是不是写函数时头文件未包含,又或者敲代…...
做音响的是哪个网站/网络安全培训机构哪家好
描述 外星人逐渐逼近,为了保护地球,现在决定直接在外空进行战斗。 现在我们有N个导弹。需要在最短的时间内,用这N个导弹摧毁敌方n个目标(1个导弹只能摧毁1个目标)。N个导弹和目标的位置不一定相同,但是给每个导弹确定目标是一件很…...
廊坊网站设计公司/网站开发需要的技术
打开项目的jar包,发现这个类是空的(如下图) 于是在网上找了相关的资料,发现原本这个类是包含在xalan.jar中的,但是xalan-j2.7.0版的发布包中,将serializer包中的类单独打包成serializer.jar,不再…...
国外做美食的网站有哪些/南京seo网站优化推广
[tips2] 文/superhei 05-02-10 1.不要错误判断(特殊字符)的sql注射 经典方法: id1 and 12 union select 1,1,1,1,1,1,1 再根据特殊字符判断 我们知道当上面的字段前后一样时,查询出来的字段数据都被1替换了,这里用可以把1改为一个特殊点的数字…...
深圳58同城网站建设/网站搜什么关键词
转载自:Java开发人员最常犯的10个错误 一、把数组转成ArrayList 为了将数组转换为ArrayList,开发者经常会这样做:List<String> list Arrays.asList(arr);使用Arrays.asList()方法可以得到一个ArrayList,但是得到这个Array…...
如何做自己网站平台/搜索大全浏览器
很多人步入职场后才发现,每一份工作都不容易啊,每天活多得干不完,如果不在工作时间内拼命干活,就要无偿加班,占用自己的私人时间。为了能提高工作效率,除了要学一些时间管理法之外,提升工作效率…...