当前位置:网站首页>It's easy to operate. ThreadLocal can also be used as a cache
It's easy to operate. ThreadLocal can also be used as a cache
2020-11-06 01:28:00 【Yin Jihuan】
The background that
A friend asked me a question about interface optimization , His optimization point is very clear , Because there are many internal calls in the interface service To form a completed business function . Every service The logic in is independent , As a result, many queries are duplicated , Look at the picture below and you will see .

The upper level query is passed on
For this scenario, the best thing is to query the required data from the upper layer , And then pass it on to the lower levels to consume . So you don't have to repeat the query .

If you start writing code like this, no problem , But a lot of times , I was independent when I wrote before , Or the old logic of reuse , There are independent queries in it .
If you want to do optimization, you can only overload one of the old methods , Pass on the information you need directly .
public void xxx(int goodsId) {Goods goods = goodsService.get(goodsId);.....}public void xxx(Goods goods) {.....}
Cache
If your business scenario allows for a certain delay in data , So you can solve the problem of repeated calls by adding cache directly . This has the advantage of not repeatedly querying the database , Instead, it takes data directly from the cache .
The bigger advantage is that it has the least impact on the optimization class , The original code logic does not need to be changed , You can only add annotations to the query .
public void xxx(int goodsId) {Goods goods = goodsService.get(goodsId);.....}public void xxx(Goods goods) {Goods goods = goodsService.get(goodsId);.....}class GoodsService {@Cached(expire = 10, timeUnit = TimeUnit.SECONDS)public Goods get(int goodsId) {return dao.findById(goodsId);}}
If your business scenario doesn't allow caching , The above method can't be used . So is it necessary to change the code , Pass on the required information one layer at a time ?
Customize the cache within the thread
Let's summarize the current problems :
- In the same request , Get the same query many times RPC And so on .
- High demand for real-time data , Not suitable for caching , The main reason is that it is not easy to set the expiration time by adding cache , Unless data changes are used to actively update the cache .
- Just cache in this request , It doesn't affect other places .
- Don't want to change existing code .
After summing up, it is found that this scene is suitable for use ThreadLocal To transfer data , Minimal changes to existing code , And it only works for the current thread , Does not affect other threads .
public void xxx(int goodsId) {Goods goods = ThreadLocal.get();if (goods == null) {goods = goodsService.get(goodsId);}.....}
The code above uses ThreadLocal To get data , If there is one, use it directly , You don't have to search again , If you don't have it, you can check it out , It doesn't affect the old logic .
Although it can achieve the effect , But not so good , Not elegant enough . It's not universal enough , If you want to cache multiple types of data in one request, how to handle it ? ThreadLocal You can't store fixed types . What's more, the old logic has to be changed , Add a judgment .
Here's a more elegant way :
- Custom cache annotations , Add to the query method .
- Define facet cuts to methods with cache annotations , Get the return value for the first time ThreadLocal. The second time directly from ThreadLocal Return the value of .
- ThreadLocal Storage in Map,Key For a certain identification of a method , This can cache multiple types of results .
- stay Filter Lieutenant general ThreadLocal Conduct remove operation , Because threads are reusable , It needs to be emptied after use .
Be careful :ThreadLocal Can't cross thread , If there is a cross thread requirement , Please use Ali's ttl To decorate .

Annotation definition
@Target({ ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)public @interface ThreadLocalCache {/*** cache key, Support SPEL expression* @return*/String key() default "";}
Storage definition
/*** In thread cache management** @ author Yin Jihuan* @ Time 2020-07-12 10:47*/public class ThreadLocalCacheManager {private static ThreadLocal<Map> threadLocalCache = new ThreadLocal<>();public static void setCache(Map value) {threadLocalCache.set(value);}public static Map getCache() {return threadLocalCache.get();}public static void removeCache() {threadLocalCache.remove();}public static void removeCache(String key) {Map cache = threadLocalCache.get();if (cache != null) {cache.remove(key);}}}
Section definition
/*** In thread caching** @ author Yin Jihuan* @ Time 2020-07-12 10:48*/@Aspectpublic class ThreadLocalCacheAspect {@Around(value = "@annotation(localCache)")public Object aroundAdvice(ProceedingJoinPoint joinpoint, ThreadLocalCache localCache) throws Throwable {Object[] args = joinpoint.getArgs();Method method = ((MethodSignature) joinpoint.getSignature()).getMethod();String className = joinpoint.getTarget().getClass().getName();String methodName = method.getName();String key = parseKey(localCache.key(), method, args, getDefaultKey(className, methodName, args));Map cache = ThreadLocalCacheManager.getCache();if (cache == null) {cache = new HashMap();}Map finalCache = cache;Map<String, Object> data = new HashMap<>();data.put("methodName", className + "." + methodName);Object cacheResult = CatTransactionManager.newTransaction(() -> {if (finalCache.containsKey(key)) {return finalCache.get(key);}return null;}, "ThreadLocalCache", "CacheGet", data);if (cacheResult != null) {return cacheResult;}return CatTransactionManager.newTransaction(() -> {Object result = null;try {result = joinpoint.proceed();} catch (Throwable throwable) {throw new RuntimeException(throwable);}finalCache.put(key, result);ThreadLocalCacheManager.setCache(finalCache);return result;}, "ThreadLocalCache", "CachePut", data);}private String getDefaultKey(String className, String methodName, Object[] args) {String defaultKey = className + "." + methodName;if (args != null) {defaultKey = defaultKey + "." + JsonUtils.toJson(args);}return defaultKey;}private String parseKey(String key, Method method, Object[] args, String defaultKey){if (!StringUtils.hasText(key)) {return defaultKey;}LocalVariableTableParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();String[] paraNameArr = nameDiscoverer.getParameterNames(method);ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext();for(int i = 0;i < paraNameArr.length; i++){context.setVariable(paraNameArr[i], args[i]);}try {return parser.parseExpression(key).getValue(context, String.class);} catch (SpelEvaluationException e) {// I can't figure out SPEL Default to class name + Method name + Parametersreturn defaultKey;}}}
Filter definition
/*** Thread cache filter** @ author Yin Jihuan* @ Personal wechat jihuan900* @ WeChat official account Ape world* @GitHub https://github.com/yinjihuan* @ The authors introduce http://cxytiandi.com/about* @ Time 2020-07-12 19:46*/@Slf4jpublic class ThreadLocalCacheFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {filterChain.doFilter(servletRequest, servletResponse);// Clear cache after executionThreadLocalCacheManager.removeCache();}}
Automatic configuration class
@Configurationpublic class ThreadLocalCacheAutoConfiguration {@Beanpublic FilterRegistrationBean idempotentParamtFilter() {FilterRegistrationBean registration = new FilterRegistrationBean();ThreadLocalCacheFilter filter = new ThreadLocalCacheFilter();registration.setFilter(filter);registration.addUrlPatterns("/*");registration.setName("thread-local-cache-filter");registration.setOrder(1);return registration;}@Beanpublic ThreadLocalCacheAspect threadLocalCacheAspect() {return new ThreadLocalCacheAspect();}}
Use cases
@Servicepublic class TestService {/*** ThreadLocalCache Will cache , Only valid for the current thread* @return*/@ThreadLocalCachepublic String getName() {System.out.println(" It's time to check ");return "yinjihaun";}/*** Support SPEL expression* @param id* @return*/@ThreadLocalCache(key = "#id")public String getName(String id) {System.out.println(" It's time to check ");return "yinjihaun" + id;}}
Function code : https://github.com/yinjihuan/kitty
Case code : https://github.com/yinjihuan/kitty-samples
About author : Yin Jihuan , Simple technology enthusiasts ,《Spring Cloud Microservices - Full stack technology and case analysis 》, 《Spring Cloud Microservices introduction Actual combat and advanced 》 author , official account Ape world Originator . Personal wechat jihuan900 , Welcome to hook up with .
I have compiled a complete set of learning materials , Those who are interested can search through wechat 「 Ape world 」, Reply key 「 Learning materials 」 Get what I've sorted out Spring Cloud,Spring Cloud Alibaba,Sharding-JDBC Sub database and sub table , Task scheduling framework XXL-JOB,MongoDB, Reptiles and other related information .

版权声明
本文为[Yin Jihuan]所创,转载请带上原文链接,感谢
边栏推荐
- 一篇文章带你了解CSS3 背景知识
- Save the file directly to Google drive and download it back ten times faster
- Python基础变量类型——List浅析
- Construction of encoder decoder model with keras LSTM
- 一篇文章带你了解CSS 分页实例
- 仅用六种字符来完成Hello World,你能做到吗?
- Python crawler actual combat details: crawling home of pictures
- Free patent download tutorial (HowNet, Espacenet)
- 全球疫情加速互联网企业转型,区块链会是解药吗?
- Elasticsearch数据库 | Elasticsearch-7.5.0应用搭建实战
猜你喜欢

Windows 10 tensorflow (2) regression analysis of principles, deep learning framework (gradient descent method to solve regression parameters)

一篇文章教会你使用Python网络爬虫下载酷狗音乐

如何玩转sortablejs-vuedraggable实现表单嵌套拖拽功能

Mac installation hanlp, and win installation and use

Working principle of gradient descent algorithm in machine learning

Brief introduction of TF flags

Architecture article collection

Summary of common algorithms of linked list

钻石标准--Diamond Standard

Do not understand UML class diagram? Take a look at this edition of rural love class diagram, a learn!
随机推荐
The difference between Es5 class and ES6 class
Python基础数据类型——tuple浅析
Calculation script for time series data
Construction of encoder decoder model with keras LSTM
This article will introduce you to jest unit test
Python基础变量类型——List浅析
Process analysis of Python authentication mechanism based on JWT
PHPSHE 短信插件说明
Wechat applet: prevent multiple click jump (function throttling)
git rebase的時候捅婁子了,怎麼辦?線上等……
How to select the evaluation index of classification model
ES6学习笔记(四):教你轻松搞懂ES6的新增语法
Wiremock: a powerful tool for API testing
仅用六种字符来完成Hello World,你能做到吗?
Save the file directly to Google drive and download it back ten times faster
Electron application uses electronic builder and electronic updater to realize automatic update
从海外进军中国,Rancher要执容器云市场牛耳 | 爱分析调研
If PPT is drawn like this, can the defense of work report be passed?
Analysis of react high order components
Do not understand UML class diagram? Take a look at this edition of rural love class diagram, a learn!