背景
在平时项目中,可能会有某个条件的查询,会多次进到db里面去查,这样就会重复的查询相同的数据,但是我们的数据又不是需要更改及显示的,这时候就可以用到
方法的缓存了。例如在我们调用微信小程序时,需要获取access_token,并且其有效时间为7200秒,过期后再次获取,我们就可以把获取access_token的方法作为
缓存。以下为我实现的过程记录。
1、重写 RedisSerializer 中的 serialize 和 deserialize
1 public class GenericFastJson2JsonRedisSerializer<T> implements RedisSerializer<T> { 2 public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 3 public GenericFastJson2JsonRedisSerializer() { 4 super(); 5 } 6 @Override 7 public byte[] serialize(T t) throws SerializationException { 8 if (t == null) { 9 return new byte[0]; 10 } 11 FastJsonWraper<T> wraperSet =new FastJsonWraper<>(t); 12 return JSON.toJSONString(wraperSet, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); 13 } 14 @Override 15 public T deserialize(byte[] bytes) throws SerializationException { 16 if (bytes == null || bytes.length <= 0) { 17 return null; 18 } 19 String deserializeStr = new String(bytes, DEFAULT_CHARSET); 20 FastJsonWraper<T> wraperGet=JSON.parseObject(deserializeStr,FastJsonWraper.class); 21 return wraperGet.getValue(); 22 } 23 }
重写RedisSerializer
2、实现缓存的获取和设置
1 public class RedisCache implements Cache { 2 3 private Logger logger = Logger.getLogger(RedisCache.class); 4 private RedisTemplate<String, Object> redisTemplate; 5 6 private String name; 7 8 private String resultType; 9 10 private long expireInSencods; 11 12 public static final String KEY_PREFIX = "wx:"; 13 14 15 @Override 16 public Object getNativeCache() { 17 return this.redisTemplate; 18 } 19 20 21 @Override 22 public ValueWrapper get(Object key) { 23 if (logger.isDebugEnabled()) { 24 logger.debug("------缓存获取-------" + key.toString()); 25 } 26 final String keyf = KEY_PREFIX + key.toString(); 27 Object object = null; 28 object = redisTemplate.execute(new RedisCallback<Object>() { 29 @Override 30 public Object doInRedis(RedisConnection connection) throws DataAccessException { 31 byte[] key = keyf.getBytes(); 32 byte[] value = connection.get(key); 33 if (value == null) { 34 if (logger.isDebugEnabled()) { 35 logger.debug("------缓存不存在-------"); 36 } 37 return null; 38 } 39 try { 40 Class<?> class1 = null; 41 if (StringUtils.isNotEmpty(resultType)) { 42 class1 = Class.forName(resultType); 43 } else { 44 class1 = String.class; 45 } 46 String resultJson = new String(value, Charset.forName("utf-8")); 47 Object result = JSONObject.parseObject(resultJson, class1); 48 return result; 49 } catch (ClassNotFoundException e) { 50 e.printStackTrace(); 51 } 52 return null; 53 } 54 }); 55 ValueWrapper obj = (object != null ? new SimpleValueWrapper(object) : null); 56 if (logger.isDebugEnabled()) { 57 logger.debug("------获取到内容-------" + obj); 58 } 59 return obj; 60 } 61 62 63 @Override 64 public <T> T get(Object key, Class<T> type) { 65 // TODO Auto-generated method stub 66 return null; 67 } 68 69 70 @Override 71 public <T> T get(Object key, Callable<T> valueLoader) { 72 // TODO Auto-generated method stub 73 return null; 74 } 75 76 77 @Override 78 public void put(Object key, Object value) { 79 if (logger.isDebugEnabled()) { 80 logger.debug("-------加入缓存------"); 81 logger.debug("key----:" + key); 82 logger.debug("key----:" + value); 83 } 84 final String keyString = KEY_PREFIX + key.toString(); 85 final Object valuef = value; 86 redisTemplate.execute(new RedisCallback<Long>() { 87 @Override 88 public Long doInRedis(RedisConnection connection) throws DataAccessException { 89 byte[] keyb = keyString.getBytes(); 90 String valuejson = JSONObject.toJSONString(valuef); 91 byte[] valueb = valuejson.getBytes(Charset.forName("utf-8")); 92 connection.set(keyb, valueb); 93 if (expireInSencods > 0) { 94 connection.expire(keyb, expireInSencods); 95 } 96 return 1L; 97 } 98 }); 99 } 100 101 102 @Override 103 public ValueWrapper putIfAbsent(Object key, Object value) { 104 // TODO Auto-generated method stub 105 return null; 106 } 107 108 109 @Override 110 public void evict(Object key) { 111 if (logger.isDebugEnabled()) { 112 logger.debug("-------緩存刪除------"); 113 } 114 final String keyf = KEY_PREFIX + key.toString(); 115 redisTemplate.execute(new RedisCallback<Long>() { 116 @Override 117 public Long doInRedis(RedisConnection connection) throws DataAccessException { 118 return connection.del(keyf.getBytes()); 119 } 120 121 }); 122 } 123 124 125 @Override 126 public void clear() { 127 if (logger.isDebugEnabled()) { 128 logger.debug("-------緩存清理------"); 129 } 130 redisTemplate.execute(new RedisCallback<String>() { 131 @Override 132 public String doInRedis(RedisConnection connection) throws DataAccessException { 133 connection.flushDb(); 134 return "ok"; 135 } 136 }); 137 } 138 139 /** 140 * @return redisTemplate 141 */ 142 public RedisTemplate<String, Object> getRedisTemplate() { 143 return redisTemplate; 144 } 145 146 /** 147 * @param redisTemplate the redisTemplate to set 148 */ 149 public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { 150 this.redisTemplate = redisTemplate; 151 } 152 153 /** 154 * @param name the name to set 155 */ 156 public void setName(String name) { 157 this.name = name; 158 } 159 160 /** 161 * @return name 162 */ 163 @Override 164 public String getName() { 165 return name; 166 } 167 168 /** 169 * @return resultType 170 */ 171 public String getResultType() { 172 return resultType; 173 } 174 175 /** 176 * @param resultType the resultType to set 177 */ 178 public void setResultType(String resultType) { 179 this.resultType = resultType; 180 } 181 182 /** 183 * @return expireInSencods 184 */ 185 public long getExpireInSencods() { 186 return expireInSencods; 187 } 188 189 /** 190 * @param expireInSencods the expireInSencods to set 191 */ 192 public void setExpireInSencods(long expireInSencods) { 193 this.expireInSencods = expireInSencods; 194 } 195 196 }
3、在spring-redis.xml中配置 spring mvc自定义缓存,bean 中的class为我们缓存实现类的包路径,属性均为缓存实现类中的属性。
1 <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> 2 <property name="caches"> 3 <set> 4 <bean class="xxxx.xxx.xxx.RedisCache"> 5 <property name="redisTemplate" ref="redisTemplate"/> 6 <property name="name" value="wechatapp"/> 7 <property name="expireInSencods" value="7200"/> 8 <property name="resultType" 9 value="xxxx.xx.xxx.xx"/> 10 </bean> 11 </set> 12 </property> 13 </bean>
Spring mvc 自定义缓存
4、在代码中使用缓存,使用注解 @Cacheable,其中缓存名字cacheNames需要与我们spring redis中配置bean的<property name="name" value="xxx"/>对应起来
@Cacheable(cacheNames = CACHE_NAME,key = "#appid+‘:‘+#secret",unless = "#result == null") @Override public WeChatAppResponseDto getAccessToken(String appid, String secret) { }
代码中的使用
然后执行代码可以发现,在第一次进入的时候,进入方法内部,然后返回结果,再次访问就没有进入方法内部了,可以打断点在缓存获取方法中查看,后面的都直接在缓存中获取了。其实通过引入的相关依赖也可以看出来,该注解功能是利用AOP来实现的。
原文地址:https://www.cnblogs.com/rolayblog/p/11176270.html
时间: 2024-10-08 10:49:44