自定義Cache十分簡單,找到接口,實現它即可,難點是序列化的自動轉型問題。
前面一篇文章已經提到,自定義Cache中 get(Object key, Class<T> aClass) 函數從未被調用,無法用來對接JSON.parseObject(String json, Class<T> clazz) 函數。
雖然不理解作者的真實意圖,事實已然如此,那就只能嘗試解決,編碼過程中,需要想辦法保存Class的值。
方法一:
改寫CacheInterceptor接口(位於context核心包下),雖然很簡單直接,但是Spring的回答也簡單粗暴:“不允許!”項目啟動直接報錯,強調不允許修改。
方法二:
在Key上做文章,KeyGenerator接口需要實現 generate(Object target, Method method, Object... params) 接口,這里能拿到數據的全類名。
但是這樣做依然不夠好,Key值不宜復雜設計,因為Key值用於數據檢索,不論基於何種技術實現,Key值越長,檢索必定越慢。
方法三:
將全類名附加到Value中,這種做法,FastJSON對此作了支持,直接調用即可。值得注意的是,需要調用ParserConfig.getGlobalInstance()開啟白名單,標明哪些類可以自動轉型。
public static void main(String[] args) { SysUser user = new SysUser(); user.setUserNick("aaaaa"); String str = JSON.toJSONString(user, FastJsonUtils.serializeConfig, SerializerFeature.WriteClassName); System.out.println(str); ParserConfig.getGlobalInstance().addAccept("cn.seaboot.admin.bean."); System.out.println(JSON.parse(str).getClass()); }
自定義Cache簡單的實現:
CacheConfig
import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.context.annotation.Bean; /** * @author Mr.css * @date 2019/12/23 */ @Configuration public class CacheConfig extends CachingConfigurerSupport { @Bean @Override public CacheManager cacheManager() { return new RedisCacheManager(); } }
CacheManager
import org.springframework.cache.Cache; import org.springframework.cache.support.AbstractCacheManager; import java.util.ArrayList; import java.util.Collection; public class RedisCacheManager extends AbstractCacheManager { @Override protected Collection<? extends Cache> loadCaches() { return new ArrayList<>(); } @Override protected Cache getMissingCache(String name) { return new RedisCache(); } }
Cache
將下列代碼中的Map換成更有效的存儲結構,按照自己的想法進行設計即可
import cn.seaboot.admin.consts.SystemConst; import cn.seaboot.common.core.Converter; import org.springframework.cache.Cache; import org.springframework.cache.support.SimpleValueWrapper; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; /** * */ public class RedisCache implements Cache { Map<Object, Object> map = new HashMap<>(); /** * 簡單直白,就是獲取Cache的名字 */ @Override public String getName() { return SystemConst.CACHE_DEF; } /** * 獲取底層的緩存實現對象 */ @Override public Object getNativeCache() { return SystemConst.CACHE_DEF; } /** * 根據鍵獲取值,把值包裝在ValueWrapper里面,如果有必要可以附加額外信息 */ @Override public ValueWrapper get(Object key) { System.out.println("ValueWrapper"); return map.containsKey(key)?new SimpleValueWrapper(map.get(key)):null; } /** * */ @Override public <T> T get(Object key, Class<T> aClass) { try { System.out.println("get(Object o, Class<T> aClass)"); return map.containsKey(key)?Converter.convert(map.get(key), aClass):null; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 與sync屬性有關 */ @Override public <T> T get(Object key, Callable<T> valueLoader) { try { System.out.println("get"); return valueLoader.call(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 存放鍵值對 */ @Override public void put(Object key, Object value) { System.out.println("put(Object key, Object value)"); map.put(key, value); } /** * 如果鍵對應的值不存在,則添加鍵值對 */ @Override public ValueWrapper putIfAbsent(Object key, Object value) { System.out.println("putIfAbsent"); map.put(key, value); return new SimpleValueWrapper(value); } /** * 移除鍵對應鍵值對 */ @Override public void evict(Object key) { System.out.println("evict"); map.remove(key); } /** * 清空緩存 */ @Override public void clear() { System.out.println("clear"); map.clear(); } }