ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存

基于 ssm + maven + redis 使用自定义注解 利用aop基于AspectJ方式 实现redis缓存

  如何能更简洁的利用aop实现redis缓存,话不多说,上demo

  需求:
    数据查询时每次都需要从数据库查询数据,数据库压力很大,查询速度慢,
    因此设置缓存层,查询数据时先从redis中查询,如果查询不到,则到数据库中查询
    然后将数据库中查询的数据放到redis中一份,下次查询时就能直接从redis中查到,不需要查询数据库了

  实现过程:

      先搭建ssm的架子,引入redis,编写redis 缓存方法 RedisCache.java以及序列化用到的工具类 


      自定义注解 getCache 目的:
            被这个注解标记的方法实现aop
            防止redis key重复

     编写切面
      @Aspect

        @Pointcut("@annotation(com.spring_redis.cache.GetCache)")
        切入点为自定义注解 即每个被该注解标记的方法实现通知

        @Around("getCache()")
        利用环绕通知 
          过程: 查询时,先查询redis 如果存在key-value,则返回不查询
          如果不存在,则查询数据库,之后将查询到的数据存入到redis缓存中
          redis key格式:为了防止key冲突,创建的key格式为:

          包名.类名.方法名.参数类型.参数值",类似 "your.package.SomeService.getById(integer).123"

目录结构:


maven依赖:


            UTF-8
             
            4.0.6.RELEASE
            
            3.2.7
        
  
  
          
        
        
            org.springframework
            spring-core
            ${spring.version}
        

        
            org.springframework
            spring-web
            ${spring.version}
        

        
            org.springframework
            spring-oxm
            ${spring.version}
        

        
            org.springframework
            spring-tx
            ${spring.version}
        

        
            org.springframework
            spring-aop
            ${spring.version}
        

        
            org.springframework
            spring-jdbc
            ${spring.version}
        

        
            org.springframework
            spring-webmvc
            ${spring.version}
        

        
        
            org.springframework
            spring-context-support
            4.0.6.RELEASE
        

        
            org.springframework
            spring-context
            
                
                    commons-logging
                    commons-logging
                
            
            ${spring.version}
        
        
            org.springframework
            spring-test
            ${spring.version}
        
        

          
          
        
            org.aspectj
            aspectjrt
            1.6.12
        
        
            org.aspectj
            aspectjweaver
            1.6.12
        
        
            cglib
            cglib
            2.2
        
          
          
        
            mysql
            mysql-connector-java
            5.1.31
        
          
          
        
            org.apache.commons
            commons-dbcp2
            2.0.1
        

        
        
            org.codehaus.jackson
            jackson-mapper-asl
            1.9.13
        

          
        
            org.mybatis
            mybatis
            ${mybatis.version}
        
        
        
            org.mybatis
            mybatis-spring
            1.2.2
        
  
            
            org.springframework.data  
            spring-data-redis  
            1.6.1.RELEASE  
          
           
            redis.clients  
            jedis  
            2.7.3  
         
  
          
        
            javax.servlet
            javax.servlet-api
            3.0.1
            provided
        
        
            javax.servlet.jsp
            jsp-api
            2.2
            provided
        
        
  
          
            log4j
            log4j
            1.2.17
        
  

这里只给出redis 的相关配置

    在applicationContext-dao.xml 里添加



        
        
        
        
        
        
        
        
        
        
        
        
        
        
        


        
                
              
              
                    
                    
                    
              
            
            
                
                    
                    
                    
                

                
              
                    
                    
                    
                   
                    
              
              
                    
                    
                        
                    
                    
                        
                    
             
            
            
            
            
            
              
              
                  
              
            
              
               
                   
               
             
             
            
            
            
                
                
                
            
            
              
                   
               
            

 springmvc.xml



    

    
    
    
    
    
    
    
        
        
        
    

    

   开启注解这个一定要写到springmvc.xml里,否则注解会不起作用

 

  那重点开始了

  创建自定义注解

/** 
 * 自定义注解,对于查询使用缓存的方法加入该注解 
 * @author Chenth 
 */  
@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.METHOD})  
public @interface GetCache {  
    String name() default "";  
    String value() default "";  
}

被这个自定义注解所标记的方法将实现下面的切面

 

  配置切面


package com.spring_redis.cache;

import java.io.Serializable;
import java.lang.reflect.Method;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.spring_redis.util.RedisCache;

@Component
@Aspect
public class GetCacheAOP  {  
      
    @Autowired
    private RedisTemplate redisTemplate;
    
    private RedisCache redisCache = new RedisCache();
  
      
    @Pointcut("@annotation(com.spring_redis.cache.GetCache)")  
    public void getCache(){
        System.out.println("我是一个切入点");  
    }  
    
    /** 
     * 在所有标注@getCache的地方切入 
     * @param joinPoint 
     */
    @Around("getCache()")
    public Object beforeExec(ProceedingJoinPoint joinPoint){  
        
        
        //前置:到redis中查询缓存
        System.out.println("调用从redis中查询的方法...");
        
        //redis中key格式:    id
        String redisKey = getCacheKey(joinPoint);
        
        //获取从redis中查询到的对象
        Object objectFromRedis = redisCache.getDataFromRedis(redisKey);
        
        //如果查询到了
        if(null != objectFromRedis){
            System.out.println("从redis中查询到了数据...不需要查询数据库");
            return objectFromRedis;
        }
        
        System.out.println("没有从redis中查到数据...");
        
        //没有查到,那么查询数据库
        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Throwable e) {
            
            e.printStackTrace();
        }
        
        System.out.println("从数据库中查询的数据...");
        
        //后置:将数据库中查询的数据放到redis中
        System.out.println("调用把数据库查询的数据存储到redis中的方法...");
        
        redisCache.setDataToRedis(redisKey, object);
        System.out.println("redis中的数据..."+object.toString());
        //将查询到的数据返回
        return object;
    }
    
    /**
     * 根据类名、方法名和参数值获取唯一的缓存键
     * @return 格式为 "包名.类名.方法名.参数类型.参数值",类似 "your.package.SomeService.getById(int).123"
     */
   
    @SuppressWarnings("unused")
    private String getCacheKey(ProceedingJoinPoint joinPoint) {
    
    
        MethodSignature ms=(MethodSignature) joinPoint.getSignature();  
        Method method=ms.getMethod();  
        String ActionName = method.getAnnotation(GetCache.class).name();  
        String fieldList = method.getAnnotation(GetCache.class).value();  
        //System.out.println("签名是"+ms.toString());
        for (String field:fieldList.split(","))   
             ActionName +="."+field;
    
        //先获取目标方法参数
        String id = null;
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            id = String.valueOf(args[0]);
        }
        
        ActionName += "="+id;
        String redisKey = ms+"."+ActionName;
        return redisKey;
    }
    
    
    public void setRedisTemplate(  
            RedisTemplate redisTemplate) {  
        this.redisTemplate = redisTemplate;  
    }
}

@Pointcut("@annotation(com.spring_redis.cache.GetCache)") 这个切入点的作用是
                                      在所有标注@getCache的地方切入 
 @Around("getCache()")这里用的是后置通知,即查询之前先查询redis,如果有数据就返回数据,没有就穿透的数据库查询数据,之后再缓存到redis中

 

  这里并没有太多的讲解配置ssm框架,可能后续会写关于spring+springmvc+mybatis的框架整合

  编写mapper层,service层,controller层

  mapper

/**
 * 
 * @author     cmy
 * @date     2016-10-22
 * @description 持久化
 */

public interface RoomMapper {

    @Insert("insert into room(roomName,address) values(#{roomName},#{addRess})")
    int insert(Room room);

    @Select("select * from room where id=#{id}")
    public Room selectByPrimaryKey(@Param("id")Integer id);

}
service
/**
 * 
 * @author     cmy
 * @date     2016-10-22
 * @description test
 */
public interface RoomService {
    
    
    int insert(Room room)throws Exception;
    
    
    Room selectByPrimaryKey(Integer id)throws Exception;
    
}

// 实现
/**
 * @author         cmy
 * @date         2016-10-22
 * @description  test 实现
 */
public class RoomServiceImpl implements RoomService{

    @Autowired
    private RoomMapper mapper;
    
    @Override
    public int insert(Room room) throws Exception {
        
        return mapper.insert(room);
    }

    @Override
    public Room selectByPrimaryKey(Integer id) throws Exception {
        
        return mapper.selectByPrimaryKey(id);
    }

    
}

controller

/**
 * 
 * @author     cmy
 * @date     2016-10-22
 * @description test controller
 */

@Controller
@RequestMapping("room")
public class RoomController {

    @Autowired
    private RoomService  roomService;
    
    @GetCache(name="room",value="id")
    @RequestMapping("selectByPrimaryKey")
    public @ResponseBody Object roomList(Integer id) throws Exception{  
        System.out.println("已查询到数据,准备缓存到redis...  "+roomService.selectByPrimaryKey(id).getRoomName());
        return roomService.selectByPrimaryKey(id);
    }
    

}

缓存要用到的工具类  RedisCache:

public class RedisCache {
    
    @Autowired
    private JedisPool jedisPool = new JedisPool();
    

    //从redis缓存中查询,反序列化
    public Object getDataFromRedis(String redisKey){
        //查询
        Jedis jedis = jedisPool.getResource();
        byte[] result = jedis.get(redisKey.getBytes());
        
        //如果查询没有为空
        if(null == result){
            return null;
        }
        
        //查询到了,反序列化
        return SerializeUtil.unSerialize(result);
    }
    
    //将数据库中查询到的数据放入redis
    public void setDataToRedis(String redisKey, Object obj){
        
        //序列化
        byte[] bytes = SerializeUtil.serialize(obj);
        
        //存入redis
        Jedis jedis = jedisPool.getResource();
        String success = jedis.set(redisKey.getBytes(), bytes);
        
        if("OK".equals(success)){
            System.out.println("数据成功保存到redis...");
        }
    }
}

缓存要用到的序列化和反序列化工具

/**
 * 
 * @Description: 序列化反序列化工具
 */
public class SerializeUtil {
    /**
     * 
     * 序列化
     */
    public static byte[] serialize(Object obj){
        
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        
        try {
            //序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            
            oos.writeObject(obj);
            byte[] byteArray = baos.toByteArray();
            return byteArray;
            
        } catch (IOException e) {
            e.printStackTrace();
        }    
        return null;
    }
    
    /**
     * 
     * 反序列化
     * @param bytes
     * @return
     */
    public static Object unSerialize(byte[] bytes){
        
        ByteArrayInputStream bais = null;
        
        try {
            //反序列化为对象
            bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}


以上就是利用aop+自定义注解实现 redis缓存的过程了

      有不对之处,还望指出 欢迎留言

有参考到的文章:http://www.cnblogs.com/mrlinfeng/p/5857775.html

        http://blog.csdn.net/chentian610/article/details/51012789



你可能感兴趣的:(redis)