Spring Boot中的緩存支持——註解配置與EhCache使用

Spring Boot中的緩存支持——註解配置與EhCache使用

一 點睛

關注、轉發、評論頭條號每天分享java知識,私信回覆“555”贈送一些Dubbo、Redis、Netty、zookeeper、Spring cloud、分佈式資料

隨著時間的積累,應用的使用用戶不斷增加,數據規模也越來越大,往往數據庫查詢操作會成為影響用戶使用體驗的瓶頸,此時使用緩存往往是解決這一問題非常好的手段之一。

Spring 3開始提供了強大的基於註解的緩存支持,可以通過註解配置方式低侵入的給原有Spring應用增加緩存功能,提高數據訪問性能。

Spring Boot中對於緩存的支持,提供了一系列的自動化配置,使我們可以非常方便的使用緩存。

下面我們通過一個簡單的例子來展示如何給一個既有應用增加緩存功能的。

二 實戰

1 引入依賴

org.springframework.boot

spring-boot-starter

org.springframework.boot

spring-boot-starter-test

test

mysql

mysql-connector-java

5.1.21

org.springframework.boot

spring-boot-starter-data-jpa

org.springframework.boot

spring-boot-starter-cache

net.sf.ehcache

ehcache

2 數據訪問接口中,增加緩存配置註解

package com.didispace.domain;

import org.springframework.cache.annotation.CacheConfig;

import org.springframework.cache.annotation.CacheEvict;

import org.springframework.cache.annotation.CachePut;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.data.jpa.repository.JpaRepository;

//在數據訪問接口中,增加緩存配置註解

@CacheConfig(cacheNames = "users")

public interface UserRepository extends JpaRepository {

@Cacheable(key = "#p0", condition = "#p0.length() < 10")

User findByName(String name);

}

3 實體類

package com.didispace.domain;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

/**

* @author 程序猿DD

* @version 1.0.0

* @date 16/3/21 下午3:35.

* @blog http://blog.didispace.com

*/

@Entity

public class User {

@Id

@GeneratedValue

private Long id;

@Column(nullable = false)

private String name;

@Column(nullable = false)

private Integer age;

public User(){}

public User(String name, Integer age) {

this.name = name;

this.age = age;

}

public Long getId() {

return id;

}

public void setId(Long id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

4 啟動類

package com.didispace;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication

//@EnableCaching註解開啟緩存功能

@EnableCaching

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

5 application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/test

spring.datasource.username=root

spring.datasource.password=123456

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop

spring.jpa.properties.hibernate.show_sql=true

6 ehcache.xml配置

xsi:noNamespaceSchemaLocation="ehcache.xsd">

maxEntriesLocalHeap="200"

timeToLiveSeconds="600">

7 測試類

package com.didispace;

import com.didispace.domain.User;

import com.didispace.domain.UserRepository;

import org.junit.Before;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.SpringApplicationConfiguration;

import org.springframework.cache.CacheManager;

import org.springframework.cache.ehcache.EhCacheCacheManager;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@SpringApplicationConfiguration(Application.class)

public class ApplicationTests {

@Autowired

private UserRepository userRepository;

@Autowired

private CacheManager cacheManager;

@Before

public void before() {

userRepository.save(new User("AAA", 10));

}

@Test

public void test() throws Exception {

User u1 = userRepository.findByName("AAA");

System.out.println("第一次查詢:" + u1.getAge());

User u2 = userRepository.findByName("AAA");

System.out.println("第二次查詢:" + u2.getAge());

u1.setAge(20);

userRepository.save(u1);

User u3 = userRepository.findByName("AAA");

System.out.println("第三次查詢:" + u3.getAge());

}

}

三 測試

在調用第二次findByName函數時,沒有再執行select語句,也就直接減少了一次數據庫的讀取操作。

四 實戰說明

1 Cache註解詳解

@CacheConfig:主要用於配置該類中會用到的一些共用的緩存配置。在這裡@CacheConfig(cacheNames = "users"):配置了該數據訪問對象中返回的內容將存儲於名為users的緩存對象中,我們也可以不使用該註解,直接通過@Cacheable自己配置緩存集的名字來定義。

@Cacheable:配置了findByName函數的返回值將被加入緩存。同時在查詢時,會先從緩存中獲取,若不存在才再發起對數據庫的訪問。該註解主要有下面幾個參數:

value、cacheNames:兩個等同的參數(cacheNames為Spring 4新增,作為value的別名),用於指定緩存存儲的集合名。由於Spring 4中新增了@CacheConfig,因此在Spring 3中原本必須有的value屬性,也成為非必需項了

key:緩存對象存儲在Map集合中的key值,非必需,缺省按照函數的所有參數組合作為key值,若自己配置需使用SpEL表達式,比如:@Cacheable(key = "#p0"):使用函數第一個參數作為緩存的key值

condition:緩存對象的條件,非必需,也需使用SpEL表達式,只有滿足表達式條件的內容才會被緩存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有當第一個參數的長度小於3的時候才會被緩存,若做此配置上面的AAA用戶就不會被緩存,讀者可自行實驗嘗試。

unless:另外一個緩存條件參數,非必需,需使用SpEL表達式。它不同於condition參數的地方在於它的判斷時機,該條件是在函數被調用之後才做判斷的,所以它可以通過對result進行判斷。

keyGenerator:用於指定key生成器,非必需。若需要指定一個自定義的key生成器,我們需要去實現org.springframework.cache.interceptor.KeyGenerator接口,並使用該參數來指定。需要注意的是:該參數與key是互斥的

cacheManager:用於指定使用哪個緩存管理器,非必需。只有當有多個時才需要使用

cacheResolver:用於指定使用那個緩存解析器,非必需。需通過org.springframework.cache.interceptor.CacheResolver接口來實現自己的緩存解析器,並用該參數指定。

除了這裡用到的兩個註解之外,還有下面幾個核心註解:

@CachePut:配置於函數上,能夠根據參數定義條件來進行緩存,它與@Cacheable不同的是,它每次都會真是調用函數,所以主要用於數據新增和修改操作上。它的參數與@Cacheable類似,具體功能可參考上面對@Cacheable參數的解析

@CacheEvict:配置於函數上,通常用在刪除方法上,用來從緩存中移除相應數據。除了同@Cacheable一樣的參數之外,它還有下面兩個參數:

allEntries:非必需,默認為false。當為true時,會移除所有數據

beforeInvocation:非必需,默認為false,會在調用方法之後移除數據。當為true時,會在調用方法之前移除數據。

2 緩存配置

Spring Boot中到底使用了什麼緩存呢?

在Spring Boot中通過@EnableCaching註解自動化配置合適的緩存管理器(CacheManager),Spring Boot根據下面的順序去偵測緩存提供者:

Generic

JCache (JSR-107)

EhCache 2.x

Hazelcast

Infinispan

Redis

Guava

Simple

除了按順序偵測外,我們也可以通過配置屬性spring.cache.type來強制指定。

我們可以通過debug調試查看cacheManager對象的實例來判斷當前使用了什麼緩存。

關注、轉發、評論頭條號每天分享java知識,私信回覆“

555”贈送一些Dubbo、Redis、Netty、zookeeper、Spring cloud、分佈式資料


分享到:


相關文章: