zoukankan      html  css  js  c++  java
  • 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依赖: 

        

      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/context
    10     http://www.springframework.org/schema/context/spring-context-3.2.xsd
    11     http://www.springframework.org/schema/tx
    12     http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    13     http://www.springframework.org/schema/aop
    14     http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
    15     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/tx
    14         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     <bean
    25         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         cmy
    20  * @date         2016-10-22
    21  * @description  test 实现
    22  */
    23 public class RoomServiceImpl implements RoomService{
    24 
    25     @Autowired
    26     private RoomMapper mapper;
    27     
    28     @Override
    29     public int insert(Room room) throws Exception {
    30         
    31         return mapper.insert(room);
    32     }
    33 
    34     @Override
    35     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     //将数据库中查询到的数据放入redis
    23     public void setDataToRedis(String redisKey, Object obj){
    24         
    25         //序列化
    26         byte[] bytes = SerializeUtil.serialize(obj);
    27         
    28         //存入redis
    29         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 bytes
    34      * @return
    35      */
    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

  • 相关阅读:
    centos7 安装prometheus node_exporter
    RMAN备份演练初级篇
    RMAN命令
    oracle数据库的归档模式
    oracle的会话(session)
    oracle的例程
    oracle热备份
    Oracle数据库归档模式的切换及其相关操作详解
    Oracle角色
    类名.class, class.forName(), getClass()区别
  • 原文地址:https://www.cnblogs.com/cmyxn/p/5990974.html
Copyright © 2011-2022 走看看