Java注解@Cacheable的工作原理

简介: Java注解@Cacheable的工作原理

n order to avoid unnecessary query on database it is a common pattern to define a cache in application layer to cache the query result from database. See one example below. Here the application cache is maintained in a custom class CacheContext.

public class AccountService1 {

   private final Logger logger = LoggerFactory.getLogger(AccountService1.class);

 

   private CacheContext accountCacheContext;

 

   public Account getAccountByName(String accountName) {

       Account result = accountCacheContext.get(accountName);

       if (result != null) {

           logger.info("get from cache... {}", accountName);

           return result;

       }

 

       Optional accountOptional = getFromDB(accountName);

       if (!accountOptional.isPresent()) {

           throw new IllegalStateException(String.format("can not find account by account name : [%s]", accountName));

       }

 

       Account account = accountOptional.get();

       accountCacheContext.addOrUpdateCache(accountName, account);

       return account;

   }In Spring there is an annotation @Cacheable which can make the cache managed by Spring instead of application developer. See improved version:

public class AccountService2 {

 

   private final Logger logger = LoggerFactory.getLogger(AccountService2.class);

   @Cacheable(value="accountCache")

   public Account getAccountByName(String accountName) {

       logger.info("in method getAccountByName, querying account... {}", accountName);

       Optional accountOptional = getFromDB(accountName);

       if (!accountOptional.isPresent()) {

           throw new IllegalStateException(String.format("can not find account by account name : [%s]", accountName));

       }

       return accountOptional.get();

   }In this example, there is no more cache evaluation and cache fill logic. All such stuff are taken over by Spring under the hood and completely transparent to application developer, with the help of following bean configuration in xml:

 

 

    class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">

 

 

 

    class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">

 

 

 

And how to research what magic has been done by Spring to achieve this behavior?

We use the following code to research. It is expected that the request sent by line 31 will directly reach database, while the second request in line 34 will be handled by Spring cache handler.



image.png

image.png

Here in line 31, in debugger we can find that accountService2 is not an instance of application class com.sap.AccountService2, but a dynamic proxy class generated by Spring.



image.png

image.pngAs a result after pressing F5, the intercept method of this dynamic proxy class is called:image.pngIn this method, the execution will be delegated to Spring cache handler class:image.pngIn example 1, the logic of cache evaluation and fill is done by application, and now it is done in method execute below.image.png

First internal cache managed by Spring is checked in line 336 via method findCachedItem. Due to expected cache miss, our application method will be called as usual via reflection, as demonstrated below:



image.png

After application method to retrieve account from database is done, the result, Account instance with id 2495 is filled to Spring cache, the variable contexts below.


image.png

Below is the screenshot for Spring internal cache to store application data, which is based on ConcurrentHashMap. Our cached Account instance with id 2495 could be found there.


image.png

image.pngFor the second query request issued by application, the cached result will be returned by Spring handler:image.pngThe last question is, how and when the dynamic proxy is generated?

Again let’s go to the entry point of Beans initialization:

image.pngHere the dynamic proxy is created based on configuration defined in xml with the help of CGlibAopProxy. For more detail about CGlibAopProxy, please refer to Spring official document.



相关文章
|
Java 容器
Java实现Autowired自动注入
Test2正常 Test3空指针 因为不在容器里
120 0
|
Java 编译器 API
Java注释和注解的区别
Java注释和注解的区别
148 0
|
Java
java注解(作用于注解)
java注解(作用于注解)
114 0
|
JSON 数据格式
@JsonProperty与@JSONField注解用处
@JsonProperty与@JSONField注解用处
|
缓存 Java 容器
Spring源码学习:一篇搞懂@Autowire和@Resource注解的区别
最近在刷到很多文章讲解Spring IOC依赖注入时@Autowire和@Resource注解的区别,不同的文章总结出来的点有异同,所以还是看源码自己总结一下其两者的区别,及其用法。
147 0
Spring源码学习:一篇搞懂@Autowire和@Resource注解的区别
|
Java 编译器
注解和反射(一)【注解的基础知识和架构】
注解和反射(一)【注解的基础知识和架构】
125 0
注解和反射(一)【注解的基础知识和架构】
|
Java 索引 Spring
【Spring注解必知必会】深度解析@Component注解实现原理
【Spring注解必知必会】深度解析@Component注解实现原理
400 0
【Spring注解必知必会】深度解析@Component注解实现原理
|
前端开发 JavaScript Java
Java注解详解以及如何实现自定义注解
Java注解详解以及如何实现自定义注解
305 1
|
Java 编译器 Spring
Java注解(Annotation)的基本原理以及实现自定义注解
在我们使用springboot的时候我们知道因为注解的存在,使得我们的开发变得格外的方便、快捷。之前的文章Spring常用注解大全,值得你的收藏!!!对于spring中各类注解也进行过介绍。然而注解也并不是因为spring框架的兴起才出现的,而是很早就已经在java中被使用。
1177 0
Java注解(Annotation)的基本原理以及实现自定义注解
|
XML Java 数据格式
Java注解@Cacheable的工作原理
Java注解@Cacheable的工作原理
149 0
Java注解@Cacheable的工作原理
下一篇
无影云桌面