当前位置:网站首页>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]所创,转载请带上原文链接,感谢
边栏推荐
- I think it is necessary to write a general idempotent component
- 仅用六种字符来完成Hello World,你能做到吗?
- I'm afraid that the spread sequence calculation of arbitrage strategy is not as simple as you think
- Python3 e-learning case 4: writing web proxy
- MeterSphere开发者手册
- Common algorithm interview has been out! Machine learning algorithm interview - KDnuggets
- 零基础打造一款属于自己的网页搜索引擎
- 至联云解析:IPFS/Filecoin挖矿为什么这么难?
- 6.3 handlerexceptionresolver exception handling (in-depth analysis of SSM and project practice)
- With the advent of tensorflow 2.0, can pytoch still shake the status of big brother?
猜你喜欢

Interface pressure test: installation, use and instruction of siege pressure test

Python filtering sensitive word records

前端工程师需要懂的前端面试题(c s s方面)总结(二)

Summary of common algorithms of binary tree

Summary of common algorithms of linked list

vue-codemirror基本用法:实现搜索功能、代码折叠功能、获取编辑器值及时验证

Brief introduction of TF flags

How to customize sorting for pandas dataframe

axios学习笔记(二):轻松弄懂XHR的使用及如何封装简易axios

Network security engineer Demo: the original * * is to get your computer administrator rights! 【***】
随机推荐
Save the file directly to Google drive and download it back ten times faster
The data of pandas was scrambled and the training machine and testing machine set were selected
前端工程师需要懂的前端面试题(c s s方面)总结(二)
一篇文章带你了解CSS3圆角知识
H5 makes its own video player (JS Part 2)
OPTIMIZER_ Trace details
Windows 10 tensorflow (2) regression analysis of principles, deep learning framework (gradient descent method to solve regression parameters)
Free patent download tutorial (HowNet, Espacenet)
Python基础变量类型——List浅析
一篇文章教会你使用Python网络爬虫下载酷狗音乐
Five vuex plug-ins for your next vuejs project
React design pattern: in depth understanding of react & Redux principle
MeterSphere开发者手册
How to use Python 2.7 after installing anaconda3?
一篇文章教会你使用HTML5 SVG 标签
Elasticsearch数据库 | Elasticsearch-7.5.0应用搭建实战
Subordination judgment in structured data
Mac installation hanlp, and win installation and use
Just now, I popularized two unique skills of login to Xuemei
助力金融科技创新发展,ATFX走在行业最前列