@Cacheable加缓存导致的跳过校验 self自调用

news/2024/12/5 3:22:18/

@Cacheable加缓存导致的跳过校验 & self自调用

@Cacheable加缓存导致的跳过校验

java">@Service
public class DataServiceImpl implements DataService {// 这个属性指向当前类的代理对象@Autowiredprivate DataService self;@Override@Cacheable(value = "dataCache", key = "#param")public String getData(String param) {if (!isValid(param)) {throw new IllegalArgumentException("Invalid parameter");}// 通过代理对象调用getData方法,确保缓存逻辑被执行return findData(param);}private String findData(String param) {// 数据查询逻辑return "Data for " + param;}private boolean isValid(String param) {// 参数校验逻辑return param != null && !param.isEmpty();}
}

上面的代码在getData方法前面加了@Cacheable注解,实现了加缓存的操作;不过仔细梳理逻辑就会发现:

当一次调用该方法请求数据;cache中没有数据,于是调用getData方法获取数据,并且将查到的数据存在缓存当中;当第二次查数据的时候,会直接从cache里面找数据,此时不会调用getData方法;因此也就直接跳过了校验。导致后面查找数据时不需要校验就可以直接从缓存里面获取数据。

改进办法:

java">@Service
public class DataServiceImpl implements DataService {// 这个属性指向当前类的代理对象@Autowiredprivate DataService self;@Overridepublic String getDataWithValidation(String param) {if (!isValid(param)) {throw new IllegalArgumentException("Invalid parameter");}// 通过代理对象调用getData方法,确保缓存逻辑被执行return self.getData(param);}@Override@Cacheable(value = "dataCache", key = "#param")public String getData(String param) {return findData(param);}private String findData(String param) {// 数据查询逻辑return "Data for " + param;}private boolean isValid(String param) {// 参数校验逻辑return param != null && !param.isEmpty();}
}

我们在getData 方法外又封装了一层方法,于是不管是从数据库中还是从缓存中调取数据,都必须要首先进行校验;便避免了上面提到的问题。

此外,在getDataWithValidation方法中返回getData方法需要使用self关键字来进行调用,否则@cacheable关键字就会失效;


self自调用

在Java中,使用self.func()这样的自引用调用(其中self是当前对象的引用)通常不是必需的,但在特定情况下,这种调用方式是必要的,特别是在使用Spring框架和面向切面编程(AOP)时。以下是一些使用self.func()调用的具体场景:

1. Spring AOP和代理

当你在Spring框架中使用AOP特性,如@Cacheable@Transactional等注解时,直接在同一个类内部调用被注解的方法不会触发AOP逻辑,因为这种调用不会经过Spring代理。为了确保AOP逻辑被正确触发,你需要通过代理对象(self)来调用方法。

java

java">@Service
public class MyService {private final MyService self = this;@Cacheable(value = "cache", key = "#id")public String getCachedData(Long id) {// 模拟数据库查询return "Data for " + id;}public String getDataWithCacheCheck(Long id) {if (someCondition()) {// 直接调用不会触发缓存逻辑return getCachedData(id);}// 使用self引用来调用,确保经过Spring代理return self.getCachedData(id);}
}

2. 确保线程安全

在多线程环境中,如果你需要确保对共享资源的访问是线程安全的,可能会使用synchronized关键字。在这种情况下,自引用调用可以确保所有的调用都经过同步块。

java

java">public class Counter {private int count = 0;public synchronized void increment() {count++;}public void incrementSafely() {// 使用self引用来确保线程安全this.self.increment();}private Counter self = this;
}

3. 避免无限递归

在某些情况下,你可能需要在方法内部调用自身,但又不希望陷入无限递归。通过使用self引用,你可以控制递归的深度。

java

java">public class RecursiveFunction {private final RecursiveFunction self = this;public void recursiveCall(int depth) {if (depth > 0) {// 使用self引用来避免无限递归self.recursiveCall(depth - 1);}}
}

4. 模拟外部调用

在单元测试中,你可能需要模拟外部对类的调用,以测试类的行为。通过使用self引用,你可以确保测试覆盖了所有通过代理的路径。

java

java">public class ServiceUnderTest {private final ServiceUnderTest self = this;public void someBusinessLogic() {// 业务逻辑}public void testExternalCall() {// 使用self引用来模拟外部调用self.someBusinessLogic();}
}

总的来说,self.func()调用在Java中不是常规做法,但在特定的框架使用(如Spring AOP)和特定的编程模式(如线程安全控制、递归控制)中,它是一种确保代码按预期行为执行的有效手段。


http://www.ppmy.cn/news/1552455.html

相关文章

Oracle 插入数据的存储过程

Oracle 插入数据的存储过程 这是用来,把实时表里面的数据插入到某个表A获取到的字段neid,然后拼接成xxx_xxx_neid历史表,接着往里面插入数据 CREATE OR REPLACE PROCEDURE XXX自定义名 IS-- 定义变量v_ne_id_table_name VARCHAR2(100); …

Debian 的更新原理

Debian 是一个遵循点版本(point release)模式的 Linux 发行版,更新原理是基于点版本发布模式,通过 APT 工具来管理和同步软件包,同时考虑到依赖性、安全性和稳定性。用户可以通过简单的命令来更新系统,而不…

【Vue3】【Naive UI】<NAutoComplete>标签

【Vue3】【Naive UI】标签 <NAutoComplete> 是 Naive UI 库中的一个组件&#xff0c;用于实现自动完成或联想输入功能。 它允许用户在输入时看到与当前输入匹配的建议列表&#xff0c;从而帮助用户更快地填写表单字段。 这个组件通常用于搜索框、地址输入等场景&#xff…

python使用python-docx处理word

文章目录 一、python-docx简介二、基本使用1、新建与保存word2、写入Word&#xff08;1&#xff09;打开文档&#xff08;2&#xff09;添加标题&#xff08;3&#xff09;添加段落&#xff08;4&#xff09;添加文字块&#xff08;5&#xff09;添加图片&#xff08;6&#xf…

蓝桥杯真题——砍竹子(C语言)

问题描述 这天, 小明在砍竹子, 他面前有 n 棵竹子排成一排, 一开始第 ii 棵竹子的 高度为 ​.他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为 H, 那么用一次魔法可以,把这一段竹子的高度都变为, 其中 [x]表…

爬虫抓取的数据能用于商业分析吗?

引言 在数字化时代&#xff0c;数据已成为企业获取竞争优势的关键资源。网络爬虫作为一种数据收集工具&#xff0c;能够从互联网上抓取大量数据&#xff0c;这些数据在商业分析中扮演着重要角色。然而&#xff0c;使用爬虫技术获取的数据是否合法、能否用于商业分析&#xff0…

大数据新视界 -- 大数据大厂之 Hive 数据质量保障:数据清洗与验证的策略(上)(17/ 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【青牛科技】超低功耗混合信号处理器由多种设备组成的流量计电路芯片——D8331

概述&#xff1a; D8331 系列超低功耗混合信号处理器由多种设备组成&#xff0c;具有针对电能表应用的不同外围设备。它们集成了模拟前端和固定功能 DSP 解决方案与一个增强型 8052 单片机核心&#xff0c;RTC 和 LCD 驱动程序集成在一个单一部件中。测量内核包括有功、无功、视…