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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM