您好,登錄后才能下訂單哦!
SpringBoot
?是為了簡(jiǎn)化?Spring
?應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等一系列問(wèn)題而誕生的產(chǎn)物,自動(dòng)裝配的特性讓我們可以更好的關(guān)注業(yè)務(wù)本身而不是外部的XML配置,我們只需遵循規(guī)范,引入相關(guān)的依賴(lài)就可以輕易的搭建出一個(gè) WEB 工程
Spring 3.1
?引入了激動(dòng)人心的基于注釋?zhuān)╝nnotation)的緩存(cache)技術(shù),它本質(zhì)上不是一個(gè)具體的緩存實(shí)現(xiàn)方案(例如?EHCache
?或者?Redis
),而是一個(gè)對(duì)緩存使用的抽象,通過(guò)在既有代碼中添加少量它定義的各種?annotation
,即能夠達(dá)到緩存方法的返回對(duì)象的效果。
具備相當(dāng)?shù)暮玫撵`活性,不僅能夠使用?SpEL(Spring Expression Language)來(lái)定義緩存的 key 和各種 condition,還提供開(kāi)箱即用的緩存臨時(shí)存儲(chǔ)方案,也支持和主流的專(zhuān)業(yè)緩存例如 EHCache、Redis、Guava 的集成。
下面針對(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
注解,緩存由開(kāi)發(fā)者自己配置,但不用參與到具體編碼
@Cacheable(value = "user", key = "#key")
public String get(String key) {
return userMapper.selectById(key);
}
在?pom.xml
?中添加?spring-boot-starter-data-redis
的依賴(lài)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
在?application.properties
?文件中配置如下內(nèi)容,由于Spring Boot2.x
?的改動(dòng),連接池相關(guān)配置需要通過(guò)spring.redis.lettuce.pool
或者?spring.redis.jedis.pool
?進(jìn)行配置了。使用了Spring Cache
后,能指定spring.cache.type
就手動(dòng)指定一下,雖然它會(huì)自動(dòng)去適配已有Cache
的依賴(lài),但先后順序會(huì)對(duì)Redis
使用有影響(JCache -> EhCache -> Redis -> Guava)
spring.redis.host=localhost
spring.redis.password=battcn
# 一般來(lái)說(shuō)是不用配置的,Spring Cache 會(huì)根據(jù)依賴(lài)的包自行裝配
spring.cache.type=redis
# 連接超時(shí)時(shí)間(毫秒)
spring.redis.timeout=10000
# Redis默認(rèn)情況下有16個(gè)分片,這里配置具體使用的分片
spring.redis.database=0
# 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制) 默認(rèn) 8
spring.redis.lettuce.pool.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制) 默認(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
創(chuàng)建一個(gè)User
類(lèi),目的是為了模擬對(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 用戶(hù)對(duì)象
* @return 操作結(jié)果
*/
User saveOrUpdate(User user);
/**
* 添加
*
* @param id key值
* @return 返回結(jié)果
*/
User get(Long id);
/**
* 刪除
*
* @param id key值
*/
void delete(Long id);
}
為了方便演示數(shù)據(jù)庫(kù)操作,直接定義了一個(gè)Map<Long, User> DATABASES
,這里的核心就是@Cacheable、@CachePut、@CacheEvict?三個(gè)注解
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<Long, User> 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ù)庫(kù)讀取出來(lái)的
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)后,編寫(xiě)一個(gè)junit
測(cè)試類(lèi)來(lái)檢驗(yàn)代碼的正確性,有很多人質(zhì)疑過(guò)Redis
線程安全性,故下面也提供了響應(yīng)的測(cè)試案例,如有疑問(wèn)歡迎指正
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)測(cè)試類(lèi),結(jié)果和我們期望的一致,可以看到增刪改查中,查詢(xún)是沒(méi)有日志輸出的,因?yàn)樗苯訌木彺嬷蝎@取的數(shù)據(jù),而添加、修改、刪除都是會(huì)進(jìn)入方法內(nèi)執(zhí)行具體的業(yè)務(wù)代碼,然后通過(guò)切面去刪除掉Redis中的緩存數(shù)據(jù)。其中 # 號(hào)代表這是一個(gè) SpEL 表達(dá)式,此表達(dá)式可以遍歷方法的參數(shù)對(duì)象,具體語(yǔ)法可以參考 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 方法
其它類(lèi)型
下列的就是Redis
其它類(lèi)型所對(duì)應(yīng)的操作方式
根據(jù)條件操作緩存內(nèi)容并不影響數(shù)據(jù)庫(kù)操作,條件表達(dá)式返回一個(gè)布爾值,true/false,當(dāng)條件為true,則進(jìn)行緩存操作,否則直接調(diào)用方法執(zhí)行的返回結(jié)果。
@CachePut(value = "user", key = "#user.id",condition = "#user.username.length() < 10")
?只緩存用戶(hù)名長(zhǎng)度少于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)行緩存)
@Cacheable(value="user",key="#userName")
)@Cacheable(value="user")
?或者@Cacheable(value={"user1","use2"})
)@Cacheable(value = "user", key = "#id",condition = "#id < 10")
)@CachePut(根據(jù)方法的請(qǐng)求參數(shù)對(duì)其結(jié)果進(jìn)行緩存,和?
@Cacheable
?不同的是,它每次都會(huì)觸發(fā)真實(shí)方法的調(diào)用)
@CachEvict(根據(jù)條件對(duì)緩存進(jìn)行清空)
@CacheEvict(value = "user", key = "#id", allEntries = true)
)@CacheEvict(value = "user", key = "#id", beforeInvocation = true)
)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
目前很多大佬都寫(xiě)過(guò)關(guān)于?SpringBoot?的教程了,如有雷同,請(qǐng)多多包涵,本教程基于最新的?spring-boot-starter-parent:2.0.1.RELEASE
編寫(xiě),包括新版本的特性都會(huì)一起介紹…
本文的重點(diǎn)是你有沒(méi)有收獲與成長(zhǎng),其余的都不重要,希望讀者們能謹(jǐn)記這一點(diǎn)。同時(shí)我經(jīng)過(guò)多年的收藏目前也算收集到了一套完整的學(xué)習(xí)資料,包括但不限于:分布式架構(gòu)、高可擴(kuò)展、高性能、高并發(fā)、Jvm性能調(diào)優(yōu)、Spring,MyBatis,Nginx源碼分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多個(gè)知識(shí)點(diǎn)高級(jí)進(jìn)階干貨,希望對(duì)想成為架構(gòu)師的朋友有一定的參考和幫助
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。