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
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
- aop切面和redis实现自定义缓存注解
- Spring Cache+Redis实现自定义注解缓存
- Redis+MyBatis自定义注解实现缓存
- 利用Spring的aop整合redis缓存
- spring-redis缓存方案学习三:基于aop的自定义注解开发
- spring-redis缓存方案学习三:基于aop的自定义注解开发
- 使用AOP 实现Redis缓存注解,支持SPEL(转)
- 使用AOP 实现Redis缓存注解,支持SPEL
- 使用AOP 实现Redis缓存注解,支持SPEL
- 深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
- spring集成redis缓存的注解实现
- ssm+redis缓存配置
- SSM-Redis 缓存配置
- SSM框架下的redis缓存
- spring aop结合redis实现数据缓存
- 使用Spring AOP注解实现Redis缓存 适合复杂业务场合
- SpringCloud的Ribbon负载均衡
- Redis中有序集(Sorted Set)判断某个键的成员存在的设计
- Java中的ReentrantLock和synchronized两种锁定机制的对比
- qlExpress实践手册-常用语法介绍
- 泛海为上海董家渡项目融资90亿 世茂5亿债券将上市
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
- spring boot 添加admin监控
- qt学习笔记之QPushButton
- LeetCode week 8 : Longest Increasing Subsequence
- php 字符串操作函数substr()截取中文子串乱码问题
- ECharts_04_loading
- 六-1 检查和编辑页面和样式 概述
- 解决bootstarp-datetimepicker 默认年月模式,默认月份比实际月份多两个月bug
- 为什么国外的 App 很少会有开屏广告?