Java注解@Cacheable的工作原理

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

In 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<Account> accountCacheContext;
    public Account getAccountByName(String accountName) {
        Account result = accountCacheContext.get(accountName);
        if (result != null) {
            logger.info("get from cache... {}", accountName);
            return result;
        }
        Optional<Account> 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<Account> 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:


<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
    <property name="caches">
      <set>
        <bean
          class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
          <property name="name" value="default" />
        </bean>
        <bean
          class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
          <property name="name" value="accountCache" />
        </bean>
      </set>
    </property>
  </bean>

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.pngHere 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.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.pngFirst 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

image.pngAfter 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.pngBelow 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.pngimage.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.pngimage.png

相关文章
|
3月前
|
Java Spring
使用Java实现自定义注解的方法与技巧
使用Java实现自定义注解的方法与技巧
|
5月前
|
Java 程序员 编译器
Java注解概述及解析注解
Java注解概述及解析注解
65 1
|
Java
java注解(作用于注解)
java注解(作用于注解)
115 0
|
Java Spring 容器
【框架源码】Spring源码核心注解@Conditional原理及应用
【框架源码】Spring源码核心注解@Conditional原理及应用
【框架源码】Spring源码核心注解@Conditional原理及应用
|
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中被使用。
1179 0
Java注解(Annotation)的基本原理以及实现自定义注解
|
XML Java 数据格式
Java注解@Cacheable的工作原理
Java注解@Cacheable的工作原理
149 0
Java注解@Cacheable的工作原理
|
Java 数据库连接
注解@notBlank的工作原理
注解@notBlank的工作原理
注解@notBlank的工作原理
下一篇
无影云桌面