Spring Cache簡單實現

Spring Cache簡單實現

業務場景

假定一個業務場景:在項目中,用戶查詢是一個非常頻繁的操作,從性能優化的角度,自然會想到對用戶的查詢方法做緩存,以避免頻繁的數據庫訪問操作,提高頁面的響應速度。

通常的做法是以用戶的userId作爲鍵值key,以返回的用戶對象作爲value值進行存儲,而以相同的userId查詢用戶時,程序將直接從緩存中獲取結果並返回,否則更新緩存。

代碼清單

這裏使用的是Spring默認的緩存管理器

服務類

package com.example.cache.springcache;
import com.example.cache.customize.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * @author: 博客「成猿手冊」
 * @description: com.example.cache.springcache
 * @date: 2020/6/7
 */
@Service(value = "userServiceBean")
public class UserService {

    //使用名爲users的緩存
    @Cacheable(cacheNames = "users")
    public User getUserById(String userId) {

        //方法內部不考慮緩存邏輯直接實現業務
        System.out.println("query user by userId=" + userId);
        return getFromDB(userId);
    }

    //模擬數據庫查詢
    private User getFromDB(String userId) {
        System.out.println("querying id from DB..." + userId);
        return new User(userId);
    }
}

getUserById()方法被標註了一個註解,即 @Cacheable(cacheNames = "users")當調用這個方法時,會先從users緩存中查詢匹配的緩存對象:

  1. 如果存在,則直接返回;

  2. 如果不存在,則執行方法體內的邏輯(查詢數據庫),並將返回值放進緩存中。對應緩存的key爲userId的值,value就是userId所對應的User對象。

相關配置

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- 定義一個Bean -->
    <bean id="userServiceBean" class="com.example.cache.springcache.UserService"/>
    <!-- 引入緩存配置 -->
    <import resource="cache.xml"/>
</beans>

cache.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd">

    <!-- Spring通過該配置啓動基於註解的緩存驅動 -->
    <cache:annotation-driven/>

    <!-- 也可以直接在這裏定義Bean,省略applicationContext.xml -->
    <!--<bean id="userServiceBean" class="com.example.cache.springcache.UserService"/>-->

    <!-- cacheManager爲默認的緩存管理器 -->
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <!-- 通過對SimpleCacheManager屬性caches的配置實現默認緩存管理器的邏輯 -->
        <property name="caches">
            <set>
                <!-- 默認的defaul緩存 -->
                <!--<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>-->
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
            </set>
        </property>
    </bean>
</beans>

實體類

Java對象和序列化是息息相關的,一般情況下,需要被緩存的實體類需要實現Serializable,只有實現了Serializable接口的類,JVM纔可以將其對象進行序列化,對於Redis,EhCache等緩存套件來說,被緩存的對象應該是可序列化的,否則在網絡傳輸,硬盤存儲時,都會拋出序列化異常。

package com.example.cache.customize;
import java.io.Serializable;

/**
 * @author: 博客「成猿手冊」
 * @description: com.example.cache
 * @date: 2020/6/7
 */
public class User  implements Serializable {
    private String userId;
    private String userName;
    private Integer age;
    
    //todo:此處省略get和set方法
}

進行測試

這裏寫一個UserMain以測試上面我們所實現的代碼效果:

package com.example.cache.springcache;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;

/**
 * @author: 博客「成猿手冊」
 * @description: com.example.cache.customize
 * @date: 2020/6/7
 */
public class UserMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userServiceBean");
        //第一次查詢,緩存中沒有,從數據庫查詢
        System.out.println("first query...");
        System.out.println("result object: " + userService.getUserById("test001"));
        //第二次查詢,緩存中存在,從緩存查詢
        System.out.println("second query...");
        System.out.println("result object: " + userService.getUserById("test001"));
    }
}

在控制檯打印的相關信息如下:

first query...
query user by userId=test001
querying id from DB...test001
Disconnected from the target VM, address: '127.0.0.1:12371', transport: 'socket'
result object: com.example.cache.customize.User@6fb365ed
second query...
result object: com.example.cache.customize.User@6fb365ed

可以看出querying id from DB的信息只在我們第一次查詢時出現。到此上面配置的基於註解的緩存起作用了,而回顧代碼會發現,在UserService的代碼中並沒有任何屬於緩存邏輯的代碼,只是一個註解@Cacheable(cacheNames = "users")就實現了基本緩存方案,使得代碼變得非常簡潔。事實上,使用Spring Cache非常簡單,只需要:

  • 緩存定義:確定需要緩存的方法和緩存策略。

  • 緩存配置:配置緩存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章