摘要:特點(diǎn)具備相當(dāng)?shù)暮玫撵`活性,不僅能夠使用來定義緩存的和各種,還提供開箱即用的緩存臨時(shí)存儲(chǔ)方案,也支持和主流的專業(yè)緩存例如的集成。其中號(hào)代表這是一個(gè)表達(dá)式,此表達(dá)式可以遍歷方法的參數(shù)對(duì)象,具體語法可以參考的相關(guān)文檔手冊(cè)。
SpringBoot 是為了簡化 Spring 應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等一系列問題而誕生的產(chǎn)物,自動(dòng)裝配的特性讓我們可以更好的關(guān)注業(yè)務(wù)本身而不是外部的XML配置,我們只需遵循規(guī)范,引入相關(guān)的依賴就可以輕易的搭建出一個(gè) WEB 工程
Spring 3.1 引入了激動(dòng)人心的基于注釋(annotation)的緩存(cache)技術(shù),它本質(zhì)上不是一個(gè)具體的緩存實(shí)現(xiàn)方案(例如 EHCache 或者 Redis),而是一個(gè)對(duì)緩存使用的抽象,通過在既有代碼中添加少量它定義的各種 annotation,即能夠達(dá)到緩存方法的返回對(duì)象的效果。
特點(diǎn)具備相當(dāng)?shù)暮玫撵`活性,不僅能夠使用 SpEL(Spring Expression Language)來定義緩存的 key 和各種 condition,還提供開箱即用的緩存臨時(shí)存儲(chǔ)方案,也支持和主流的專業(yè)緩存例如 EHCache、Redis、Guava 的集成。
基于 annotation 即可使得現(xiàn)有代碼支持緩存
開箱即用 Out-Of-The-Box,不用安裝和部署額外第三方組件即可使用緩存
支持 Spring Express Language,能使用對(duì)象的任何屬性或者方法來定義緩存的 key 和 condition
支持 AspectJ,并通過其實(shí)現(xiàn)任何方法的緩存支持
支持自定義 key 和自定義緩存管理者,具有相當(dāng)?shù)撵`活性和擴(kuò)展性
使用前后下面針對(duì)Spring Cache使用前后給出了偽代碼部分,具體中也許比這要更加復(fù)雜,但是Spring Cache都可以很好的應(yīng)對(duì)
使用前
我們需要硬編碼,如果切換Cache Client還需要修改代碼,耦合度高,不易于維護(hù)
public String get(String key) { String value = userMapper.selectById(key); if (value != null) { cache.put(key,value); } return value; }
使用后
基于Spring Cache注解,緩存由開發(fā)者自己配置,但不用參與到具體編碼
@Cacheable(value = "user", key = "#key") public String get(String key) { return userMapper.selectById(key); }添加依賴
在 pom.xml 中添加 spring-boot-starter-data-redis的依賴
屬性配置org.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2 org.springframework.boot spring-boot-starter-test test
在 application.properties 文件中配置如下內(nèi)容,由于Spring Boot2.x 的改動(dòng),連接池相關(guān)配置需要通過spring.redis.lettuce.pool 或者 spring.redis.jedis.pool 進(jìn)行配置了。使用了Spring Cache后,能指定spring.cache.type就手動(dòng)指定一下,雖然它會(huì)自動(dòng)去適配已有Cache的依賴,但先后順序會(huì)對(duì)Redis使用有影響(JCache -> EhCache -> Redis -> Guava)
spring.redis.host=localhost spring.redis.password=battcn # 一般來說是不用配置的,Spring Cache 會(huì)根據(jù)依賴的包自行裝配 spring.cache.type=redis # 連接超時(shí)時(shí)間(毫秒) spring.redis.timeout=10000 # Redis默認(rèn)情況下有16個(gè)分片,這里配置具體使用的分片 spring.redis.database=0 # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制) 默認(rèn) 8 spring.redis.lettuce.pool.max-active=8 # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制) 默認(rèn) -1 spring.redis.lettuce.pool.max-wait=-1 # 連接池中的最大空閑連接 默認(rèn) 8 spring.redis.lettuce.pool.max-idle=8 # 連接池中的最小空閑連接 默認(rèn) 0 spring.redis.lettuce.pool.min-idle=0具體編碼 實(shí)體類
創(chuàng)建一個(gè)User類,目的是為了模擬對(duì)象存儲(chǔ)
package com.battcn.entity; import java.io.Serializable; /** * @author Levin * @since 2018/5/11 0007 */ public class User implements Serializable { private static final long serialVersionUID = 8655851615465363473L; private Long id; private String username; private String password; // TODO 省略get set }定義接口
package com.battcn.service; import com.battcn.entity.User; /** * @author Levin * @since 2018/5/11 0011 */ public interface UserService { /** * 刪除 * * @param user 用戶對(duì)象 * @return 操作結(jié)果 */ User saveOrUpdate(User user); /** * 添加 * * @param id key值 * @return 返回結(jié)果 */ User get(Long id); /** * 刪除 * * @param id key值 */ void delete(Long id); }實(shí)現(xiàn)類
為了方便演示數(shù)據(jù)庫操作,直接定義了一個(gè)Map
package com.battcn.service.impl; import com.battcn.entity.User; import com.battcn.service.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; /** * @author Levin * @since 2018/5/11 0011 */ @Service public class UserServiceImpl implements UserService { private static final Map主函數(shù)DATABASES = new HashMap<>(); static { DATABASES.put(1L, new User(1L, "u1", "p1")); DATABASES.put(2L, new User(2L, "u2", "p2")); DATABASES.put(3L, new User(3L, "u3", "p3")); } private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Cacheable(value = "user", key = "#id") @Override public User get(Long id) { // TODO 我們就假設(shè)它是從數(shù)據(jù)庫讀取出來的 log.info("進(jìn)入 get 方法"); return DATABASES.get(id); } @CachePut(value = "user", key = "#user.id") @Override public User saveOrUpdate(User user) { DATABASES.put(user.getId(), user); log.info("進(jìn)入 saveOrUpdate 方法"); return user; } @CacheEvict(value = "user", key = "#id") @Override public void delete(Long id) { DATABASES.remove(id); log.info("進(jìn)入 delete 方法"); } }
@EnableCaching 必須要加,否則spring-data-cache相關(guān)注解不會(huì)生效...
package com.battcn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; /** * @author Levin */ @SpringBootApplication @EnableCaching public class Chapter9Application { public static void main(String[] args) { SpringApplication.run(Chapter9Application.class, args); } }測試
完成準(zhǔn)備事項(xiàng)后,編寫一個(gè)junit測試類來檢驗(yàn)代碼的正確性,有很多人質(zhì)疑過Redis線程安全性,故下面也提供了響應(yīng)的測試案例,如有疑問歡迎指正
package com.battcn; import com.battcn.entity.User; import com.battcn.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** * @author Levin * @since 2018/5/10 0010 */ @RunWith(SpringRunner.class) @SpringBootTest public class Chapter9ApplicationTest { private static final Logger log = LoggerFactory.getLogger(Chapter9ApplicationTest.class); @Autowired private UserService userService; @Test public void get() { final User user = userService.saveOrUpdate(new User(5L, "u5", "p5")); log.info("[saveOrUpdate] - [{}]", user); final User user1 = userService.get(5L); log.info("[get] - [{}]", user1); userService.delete(5L); } }
啟動(dòng)測試類,結(jié)果和我們期望的一致,可以看到增刪改查中,查詢是沒有日志輸出的,因?yàn)樗苯訌木彺嬷蝎@取的數(shù)據(jù),而添加、修改、刪除都是會(huì)進(jìn)入方法內(nèi)執(zhí)行具體的業(yè)務(wù)代碼,然后通過切面去刪除掉Redis中的緩存數(shù)據(jù)。其中 # 號(hào)代表這是一個(gè) SpEL 表達(dá)式,此表達(dá)式可以遍歷方法的參數(shù)對(duì)象,具體語法可以參考 Spring 的相關(guān)文檔手冊(cè)。
2018-05-14 09:20:55.303 INFO 21176 --- [ main] com.battcn.service.impl.UserServiceImpl : 進(jìn)入 saveOrUpdate 方法 2018-05-14 09:20:55.582 INFO 21176 --- [ main] io.lettuce.core.EpollProvider : Starting without optional epoll library 2018-05-14 09:20:55.584 INFO 21176 --- [ main] io.lettuce.core.KqueueProvider : Starting without optional kqueue library 2018-05-14 09:20:56.316 INFO 21176 --- [ main] com.battcn.Chapter9ApplicationTest : [saveOrUpdate] - [User{id=5, username="u5", password="p5"}] 2018-05-14 09:20:56.320 INFO 21176 --- [ main] com.battcn.Chapter9ApplicationTest : [get] - [User{id=5, username="u5", password="p5"}] 2018-05-14 09:20:56.322 INFO 21176 --- [ main] com.battcn.service.impl.UserServiceImpl : 進(jìn)入 delete 方法
其它類型
下列的就是Redis其它類型所對(duì)應(yīng)的操作方式
opsForValue: 對(duì)應(yīng) String(字符串)
opsForZSet: 對(duì)應(yīng) ZSet(有序集合)
opsForHash: 對(duì)應(yīng) Hash(哈希)
opsForList: 對(duì)應(yīng) List(列表)
opsForSet: 對(duì)應(yīng) Set(集合)
opsForGeo: 對(duì)應(yīng) GEO(地理位置)
根據(jù)條件操作緩存根據(jù)條件操作緩存內(nèi)容并不影響數(shù)據(jù)庫操作,條件表達(dá)式返回一個(gè)布爾值,true/false,當(dāng)條件為 true,則進(jìn)行緩存操作,否則直接調(diào)用方法執(zhí)行的返回結(jié)果。
長度: @CachePut(value = "user", key = "#user.id",condition = "#user.username.length() < 10") 只緩存用戶名長度少于10的數(shù)據(jù)
大小: @Cacheable(value = "user", key = "#id",condition = "#id < 10") 只緩存ID小于10的數(shù)據(jù)
組合: @Cacheable(value="user",key="#user.username.concat(##user.password)")
提前操作: @CacheEvict(value="user",allEntries=true,beforeInvocation=true) 加上beforeInvocation=true后,不管內(nèi)部是否報(bào)錯(cuò),緩存都將被清除,默認(rèn)情況為false
注解介紹@Cacheable(根據(jù)方法的請(qǐng)求參數(shù)對(duì)其結(jié)果進(jìn)行緩存)
key: 緩存的 key,可以為空,如果指定要按照 SpEL 表達(dá)式編寫,如果不指定,則缺省按照方法的所有參數(shù)進(jìn)行組合(如:@Cacheable(value="user",key="#userName"))
value: 緩存的名稱,必須指定至少一個(gè)(如:@Cacheable(value="user") 或者 @Cacheable(value={"user1","use2"}))
condition: 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進(jìn)行緩存(如:@Cacheable(value = "user", key = "#id",condition = "#id < 10"))
@CachePut(根據(jù)方法的請(qǐng)求參數(shù)對(duì)其結(jié)果進(jìn)行緩存,和 @Cacheable 不同的是,它每次都會(huì)觸發(fā)真實(shí)方法的調(diào)用)
key: 同上
value: 同上
condition: 同上
@CachEvict(根據(jù)條件對(duì)緩存進(jìn)行清空)
key: 同上
value: 同上
condition: 同上
allEntries: 是否清空所有緩存內(nèi)容,缺省為 false,如果指定為 true,則方法調(diào)用后將立即清空所有緩存(如:@CacheEvict(value = "user", key = "#id", allEntries = true))
beforeInvocation: 是否在方法執(zhí)行前就清空,缺省為 false,如果指定為 true,則在方法還沒有執(zhí)行的時(shí)候就清空緩存,缺省情況下,如果方法執(zhí)行拋出異常,則不會(huì)清空緩存(如:@CacheEvict(value = "user", key = "#id", beforeInvocation = true))
總結(jié)spring-cache文檔: https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/integration.html#cache-introduction
spring-data-redis文檔: https://docs.spring.io/spring-data/redis/docs/2.0.1.RELEASE/reference/html/#new-in-2.0.0
Redis 文檔: https://redis.io/documentation
Redis 中文文檔: http://www.redis.cn/commands.html
目前很多大佬都寫過關(guān)于 SpringBoot 的教程了,如有雷同,請(qǐng)多多包涵,本教程基于最新的 spring-boot-starter-parent:2.0.1.RELEASE編寫,包括新版本的特性都會(huì)一起介紹...
說點(diǎn)什么個(gè)人QQ:1837307557
battcn開源群(適合新手):391619659
微信公眾號(hào)(歡迎調(diào)戲):battcn
個(gè)人博客:http://blog.battcn.com/
全文代碼:https://github.com/battcn/spring-boot2-learning/tree/master/chapter9
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/62005.html
摘要:特點(diǎn)具備相當(dāng)?shù)暮玫撵`活性,不僅能夠使用來定義緩存的和各種,還提供開箱即用的緩存臨時(shí)存儲(chǔ)方案,也支持和主流的專業(yè)緩存例如的集成。其中號(hào)代表這是一個(gè)表達(dá)式,此表達(dá)式可以遍歷方法的參數(shù)對(duì)象,具體語法可以參考的相關(guān)文檔手冊(cè)。 SpringBoot 是為了簡化 Spring 應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等一系列問題而誕生的產(chǎn)物,自動(dòng)裝配的特性讓我們可以更好的關(guān)注業(yè)務(wù)本身而不是外部的XML配置,...
摘要:本文介紹如何在中使用默認(rèn)的聲明式緩存定義和接口用來統(tǒng)一不同的緩存技術(shù)。在使用集成的時(shí)候,我們需要注冊(cè)實(shí)現(xiàn)的的。默認(rèn)使用在我們不使用其他第三方緩存依賴的時(shí)候,自動(dòng)采用作為緩存管理器。源碼下載參考資料揭秘與實(shí)戰(zhàn)二數(shù)據(jù)緩存篇快速入門 本文介紹如何在springboot中使用默認(rèn)的spring cache 聲明式緩存 Spring 定義 CacheManager 和 Cache 接口用來統(tǒng)一不...
摘要:但是這種手寫文檔帶來的弊端就是維護(hù)起來苦不堪言,對(duì)于接口容易發(fā)生變化的開發(fā)者來說,維護(hù)文檔就是噩夢好在現(xiàn)如今市場上書寫文檔的工具有很多,常見的有阿里的但是能稱之為框架的,估計(jì)也只有了。 SpringBoot 是為了簡化 Spring 應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等一系列問題而誕生的產(chǎn)物,自動(dòng)裝配的特性讓我們可以更好的關(guān)注業(yè)務(wù)本身而不是外部的XML配置,我們只需遵循規(guī)范,引入相關(guān)的依賴...
摘要:建一個(gè)單元測試類其中,注解開啟了生成文件,并指定了存放位置。怎么用創(chuàng)建一個(gè)新文件用構(gòu)建文檔這個(gè)例子非常簡單,通過單元測試和一些簡單的配置就能夠得到文檔了。 準(zhǔn)備工作 你需要15min Jdk 1.8 maven 3.0+ idea 創(chuàng)建工程 引入依賴,其pom文件: org.springframework.boot spring-boot-...
閱讀 2556·2021-09-22 15:25
閱讀 2963·2021-09-14 18:03
閱讀 1212·2021-09-09 09:33
閱讀 1700·2021-09-07 09:59
閱讀 2930·2021-07-29 13:50
閱讀 1500·2019-08-30 15:44
閱讀 1715·2019-08-29 16:22
閱讀 1287·2019-08-29 12:49