如果在工作遇到依賴系統返回耗時十分長,有時還不穩定,但是返回的結果數據又變化不大,這時我們該怎麼辦?下面我向大家推薦一下,使用SpringCache來構建方法級緩存,讓我們的服務變的順暢起來,同時提高我們服務的響應速度。在進行SpringCache實戰之前先給大家梳理一下思路。
使用SpringCache的思路
1.使用@EnableCaching或者來開啟緩存服務
2.實現Cache接口來構建自己的緩存處理器(實現查詢和添加的功能)
3.可以使用SimpleCacheManager緩存管理器,也可以繼承AbstractCacheManager來實現自己的緩存管理器
4.將緩存處理器註冊到緩存管理器中,由緩存管理器來統一管理緩存
5.在方法上可以使用@Cacheable,@CachePut,@CacheEvict加載方法上
- @Cacheable 用於先查後做,如果根據相應的key查到結果就直接返回, 不在執行方法, 如果沒有則執行完方法後將方法的返回結果放入到緩存中
- @CachePut 用於設置緩存,先執行方法,再緩存方法的結果
- @CacheEvict用於刪除緩存。在方法執行前,刪除緩存
SpringCache實戰
我們這使用數據庫來當緩存的中間件,如果想使用Redis或者其他的中間件只需替換數據的實現或者重新實現緩存處理器,然後在用的使用指定緩存名稱即可。
1.定義緩存處理器
@Slf4j public class DBCache implements Cache { /** * 緩存的命名屬性 **/ private String name; @Autowired private DBCacheRepository dbCacheRepository; @Override public String getName() { return this.name; } @Override public Object getNativeCache() { return this.dbCacheRepository; } @Override //查詢方法 public ValueWrapper get(Object key) { ValueWrapper result = null; try { //查詢緩存中間件 DBCachePO dbCachePO = dbCacheRepository.get(key.toString()); String value = dbCachePO == null ? null : dbCachePO.getValue(); //處理緩存中間件返回的值 if (value != null) { Class valueType = Class.forName(dbCachePO.getValueClassType()); result = new SimpleValueWrapper(new Gson().fromJson(value, valueType)); } } catch (Exception e) { log.warn("get value from DBCache error, key={}", key, e); } return result; } //添加方法 @Override public void put(Object key, Object value) { try { String[] keyArray = key.toString().split("#"); if (ArrayUtils.isEmpty(keyArray) || keyArray.length < 2) { throw new RuntimeException("illegalKey, use: className.methodName#businessId#other, currentKey=" + key.toString()); } String businessId = keyArray[1]; DBCachePO dbCachePO = new DBCachePO(); dbCachePO.setBusinessId(businessId); dbCachePO.setKey(key.toString()); dbCachePO.setValue(new Gson().toJson(value)); dbCachePO.setValueClassType(value.getClass().getTypeName()); dbCacheRepository.add(dbCachePO); } catch (Exception e) { log.warn("DBCache set value error, key={}, value={}", key, value, e); } } public void setName(String name) { this.name = name; } }
2.開啟緩存和將緩存處理器註冊到緩存管理器
@EnableCaching @Configuration public class CacheConfig { @Bean public DBCache dbCache(){ DBCache dbCache = new DBCache(); dbCache.setName("dbCache"); return dbCache; } @Bean public SimpleCacheManager cacheManager(){ SimpleCacheManager selfCacheManager = new SimpleCacheManager(); Set caches = new HashSet<>(); caches.add(dbCache()); selfCacheManager.setCaches(caches); return selfCacheManager; } }
3.應用到方法上,構建方法級緩存,在cacheNames中可以指定你想使用的緩存處理器,這裡對應的值就是緩存處理器裡name的值,key值的生成支持SpringEL(SpEL)
@Service @Slf4j public class UserService { @Cacheable(cacheNames = {"dbCache"},key = "#root.targetClass.simpleName + '.' + #root.methodName + '#' + #id") public UserDto getUserFromUserCenter(Long id){ //模擬調用RPC log.info("========================RPC調用開始==================="); UserDto userDto = buildUserDto(); log.info("========================RPC調用完成==================="); return userDto; } private UserDto buildUserDto(){ UserDto userDto = new UserDto(); userDto.setAge(18); userDto.setPassword("121321"); userDto.setUserName("txw"); userDto.setPhone("211656778"); return userDto; }
效果顯示
1.插入數據庫的結構,如下圖所示:
2.代碼執行過程剖析圖
附數據庫腳本
CREATE TABLE `db_cache_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Id', `business_id` char(30) NOT NULL COMMENT '業務ID', `key` varchar(200) NOT NULL COMMENT 'key', `value` text COMMENT 'Value', `value_class_type` varchar(200) NOT NULL COMMENT '緩存value的java類型,用於反序列化', `add_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_UNIQUE` (`key`), KEY `idx_business_id` (`business_id`), KEY `idx_addtime` (`add_time`) ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;