介紹SpringBoot項目中使用緩存,以前先介紹一下Spring的緩存抽象和JSR107,本博客是我在學習尚硅谷視頻和參考其它博客以後作的筆記,僅供學習參考java
@git
Spring從3.1開始定義了org.springframework.cache.Cache
和org.springframework.cache.CacheManager接口來統一不一樣的緩存技術;並支持使用Java Caching(JSR-107)註解簡化咱們進行緩存開發。Spring Cache 只負責維護抽象層,具體的實現由你的技術選型來決定。將緩存處理和緩存技術解除耦合。github
Java Caching(JSR-107)定義了5個核心接口,分別是CachingProvider, CacheManager, Cache, Entry和 Expiry。redis
引用尚硅谷視頻課件中的圖示:
spring
例子實踐以前,先簡單介紹Spring提供的重要緩存註解sql
ok,本博客以尚硅谷視頻例子進行改寫,用這個比較經典的例子進行說明apache
環境準備:api
DROP TABLE IF EXISTS `employee`; CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lastName` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `gender` int(2) DEFAULT NULL, `d_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `department`; CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `departmentName` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
@EnableCaching開啓基於註解的緩存數組
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class SpringbootCacheApplication { public static void main(String[] args) { SpringApplication.run(SpringbootCacheApplication.class, args); } }
@Cacheable註解的做用,前面也簡介了,主要是針對方法配置,可以根據方法的請求參數對其結果進行緩存,介紹一下註解的主要屬性緩存
@Cacheable(value = {"emp"}, /*keyGenerator = "myKeyGenerator",*/key = "#id",condition = "#a0>=1",unless = "#a0!=2") public Employee getEmp(Integer id) { Employee employee = this.employeeMapper.getEmpById(id); LOG.info("查詢{}號員工數據",id); return employee; }
這裏也可使用自定義的keyGenerator,使用屬性keyGenerator = "myKeyGenerator
定義一個@Bean類,將KeyGenerator添加到Spring容器
@Configuration public class CacheConfig { @Bean(value = {"myKeyGenerator"}) public KeyGenerator keyGenerator(){ return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { return method.getName()+"["+ Arrays.asList(params).toString()+"]"; } }; } }
@CachePut註解也是一個用來緩存的註解,不過緩存和@Cacheable有明顯的區別是即調用方法,又更新緩存數據,也就是執行方法操做以後再來同步更新緩存,因此這個主鍵經常使用於更新操做,也能夠用於查詢,主鍵屬性和@Cacheable有不少相似的,詳情參看@link @CachePut源碼
/** * @CachePut:既調用方法,又更新緩存數據;同步更新緩存 * 修改了數據,同時更新緩存 */ @CachePut(value = {"emp"}, key = "#result.id") public Employee updateEmp(Employee employee){ employeeMapper.updateEmp(employee); LOG.info("更新{}號員工數據",employee.getId()); return employee; }
主要屬性:
@CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id") public void deleteEmp(Integer id){ employeeMapper.deleteEmpById(id); //int i = 10/0; }
@Caching 用於定義複雜的緩存規則,能夠集成@Cacheable和 @CachePut
// @Caching 定義複雜的緩存規則 @Caching( cacheable = { @Cacheable(/*value={"emp"},*/key = "#lastName") }, put = { @CachePut(/*value={"emp"},*/key = "#result.id"), @CachePut(/*value={"emp"},*/key = "#result.email") } ) public Employee getEmpByLastName(String lastName){ return employeeMapper.getEmpByLastName(lastName); }
@CacheConfig註解能夠用於抽取緩存的公共配置,而後在類加上就能夠,eg:@CacheConfig(cacheNames = {"emp"},cacheManager = "employeeCacheManager")
附錄拓展:SpEL表達式用法
Cache SpEL available metadata
名稱 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root對象 | 當前被調用的方法名 | #root.methodname |
method | root對象 | 當前被調用的方法 | #root.method.name |
target | root對象 | 當前被調用的目標對象實例 | #root.target |
targetClass | root對象 | 當前被調用的目標對象的類 | #root.targetClass |
args | root對象 | 當前被調用的方法的參數列表 | #root.args[0] |
caches | root對象 | 當前方法調用使用的緩存列表 | #root.caches[0].name |
argument Name | 執行上下文(avaluation context) | 當前被調用的方法的參數,如findArtisan(Artisan artisan),能夠經過#artsian.id得到參數 | #artsian.id |
result | 執行上下文(evaluation context) | 方法執行後的返回值(僅當方法執行後的判斷有效,如 unless cacheEvict的beforeInvocation=false) | #result |
基於前面的Spring緩存環境,集成redis要引入相關配置:
<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>
切換緩存方式爲Redis:spring.cache.type=redis
RedisTemplate配置
@Resource private LettuceConnectionFactory lettuceConnectionFactory; @Bean @Primary public RedisTemplate<Object,Object> redisTemplate(){ RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<Object, Object>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.initJacksonSerializer(); // 設置value的序列化規則和 key的序列化規則 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; }
RedisCacheManager相關代碼能夠參考博文,該博主已經對代碼作了比較好的封裝,因此本文不復制代碼
使用RestTemplate操做redis
@Autowired DepartmentMapper departmentMapper; @Qualifier("redisCacheManager") @Autowired RedisCacheManager redisCacheManager; // @Cacheable(cacheNames = "dept",cacheManager = "redisCacheManager") // public Department getDeptById(Integer id){ // System.out.println("查詢部門"+id); // Department department = departmentMapper.getDeptById(id); // return department; // } // 使用緩存管理器獲得緩存,進行api調用 public Department getDeptById(Integer id){ LOG.info("查詢id爲{}的員工信息",id); //獲取某個緩存 Cache deptCache = redisCacheManager.getCache("dept"); Department department = null; if(deptCache.get(id)==null){ department = departmentMapper.getDeptById(id); deptCache.put(id,department); } else { SimpleValueWrapper valueWrapper = (SimpleValueWrapper) deptCache.get(id); department = (Department)valueWrapper.get(); } return department; }
固然使用前面的Spring主鍵也是能夠緩存的,
參考博文:
緩存抽象層Spring cache實戰操做
代碼例子下載:github連接