0


Spring与Redis集成

1.引入RedisTemplate

据以前的情况,我们在Java中使用Redis时一般是使用Jedis来操作的,大致的一段代码如下所示

    @Override
    public User findUserById(Integer id) {
        User user = null;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String userStr = jedis.get("user_" + id); // 尝试获取数据
            if (userStr != null && !userStr.isEmpty()) { // 如果获取到有效数据,则转换后返回
                user = JSONObject.parseObject(userStr, User.class);
            } else {// 如果没有获取到数据,则查询数据库返回
                user = userMapper.findUserById(id);
                if (user != null) jedis.set("user_" + id, JSONObject.toJSONString(user)); // 设置到redis中
            }
        } finally {
            // 记得关闭Jedis,因为这里使用的是JedisPool,所以这里的关闭并不是直接关闭连接,而是释放,以供其他的业务使用
            if (jedis != null) jedis.close();
        }
        return user;
    }

上边的这样的一段代码其实是有些臃肿的,但是如果我们引入RedisTemplate,其实会简化不少。

  • maven 引入 spring-data-redis
  <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.9.0</version>
  </dependency>
  <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.2.13.RELEASE</version>
  </dependency>
  • 将RedisTemplate 加入Bean容器中,让Spring进行管理。
  @Bean
  public RedisConnectionFactory redisConnectionFactory() {
      RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
      redisStandaloneConfiguration.setHostName(host);
      redisStandaloneConfiguration.setPort(port);

      RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
      return redisConnectionFactory;
  }

  @Bean
  public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
      RedisTemplate redisTemplate = new RedisTemplate();
      redisTemplate.setConnectionFactory(redisConnectionFactory);
      //设置key值的序列化方式,默认是JDK的形式
      redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
      return redisTemplate;
  }
  • 如果使用RedisTemplate的替换的话,会简洁很多。
  @Autowired
  private RedisTemplate redisTemplate;

  @Override
  public User findUserById(Integer id) {
      Object result = redisTemplate.opsForValue().get("user_" + id);
      if (result != null) return (User) result;

      User user = userMapper.findUserById(id);
      // 设置到redis中
      if (user != null) redisTemplate.opsForValue().set("user_" + id, user);

      return user;
  }
  • 大概看一下关于RedisTemplate的方法

看了以上的内容,可以看到引入了RedisTemplate其实已经很简洁了,但是明显还不够,下面我们将考虑引入 “注解”


2. 引入注解

  • 开启缓存 @EnableCaching
@Configuration@EnableCachingpublicclassAppConfig{...}
  • 引入@Cacheable,表示这个方法将会访问缓存,如果无法命中缓存的话,会将方法返回的值存入redis,假设有注解为 @Cacheable(value="user", key = "#id"),那么生成的key值为 user::{id},即如果id为1 那么生成的 key就是 user::1
@Override@Cacheable(value="user", key ="#id")// 这里返回的值会被存放到redis,key-value格式,其中生成的key值(假设id为1): user::1publicUserfindUserById(Integer id){User user = userMapper.findUserById(id);return user;}

但是这样还不够,因为Spring并不清楚缓存的方式是什么,这就涉及到

CacheManager

  • 设置CacheManager,在AppConfig中加入以下内容
@BeanpublicRedisConnectionFactoryredisConnectionFactory(){RedisStandaloneConfiguration redisStandaloneConfiguration =newRedisStandaloneConfiguration();
    redisStandaloneConfiguration.setHostName(host);// 这里是redis的ip
    redisStandaloneConfiguration.setPort(port);// 这里是redis的端口// 自适应集群变化RedisConnectionFactory redisConnectionFactory =newJedisConnectionFactory(redisStandaloneConfiguration);return redisConnectionFactory;}@BeanpublicRedisCacheConfigurationredisCacheConfiguration(){RedisCacheConfiguration redisCacheConfiguration =RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));return redisCacheConfiguration;}@BeanpublicRedisCacheWriterredisCacheWriter(RedisConnectionFactory redisConnectionFactory){RedisCacheWriter redisCacheWriter =RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);return redisCacheWriter;}@BeanpublicCacheManagercacheManager(RedisCacheWriter redisCacheWriter,RedisCacheConfiguration redisCacheConfiguration){CacheManager cacheManager =newRedisCacheManager(redisCacheWriter, redisCacheConfiguration);((RedisCacheManager) cacheManager).isTransactionAware();return cacheManager;}

3. 自行通过注解和AOP实现缓存

  • 引入AOP相关的包
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.22</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.22</version></dependency><!-- Jackson JSON Processor --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.8</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.8</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.28</version></dependency>
  • 创建@CustomCache
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceCustomCache{/**
   * key的规则,可以使用springEL表达式,可以使用方法执行的一些参数
   */Stringkey();/**
   *  类似前缀
   * @return
   */Stringvalue();}
  • 修改AppConfig
@EnableAspectJAutoProxy// 开启AOP自动代理publicclassAppConfig{@BeanpublicRedisConnectionFactoryredisConnectionFactory(){RedisStandaloneConfiguration redisStandaloneConfiguration =newRedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);// 自适应集群变化RedisConnectionFactory redisConnectionFactory =newJedisConnectionFactory(redisStandaloneConfiguration);return redisConnectionFactory;}@BeanpublicRedisTemplateredisTemplate(RedisConnectionFactory redisConnectionFactory){RedisTemplate redisTemplate =newRedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
        redisTemplate.setValueSerializer(StringRedisSerializer.UTF_8);return redisTemplate;}}
  • 创建 CustomCacheAspect
@Component@AspectpublicclassCustomCacheAspect{@AutowiredprivateRedisTemplate redisTemplate;@Pointcut("@annotation(cn.lazyfennec.cache.redis.annotation.CustomCache)")publicvoidcachePointcut(){}@Around("cachePointcut()")publicObjectdoCache(ProceedingJoinPoint joinPoint){Object obj =null;try{MethodSignature signature =(MethodSignature) joinPoint.getSignature();Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes());CustomCache customCache = method.getAnnotation(CustomCache.class);String cacheKey = customCache.key();String cacheValue = customCache.value();// 创建解析器ExpressionParser parser =newSpelExpressionParser();Expression expression = parser.parseExpression(cacheKey);EvaluationContext context =newStandardEvaluationContext();// 参数// 添加参数Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discover =newDefaultParameterNameDiscoverer();String[] parameterNames = discover.getParameterNames(method);for(int i =0; i < parameterNames.length; i++){
                context.setVariable(parameterNames[i], args[i].toString());}// 解析String key = cacheValue +"::"+ expression.getValue(context).toString();// 1、 判定缓存中是否存在
            obj = redisTemplate.opsForValue().get(key);if(obj !=null)return obj;// 2、不存在则继续行方法
            obj = joinPoint.proceed();// 3、 同步存储value到缓存。
            redisTemplate.opsForValue().set(key, obj);}catch(NoSuchMethodException e){
            e.printStackTrace();}catch(Throwable throwable){
            throwable.printStackTrace();}return obj;}}
  • 新建方法 getUserNameById
@RequestMapping("/custom/name/{id}")@ResponseBodypublicStringgetUserNameById(@PathVariableInteger id){return userService.getUserNameById(id);}
  • 实际实现方法 getUserNameById,使用方式
@Override@CustomCache(value ="custom_user", key ="#id")publicStringgetUserNameById(Integer id){return userMapper.findUserNameById(id);}

标签: spring redis

本文转载自: https://blog.csdn.net/qq_36649893/article/details/135884558
版权归原作者 一杯可乐、 所有, 如有侵权,请联系我们删除。

“Spring与Redis集成”的评论:

还没有评论