Spring整合Redis使用注解模式开发

第一次写博客,好紧张~~

最近在学习Redis,需求是将之前做的一个小型商城的一些数据放入Redis缓存中,避免每次都频繁的去数据库查询,降低效率。

属于摸索阶段,只能勉强实现功能,其中可能会有些有问题的地方,希望看到这篇文章的大佬能指出纠正。


项目环境:Spring+SpringMVC+Hibernate

  1. Spring-version:
    5.0.6.RELEASE
  2. Hibernate-version:
    5.2.6.Final

我使用的都是目前最新的版本


整合Redis所需的依赖


    redis.clients
    jedis
    2.9.0


    org.springframework.data
    spring-data-redis
    2.0.1.RELEASE

在使用注解模式之前,我是使用编码方式完成了所需功能,下面把这种方式也说一下吧。

application-redis.xml配置文件


    
        
        
        
        
        
        
        
        
    

    
    
        
        
        
        
    

    
    

    
    
        
        
        
        
        
    

Spring的主配置文件就不贴了,不使用缓存注解模式的话就没有需要添加的地方,就是一个普通的Spring+Hibernate的整合文件。


 配置完成后就可以开始编写代码了,其实逻辑很简单,访问的时候先通过Key判断缓存中是否存在数据,存在就直接取出数据转换格式后返回,不存在就进入数据库查询再放入缓存,返回数据。

我以我的需求为例,我目前需要将首页的广告放入缓存,从缓存中获取,因为这些资源是公开的,对所有人可见的,不必每次去数据库查询回来,所以放在缓存最合适,提高效率。

这是我的ADServiceImpl中实现获取的方法

@Override
    public List findAllByType() {
        try {
            //去缓存中查
            String adList = redisServiceImpl.get("adList");
            //不为null
            if (!WoUtil.isEmpty(adList)) {
                List ads = JSONArray.parseArray(adList,AD.class);
                //直接返回数据
                return ads;
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        //缓存中不存在,就进入数据库查询,这是我自己封装的一个BaseDao的根据条件查询的方法
        List adList = adDaoImpl.findAllBy(new HashMap(){
            {
                this.put("type",AD_TYPE);
            }
        });
        try {
            //从数据库查出后转换类型再放入缓存
            String jsonStr = JSONArray.toJSONString(adList);
            redisServiceImpl.set("adList",jsonStr);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return adList;
    }

我这里使用的alibaba提供的fastJson,让对象和字符串之间可以轻松转换,不用使用序列化和反序列化了。

使用try{}catch{}保证缓存操作出问题不会影响正常的查询功能。

上面这样就可以完成对redis的操作了,但当我写完第一个后问题就来了,我不止广告需要存入缓存,还有其他很多地方都需要存入,比如商品分类和商品这些,那我不是都要在他们的Service加上这些代码?而且不难看出,这些代码可以说都是重复的 。

Spring整合Redis使用注解模式开发_第1张图片

Spring整合Redis使用注解模式开发_第2张图片

(⊙o⊙)…我使用的idea,设置了下背景,还是很好看的吧。。。。。

这两部分不是我们实际需要的代码,所以看起来很臃肿,一点也不优雅。

如果每一个Service都这样写那也太麻烦了吧,所以我找了些注解模式的文章学习,使用注解的话,配置文件中就需要添加一些东西了。

application-redis.xml,在刚才的基础上添加内容 


        
            
                //操作缓存的实现类
                
                    
                    //这里的value就是使用注解时使用的,用来找到name然后进入到缓存的实现类
                    
                    //这里根据我的需求直接返回的时候就是我需要的类型,所以传一个type
                    
                    //根据需求给缓存实现类添加属性,比如过期时间,我这里暂时不用
                    <---->
                
                
                    
                    
                    
                
            
        
    

在这里我使用的是

org.springframework.cache.support.SimpleCacheManager;

网上很多都是用的

org.springframework.data.redis.cache.RedisCacheManager.

我使用另一个会一直报错,找了很久也没找到问题的原因,希望有大佬能告诉我。

 

这个必须在spring的主配置文件中,cache-manager的名字必须和application-redis中的cacheManager一致

 然后开始编写操作缓存的实现类

//实现Cache接口
public class RedisCache implements Cache {

    //缓存的名称
    private String name;

    //返回的类型
    private Class type;

    //Spring提供的操作Reids的工具
    private RedisTemplate redisTemplate;

    public void setName(String name) {
        this.name = name;
    }

    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Object getNativeCache() {
        return this.redisTemplate;
    }


    //通过key查询缓存
    @Override
    public ValueWrapper get(Object key) {
        if (WoUtil.isEmpty(key)) {
            return null;
        }else {
            final String finalKey;
            if (key instanceof String) {
                finalKey = (String) key;
            }else {
                finalKey = key.toString();
            }
            Object object = null;
            object = redisTemplate.execute(new RedisCallback() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                        byte[] key = finalKey.getBytes();
                        byte[] value = connection.get(key);
                        if (value == null) {
                            return null;
                        }
                        String val = new String(value);
                    List tList = JSONArray.parseArray(val, type);
                    return tList;
                }
            });
            return (object != null ? new SimpleValueWrapper(object) : null);
        }
    }

    @Override
    public  T get(Object key, final Class type) {
        return null;
    }

    @Override
    public  T get(Object o, Callable callable) {
        return null;
    }


    //向缓存存放数据
    @Override
    public void put(Object key , Object value) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
            return;
        } else {
            final String finalKey;
            if (key instanceof String) {
                finalKey = (String) key;
            } else {
                finalKey = key.toString();
            }
            if (!StringUtils.isEmpty(finalKey)) {
                final Object finalValue = value;
                redisTemplate.execute(new RedisCallback() {
                    @Override
                    public Boolean doInRedis(RedisConnection connection) {
                        String jsonStr = JSONArray.toJSONString(finalValue);
                        connection.set(finalKey.getBytes(),jsonStr.getBytes());
                        return true;
                    }
                });
            }
        }
    }


    @Override
    public ValueWrapper putIfAbsent(Object o, Object o1) {
        return null;
    }


    //通过key删除缓存的数据
    @Override
    public void evict(Object key) {
        if (WoUtil.isEmpty(key)) {
            return;
        }else {
            final String finalKey;
            if (key instanceof String) {
                finalKey = (String) key;
            }else {
                finalKey = key.toString();
            }
            redisTemplate.execute(new RedisCallback() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.del(finalKey.getBytes());
                }
            });
        }
    }

    @Override
    public void clear() {

    }
}
 
   

这里面最主要的就是put和get方法,我只实现了put和get和一个evict就目前够用了,方法逻辑很简单,判断key是否为空,不为空就调用对应的方法,因为我都是获取的List,所有返回的是List,根据的自己的需求编写。

下面就是如何使用了,我以商品为例

    //value对应redis配置中的value
    //key只要保证唯一就可以了,我这里用的root获取当前被调用的对象的Class
    @Override
    @Cacheable(value = "goodsCache", key = "#root.targetClass")
    public List getList() {
        List goodsList = goodsDaoImpl.findAll();
        return goodsList;
    }

 这样看起来代码就很优雅了,里面只有我们真正需要的代码了。

Spring提供的root对象的使用

属性名称

描述

示例

methodName

当前方法名

#root.methodName

method

当前方法

#root.method.name

target

当前被调用的对象

#root.target

targetClass

当前被调用的对象的class

#root.targetClass

args

当前方法参数组成的数组

#root.args[0]

caches

当前被调用的方法使用的Cache

#root.caches[0].name

 


第一次写博客,逻辑很乱,只会把自己做的东西给大家看看,也没怎么分析,实在是抱歉,有时间会多写写锻炼自己的。 

你可能感兴趣的:(Spring整合Redis使用注解模式开发)