一个复杂的系统,可能外部一个web请求,调用到服务端之后,会变成多个请求,可能是再次请求外部,也可能是请求外部的DB,这时候就面临一个问题,就是一个请求,如何不被重复发送,例如根据userId在数据库查询用户信息,这个操作,可能会由于新人改代码,明明线程内已经请求过一次了,还会再继续请求,这个时候就多了一次网络开销。
这种问题如何避免呢?也可能有答案,就是通过review代码的形式,之前已经获取的用户信息中,放在一个变量中,把这个变量不断的传递下去,先从这个变量中获取数据,如果变量中没有,则从远端(例如数据库端)获取这个数据,但是这样有个问题,就是这个变量会冗余的作为方法体的参数,看起来有点不爽。
所以,基于此,我觉得可以尝试用ThreadLocal来缓存一个线程中以及调用过的方法的返回结果。这样的话,非常复杂的系统,再也不用反复review代码去看有哪些调用是被重复搞的,也不用再通过上下文去传递变量了。
设计图如下:
上代码(目前还是一个初级版本 https://github.com/iamzhongyong/RMICache ):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package rmicache;
import java.util.HashMap;
import java.util.Map;
/** * 缓存信息的持有
*
*/
public class RMICacheHolder {
private RMICacheHolder() {}
private static RMICacheHolder rmiCacheHolder = new RMICacheHolder();
/** 缓存的实体对象, map结构,一个线程体内,可能缓存多个方法的对象 */
private ThreadLocal<Map<String /*方法的签名信息*/,Object/*线程缓存的对象*/>> cacheEntry = new ThreadLocal<Map<String,Object>>(){
@Override
protected Map<String, Object> initialValue() {
return new HashMap<String,Object>();
}
};
/**构造单例*/
public static RMICacheHolder newInstance(){
return rmiCacheHolder;
}
/**根据方法签名,获取缓存对象,如果没有,则通过callback的形式来放入到缓存中*/
public Object getEntry(String methedSign,RMICacheCallback callback){
Map<String,Object> cacheObject = RMICacheHolder.newInstance().cacheEntry.get();
Object cacheValue = cacheObject.get(methedSign);
if(null == cacheValue){
cacheValue = callback.RMIGet();
cacheObject.put(methedSign, cacheValue);
}
return cacheValue;
}
/**根据方法的签名,获取方法的缓存对象*/
public Object getEntry(String methodSign){
Map<String,Object> cacheObject = RMICacheHolder.newInstance().cacheEntry.get();
return cacheObject.get(methodSign);
}
/**缓存之中,放入数据*/
public void putEntry(String methodSign,Object obj){
Map<String,Object> cacheObject = RMICacheHolder.newInstance().cacheEntry.get();
cacheObject.put(methodSign, obj);
}
/**清理线程缓存中的数据,由于现在大多数都是基于线程池的使用,所以这不清理操作必须存在*/
public void clearThreadLocal(){
RMICacheHolder.newInstance().cacheEntry.set( new HashMap<String,Object>());
}
} |
下面一个是一个callback的接口定义:
1
2
3
4
5
6
7
8
9
10
|
package rmicache;
public interface RMICacheCallback {
/**
* 远程获取这个结果
* @return
*/
public Object RMIGet();
} |
结合一个例子使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package test;
import rmicache.RMICacheCallback;
import rmicache.RMICacheHolder;
/** * 辅助进行测试的方法
*
*/
public class BizService {
/**
* 假设这个数据的获取非常消耗时间,在一个线程处理过程中,由于逻辑复杂,不能保证这个方法被人调用多次
* 如果系统对于高并发和响应时间有很高的要求,那么多一个耗时的调用,是非常致命的。
*/
public UserDO getUserDOByID(Long userId){
try {
Thread.sleep( 1000 );
} catch (InterruptedException e) {
}
UserDO user = new UserDO();
user.setName( "iamzhongyong_" +Thread.currentThread().getName());
user.setAge( 18 );
return user;
}
/**
* 远程的包装类
*/
public UserDO getUserDOByIdWraper( final Long userId){
return (UserDO) RMICacheHolder.newInstance().getEntry( "getUserDOByID" , new RMICacheCallback() {
public Object RMIGet() {
return getUserDOByID(userId);
}
});
}
} |
测试类:
1
2
3
4
5
6
|
直接调用远程,方法调用三次,耗时: 3004
三次包装类调用,方法调用三次,有缓存,耗时: 1010
线程数据清理,调用一次包装类,耗时: 1000
异步方法调用三次,一次远程,一次缓存,耗时: 2001
异步方法调用三次,全部是远程,耗时: 3001
线程缓存清理后,异步方法调用三次,一次远程,一次缓存,耗时: 2000
|
相关推荐
远程方法调用(Remote Method Invocation,RMI)是Java平台中一种用于分布式计算的技术,它允许Java对象在不同的 JVM(Java虚拟机)之间调用方法,仿佛这些对象都在同一个JVM中一样。RMI是Java EE(现在被称为...
bazel项目中,通过使用远程缓存bazel_remote_cache 服务,进行编译加速。 受限于单服务的访问和读写能力受限,进行优化升级。 通过使用nginx uri一致性哈希,将请求分发到10台缓存服务器上,总容量提升10倍,经过...
### Remote Method Invocation (RMI) – 远程方法调用详解 #### 一、RMI 概述 **远程方法调用**(Remote Method Invocation, RMI)是Java平台中的一个核心概念和技术,它允许开发者创建分布式应用,在这些应用中,...
Java Remote Method Invocation API Guide Java Remote Method Invocation(Java RMI)是一种允许分布式应用程序在Java平台上运行的技术。它允许在不同的Java虚拟机(JVM)上运行的对象之间调用方法,从而实现...
10. **RMI(Remote Method Invocation)和JNDI(Java Naming and Directory Interface)**: RMI是一种让对象在不同的虚拟机上进行远程通信的机制。JNDI则是一个目录服务,用于在Java应用中查找和访问各种命名和目录...
Java Remote Method Invocation API Guide Java Remote Method Invocation(Java RMI)是一种允许开发者创建分布式应用程序的技术。Java RMI 允许对象在另一个 Java 虚拟机(JVM)上调用远程 Java 对象的方法,可能...
`laravel-remote-content-cache`项目则针对Laravel 5框架,设计了一个专门的缓存解决方案,用于存储和管理从远程服务器获取的数据。缓存技术在Web开发中起着至关重要的作用,它能够减少对远程资源的请求次数,从而...
jdk20-java-remote-method-invocation-api-guide Java Platform, Standard Edition 的 Java Remote Method Invocation API Guide 介绍了 Java Remote Method Invocation(Java RMI)的概念和应用。Java RMI 是一种...
远程组件 在运行时从URL加载React组件。 目录 渲染道具 React钩 创建一个远程组件 远程组件入门套件 使用Webpack创建一个远程组件 创建React App(CRA) 使用Next.js进行服务器端渲染 getServerSideProps 从Next...
COM组件设计与应用的核心之一是IDispatch接口,它是实现自动化(Automation)的关键。自动化使得脚本语言可以方便地调用组件(如Microsoft Office中的Word、Excel)的功能,而无需在编译时就确定所有调用细节。在VC6...
全球领先的半导体及解决方案供应商瑞萨电子于8月6日—8日在深圳举办的2014年工业计算机及嵌入式系统展首日,宣布推出Remote I/O组件的参考设计解决方案。该方案使用了工业以太网通信SoC产品R-IN32M3系列,适用于智能...
本资料“COM组件设计与应用”主要涵盖了COM组件的设计原理、创建过程、注册方法以及在实际应用中的实践技巧。 一、COM基础 1. COM组件定义:COM组件是一种二进制规范,定义了对象如何在内存中表示、如何暴露其接口...
TMS RemoteDB v2.13是一款在IT行业中广泛使用的软件组件,它专为开发人员设计,旨在帮助他们构建强大的三层架构应用程序。这款工具的强大之处在于其对多种数据库的支持以及丰富的数据库访问组件,使得开发人员能够更...
Java Remote Method Invocation API 指南 Java Platform, Standard Edition 的 Java Remote Method Invocation (Java RMI) 是一种允许创建分布式应用程序的技术。Java RMI 允许对象在另一个 Java Virtual Machine ...
Remote Remote Remote Remote Remote
"JDK16 Java Remote Method Invocation API Guide" Java Platform, Standard Edition 的 Java Remote Method Invocation(Java RMI)允许您创建分布式应用程序。Java RMI 允许对象在另一个 Java Virtual Machine...
remote-method- guesser ( rmg )是用Java编写的命令行实用程序,可用于识别Java RMI端点上的安全漏洞。 当前,支持以下操作: 列出可用的绑定名称及其对应的接口类名称 列出代码库位置(如果由远程服务器公开...
Java Remote Method Invocation API Guide Overview Java Remote Method Invocation(Java RMI)是 Java 平台提供的一种分布式应用程序开发技术,允许对象在不同的 Java 虚拟机(JVM)上调用远程 Java 对象的方法...
It is also essential to mention the relevance and novelty of the study within the remote sensing domain. 2. Materials and Methods This section should provide enough detail for others to replicate ...
7. 全局主映射(Global Master Map):这是Cache数据库中用来管理数据分布和恢复的关键组件,能够确保数据的一致性和高效访问。 8. 隐式连接(Implicit Joins):在Cache数据库中,隐式连接是一种无需明确指定连接条件...