今天在看 renren-security 源码,发现能够在配置文件中,动态的开启/关闭redis缓存:java
renren: redis: open: false #是否开启redis缓存 true开启 false关闭
若是reren.redis.open=true,则会把sys_config表的数据同时保存到redisgit
若是reren.redis.open=false,则不会把sys_config表的数据同时保存到redis。面试
那这种功能是如何实现的呢?redis
首先,使用IDEA的Find in Path功能(个人快捷键为)在源码中查一下reren.redis.open这个配置:spring
源代码:发现是在一个AOP切面中使用的:是对com.newbanker.common.utils.RedisUtils类(RedisUtils的源码在下面)的全部方法作了拦截,json
若是reren.redis.open=true,则执行RedisUtils的目标方法(看上图源码,在第42行),不然不作任何处理。缓存
result = point.proceed(); // 上图源码42行:执行RedisUtils的目标方法
那咱们再看一下RedisUtils是干啥的,源码在下面,为了便于阅读,这里先说一下RedisUtils这个类的重点:mybatis
package com.newbanker.common.utils; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SetOperations; import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; import javax.annotation.Resource; /** * Redis工具类 * * @author chenshun * @email sunlightcs@gmail.com * @date 2017-07-17 21:12 */ @Component public class RedisUtils { /** * 默认过时时长,单位:秒 */ public final static long DEFAULT_EXPIRE = 60 * 60 * 24; /** * 不设置过时时长 */ public final static long NOT_EXPIRE = -1; @Autowired private RedisTemplate redisTemplate; @Resource(name = "redisTemplate") private ValueOperations<String, String> valueOperations; @Resource(name = "redisTemplate") private HashOperations<String, String, Object> hashOperations; @Resource(name = "redisTemplate") private ListOperations<String, Object> listOperations; @Resource(name = "redisTemplate") private SetOperations<String, Object> setOperations; @Resource(name = "redisTemplate") private ZSetOperations<String, Object> zSetOperations; public void set(String key, Object value, long expire) { valueOperations.set(key, toJson(value)); if (expire != NOT_EXPIRE) { redisTemplate.expire(key, expire, TimeUnit.SECONDS); } } public void set(String key, Object value) { set(key, value, DEFAULT_EXPIRE); } public <T> T get(String key, Class<T> clazz, long expire) { String value = valueOperations.get(key); if (expire != NOT_EXPIRE) { redisTemplate.expire(key, expire, TimeUnit.SECONDS); } return value == null ? null : fromJson(value, clazz); } public <T> T get(String key, Class<T> clazz) { return get(key, clazz, NOT_EXPIRE); } public String get(String key, long expire) { String value = valueOperations.get(key); if (expire != NOT_EXPIRE) { redisTemplate.expire(key, expire, TimeUnit.SECONDS); } return value; } public String get(String key) { return get(key, NOT_EXPIRE); } public void delete(String key) { redisTemplate.delete(key); } /** * Object转成JSON数据 */ private String toJson(Object object) { if (object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double || object instanceof Boolean || object instanceof String) { return String.valueOf(object); } return JSON.toJSONString(object); } /** * JSON数据,转成Object */ private <T> T fromJson(String json, Class<T> clazz) { return JSON.parseObject(json, clazz); } }
在使用时,只须要正常去编写代码,具体是否开启redis,不在代码中直接写重复的if,把哪些重复的判断redis是否开启的判断,放到AOP中:app
package com.newbanker.modules.sys.service.impl; import com.newbanker.common.utils.RedisUtils; import com.newbanker.modules.sys.dao.SysConfigDao; import com.newbanker.modules.sys.entity.SysConfigEntity; import com.newbanker.modules.sys.service.SysConfigService; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service("sysConfigService") public class SysConfigServiceImpl extends ServiceImpl<SysConfigDao, SysConfigEntity> implements SysConfigService { @Autowired private RedisUtils redisUtils; @Override @Transactional(rollbackFor = Exception.class) public void save(SysConfigEntity config) { // 保存数据到db baseMapper.insert(config); // 保存数据到redis redisUtils.set(config.getParamKey(), config.getParamValue()); } }
回想一下面试时,是否是被问到过:请说一下你对AOP的理解和使用?ok,上面说的这些,就是对AOP的使用的很好的案例。ide
另外:说一下个人感悟:就想标题同样:《使用application.yaml配置开启或关闭redis》,咱们在编写代码中,能够把一些功能经过AOP和配置文件的方式,进行实现,可是具体是否启用,能够统一在AOP中进行判断。虽然可使用以下方式进项启用与否的判断:
if (open) { // 保存数据到redis redisUtils.set(config.getParamKey(), config.getParamValue()); }
但若是有不少相似的判断逻辑,确实应该使用AOP,避免在业务代码中加入不少模板方法。
关于模板方法,能够看: