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

来源:互联网 发布:lovelive日服数据库 编辑:程序博客网 时间:2024/06/06 05:46

 基于 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依赖: 

    

  1 <properties>  2             <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  3              <!-- spring版本号 -->  4             <spring.version>4.0.6.RELEASE</spring.version>  5             <!-- mybatis版本号 -->  6             <mybatis.version>3.2.7</mybatis.version>  7         </properties>  8   <dependencies>  9    10           <!-- spring核心包 --> 11         <!-- springframe start --> 12         <dependency> 13             <groupId>org.springframework</groupId> 14             <artifactId>spring-core</artifactId> 15             <version>${spring.version}</version> 16         </dependency> 17  18         <dependency> 19             <groupId>org.springframework</groupId> 20             <artifactId>spring-web</artifactId> 21             <version>${spring.version}</version> 22         </dependency> 23  24         <dependency> 25             <groupId>org.springframework</groupId> 26             <artifactId>spring-oxm</artifactId> 27             <version>${spring.version}</version> 28         </dependency> 29  30         <dependency> 31             <groupId>org.springframework</groupId> 32             <artifactId>spring-tx</artifactId> 33             <version>${spring.version}</version> 34         </dependency> 35  36         <dependency> 37             <groupId>org.springframework</groupId> 38             <artifactId>spring-aop</artifactId> 39             <version>${spring.version}</version> 40         </dependency> 41  42         <dependency> 43             <groupId>org.springframework</groupId> 44             <artifactId>spring-jdbc</artifactId> 45             <version>${spring.version}</version> 46         </dependency> 47  48         <dependency> 49             <groupId>org.springframework</groupId> 50             <artifactId>spring-webmvc</artifactId> 51             <version>${spring.version}</version> 52         </dependency> 53  54         <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support --> 55         <dependency> 56             <groupId>org.springframework</groupId> 57             <artifactId>spring-context-support</artifactId> 58             <version>4.0.6.RELEASE</version> 59         </dependency> 60  61         <dependency> 62             <groupId>org.springframework</groupId> 63             <artifactId>spring-context</artifactId> 64             <exclusions> 65                 <exclusion> 66                     <groupId>commons-logging</groupId> 67                     <artifactId>commons-logging</artifactId> 68                 </exclusion> 69             </exclusions> 70             <version>${spring.version}</version> 71         </dependency> 72         <dependency> 73             <groupId>org.springframework</groupId> 74             <artifactId>spring-test</artifactId> 75             <version>${spring.version}</version> 76         </dependency> 77         <!-- springframe end --> 78  79           <!-- aop注解  --> 80            81         <dependency> 82             <groupId>org.aspectj</groupId> 83             <artifactId>aspectjrt</artifactId> 84             <version>1.6.12</version> 85         </dependency> 86         <dependency> 87             <groupId>org.aspectj</groupId> 88             <artifactId>aspectjweaver</artifactId> 89             <version>1.6.12</version> 90         </dependency> 91         <dependency> 92             <groupId>cglib</groupId> 93             <artifactId>cglib</artifactId> 94             <version>2.2</version> 95         </dependency> 96            97           <!-- mysql驱动包 --> 98         <dependency> 99             <groupId>mysql</groupId>100             <artifactId>mysql-connector-java</artifactId>101             <version>5.1.31</version>102         </dependency>103           104           <!-- dbcp2连接池 -->105         <dependency>106             <groupId>org.apache.commons</groupId>107             <artifactId>commons-dbcp2</artifactId>108             <version>2.0.1</version>109         </dependency>110 111         <!-- json数据 -->112         <dependency>113             <groupId>org.codehaus.jackson</groupId>114             <artifactId>jackson-mapper-asl</artifactId>115             <version>1.9.13</version>116         </dependency>117 118           <!-- mybatis核心包 -->119         <dependency>120             <groupId>org.mybatis</groupId>121             <artifactId>mybatis</artifactId>122             <version>${mybatis.version}</version>123         </dependency>124         <!-- mybatis/spring包 -->125         <dependency>126             <groupId>org.mybatis</groupId>127             <artifactId>mybatis-spring</artifactId>128             <version>1.2.2</version>129         </dependency>130   131           <dependency>  132             <groupId>org.springframework.data</groupId>  133             <artifactId>spring-data-redis</artifactId>  134             <version>1.6.1.RELEASE</version>  135         </dependency>  136          <dependency>  137             <groupId>redis.clients</groupId>  138             <artifactId>jedis</artifactId>  139             <version>2.7.3</version>  140         </dependency> 141   142           <!-- servlet-api -->143         <dependency>144             <groupId>javax.servlet</groupId>145             <artifactId>javax.servlet-api</artifactId>146             <version>3.0.1</version>147             <scope>provided</scope>148         </dependency>149         <dependency>150             <groupId>javax.servlet.jsp</groupId>151             <artifactId>jsp-api</artifactId>152             <version>2.2</version>153             <scope>provided</scope>154         </dependency>155         <!-- servlet-api end -->156   157           <dependency>158             <groupId>log4j</groupId>159             <artifactId>log4j</artifactId>160             <version>1.2.17</version>161         </dependency>162   </dependencies>163   

 

   这里只给出redis 的相关配置

    在applicationContext-dao.xml 里添加

 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 4     xmlns:context="http://www.springframework.org/schema/context" 5     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 6     xmlns:util="http://www.springframework.org/schema/util" 7     xsi:schemaLocation="http://www.springframework.org/schema/beans 8     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 9     http://www.springframework.org/schema/context10     http://www.springframework.org/schema/context/spring-context-3.2.xsd11     http://www.springframework.org/schema/tx12     http://www.springframework.org/schema/tx/spring-tx-3.2.xsd13     http://www.springframework.org/schema/aop14     http://www.springframework.org/schema/aop/spring-aop-3.2.xsd15     http://www.springframework.org/schema/util 16     http://www.springframework.org/schema/util/spring-util-3.2.xsd">17         18         19         <!-- 加载db.properties文件中的内容,db.properties文件中key命名要有一定的特殊规则 -->20         <context:property-placeholder location="classpath:properties/db.properties" />21         22         23         24         <!-- 配置数据源 ,dbcp -->25         26         <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">27         <property name="driverClassName" value="${jdbc.driver}" />28         <property name="url" value="${jdbc.url}" />29         <property name="username" value="${jdbc.username}" />30         <property name="password" value="${jdbc.password}" />31         </bean>32 33 34         <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"35         p:dataSource-ref="dataSource" p:configLocation="classpath:mybatis/sqlMapConfig.xml"36         ></bean>37               <!-- Redis和缓存配置开始 -->  38             <!-- jedis 配置 -->  39             <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >  40                   <property name="maxIdle" value="100" />  41                   <property name="maxWaitMillis" value="1000" />  42                   <property name="testOnBorrow" value="true" />  43             </bean >  44             45             <!-- redis连接池 -->46                 <bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="close">47                     <constructor-arg name="poolConfig" ref="poolConfig"/>48                     <constructor-arg name="host" value="127.0.0.1"/>49                     <constructor-arg name="port" value="6379"/>50                 </bean>51 52               <!-- redis服务器中心 -->  53             <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >  54                   <property name="poolConfig" ref="poolConfig" />  55                   <property name="port" value="6379" />  56                   <property name="hostName" value="127.0.0.1" />  57                   <!-- <property name="password" value="${redis.password}" /> --> 58                   <property name="timeout" value="10000" ></property>  59             </bean >  60             <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >  61                   <property name="connectionFactory" ref="connectionFactory" />  62                   <property name="keySerializer" >  63                       <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  64                   </property>  65                   <property name="valueSerializer" >  66                       <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  67                   </property>  68             </bean > 69             70             71             72             73             74             <!-- cache配置 -->  75             <bean id="putCache" class="com.spring_redis.cache.PutCacheAOP" >  76                   <property name="redisTemplate" ref="redisTemplate" />77             </bean>  78             79             <!-- cache配置 -->  80              <bean id="getCache" class="com.spring_redis.cache.GetCacheAOP" >  81                    <property name="redisTemplate" ref="redisTemplate" />82              </bean>  83              84              <!-- Redis和缓存配置结束 -->85             86             <!-- mapper扫描器 -->87             <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">88                 <!-- 扫描包路径,如果需要扫描多个包,中间使用半角逗号隔开 -->89                 <property name="basePackage" value="com.spring_redis.mapper"></property>90                 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>91             </bean>92             93             <bean id="roomservice" class="com.spring_redis.service.impl.RoomServiceImpl" >  94                    95              </bean>  96             97 </beans>

 

  springmvc.xml

 1 <beans xmlns="http://www.springframework.org/schema/beans" 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" 3     xmlns:context="http://www.springframework.org/schema/context" 4     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 5     xsi:schemaLocation="http://www.springframework.org/schema/beans  6         http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  7         http://www.springframework.org/schema/mvc  8         http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd  9         http://www.springframework.org/schema/context 10         http://www.springframework.org/schema/context/spring-context-3.2.xsd 11         http://www.springframework.org/schema/aop 12         http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 13         http://www.springframework.org/schema/tx14         http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">15 16     <aop:aspectj-autoproxy proxy-target-class="true"/>17 18     <!-- 可以扫描controller、service、... 这里让扫描controller,指定controller的包 com.ssm.controlle -->19     <context:component-scan base-package="com.spring_redis">20     </context:component-scan>21     <!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置 mvc:annotation-driven默认加载很多的参数绑定方法 -->22     <mvc:annotation-driven />23     <!-- 视图解析器 解析jsp解析,默认使用jstl标签,classpath下的得有jstl的包 -->24     <bean25         class="org.springframework.web.servlet.view.InternalResourceViewResolver">26         <!-- 配置jsp路径的前缀 <property name="prefix" value="/jsp/"/> -->27         <!-- 配置jsp路径的后缀 -->28         <property name="suffix" value=".jsp" />29     </bean>30 31     32 </beans>

   <aop:aspectj-autoproxy proxy-target-class="true"/>  开启注解这个一定要写到springmvc.xml里,否则注解会不起作用

 

  那重点开始了

  创建自定义注解

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

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

 

  配置切面

  1 package com.spring_redis.cache;  2   3 import java.io.Serializable;  4 import java.lang.reflect.Method;  5   6   7 import org.aspectj.lang.JoinPoint;  8 import org.aspectj.lang.ProceedingJoinPoint;  9 import org.aspectj.lang.annotation.Around; 10 import org.aspectj.lang.annotation.Aspect; 11 import org.aspectj.lang.annotation.Pointcut; 12 import org.aspectj.lang.reflect.MethodSignature; 13 import org.springframework.beans.factory.annotation.Autowired; 14 import org.springframework.data.redis.core.RedisTemplate; 15 import org.springframework.stereotype.Component; 16  17 import com.spring_redis.util.RedisCache; 18  19 @Component 20 @Aspect 21 public class GetCacheAOP  {   22        23     @Autowired 24     private RedisTemplate<Serializable, Object> redisTemplate; 25      26     private RedisCache redisCache = new RedisCache(); 27    28        29     @Pointcut("@annotation(com.spring_redis.cache.GetCache)")   30     public void getCache(){ 31         System.out.println("我是一个切入点");   32     }   33      34     /**  35      * 在所有标注@getCache的地方切入  36      * @param joinPoint  37      */ 38     @Around("getCache()") 39     public Object beforeExec(ProceedingJoinPoint joinPoint){   40          41          42         //前置:到redis中查询缓存 43         System.out.println("调用从redis中查询的方法..."); 44          45         //redis中key格式:    id 46         String redisKey = getCacheKey(joinPoint); 47          48         //获取从redis中查询到的对象 49         Object objectFromRedis = redisCache.getDataFromRedis(redisKey); 50          51         //如果查询到了 52         if(null != objectFromRedis){ 53             System.out.println("从redis中查询到了数据...不需要查询数据库"); 54             return objectFromRedis; 55         } 56          57         System.out.println("没有从redis中查到数据..."); 58          59         //没有查到,那么查询数据库 60         Object object = null; 61         try { 62             object = joinPoint.proceed(); 63         } catch (Throwable e) { 64              65             e.printStackTrace(); 66         } 67          68         System.out.println("从数据库中查询的数据..."); 69          70         //后置:将数据库中查询的数据放到redis中 71         System.out.println("调用把数据库查询的数据存储到redis中的方法..."); 72          73         redisCache.setDataToRedis(redisKey, object); 74         System.out.println("redis中的数据..."+object.toString()); 75         //将查询到的数据返回 76         return object; 77     } 78      79     /** 80      * 根据类名、方法名和参数值获取唯一的缓存键 81      * @return 格式为 "包名.类名.方法名.参数类型.参数值",类似 "your.package.SomeService.getById(int).123" 82      */ 83     84     @SuppressWarnings("unused") 85     private String getCacheKey(ProceedingJoinPoint joinPoint) { 86      87      88         MethodSignature ms=(MethodSignature) joinPoint.getSignature();   89         Method method=ms.getMethod();   90         String ActionName = method.getAnnotation(GetCache.class).name();   91         String fieldList = method.getAnnotation(GetCache.class).value();   92         //System.out.println("签名是"+ms.toString()); 93         for (String field:fieldList.split(","))    94              ActionName +="."+field; 95      96         //先获取目标方法参数 97         String id = null; 98         Object[] args = joinPoint.getArgs(); 99         if (args != null && args.length > 0) {100             id = String.valueOf(args[0]);101         }102         103         ActionName += "="+id;104         String redisKey = ms+"."+ActionName;105         return redisKey;106     }107     108     109     public void setRedisTemplate(  110             RedisTemplate<Serializable, Object> redisTemplate) {  111         this.redisTemplate = redisTemplate;  112     }113 }  

  

 @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

 1 /** 2  *  3  * @author     cmy 4  * @date     2016-10-22 5  * @description test 6  */ 7 public interface RoomService { 8      9     10     int insert(Room room)throws Exception;11     12     13     Room selectByPrimaryKey(Integer id)throws Exception;14     15 }16 17 // 实现18 /**19  * @author         cmy20  * @date         2016-10-2221  * @description  test 实现22  */23 public class RoomServiceImpl implements RoomService{24 25     @Autowired26     private RoomMapper mapper;27     28     @Override29     public int insert(Room room) throws Exception {30         31         return mapper.insert(room);32     }33 34     @Override35     public Room selectByPrimaryKey(Integer id) throws Exception {36         37         return mapper.selectByPrimaryKey(id);38     }39 40     41 }

   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

 1 public class RedisCache { 2      3     @Autowired 4     private JedisPool jedisPool = new JedisPool(); 5      6  7     //从redis缓存中查询,反序列化 8     public Object getDataFromRedis(String redisKey){ 9         //查询10         Jedis jedis = jedisPool.getResource();11         byte[] result = jedis.get(redisKey.getBytes());12         13         //如果查询没有为空14         if(null == result){15             return null;16         }17         18         //查询到了,反序列化19         return SerializeUtil.unSerialize(result);20     }21     22     //将数据库中查询到的数据放入redis23     public void setDataToRedis(String redisKey, Object obj){24         25         //序列化26         byte[] bytes = SerializeUtil.serialize(obj);27         28         //存入redis29         Jedis jedis = jedisPool.getResource();30         String success = jedis.set(redisKey.getBytes(), bytes);31         32         if("OK".equals(success)){33             System.out.println("数据成功保存到redis...");34         }35     }36 }

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

 1 /** 2  *  3  * @Description: 序列化反序列化工具 4  */ 5 public class SerializeUtil { 6     /** 7      *  8      * 序列化 9      */10     public static byte[] serialize(Object obj){11         12         ObjectOutputStream oos = null;13         ByteArrayOutputStream baos = null;14         15         try {16             //序列化17             baos = new ByteArrayOutputStream();18             oos = new ObjectOutputStream(baos);19             20             oos.writeObject(obj);21             byte[] byteArray = baos.toByteArray();22             return byteArray;23             24         } catch (IOException e) {25             e.printStackTrace();26         }    27         return null;28     }29     30     /**31      * 32      * 反序列化33      * @param bytes34      * @return35      */36     public static Object unSerialize(byte[] bytes){37         38         ByteArrayInputStream bais = null;39         40         try {41             //反序列化为对象42             bais = new ByteArrayInputStream(bytes);43             ObjectInputStream ois = new ObjectInputStream(bais);44             return ois.readObject();45             46         } catch (Exception e) {47             e.printStackTrace();48         }49         return null;50     }51 }

 

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

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

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

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

阅读全文
0 0
原创粉丝点击