在SSH项目中整合redis
利用spring中的AOP 对redis进行统一的管理
1. 相关Jar文件
下载并导入以下3个Jar文件:
commons-pool2-2.4.2.jar、jedis-2.3.1.jar、spring-data-redis-1.3.4.RELEASE.jar。
三个文件分别对应的下载地址:http://www.java2s.com/Code/JarDownload/spring-data/ ,repo1.maven.org/maven2/redis/clients/jedis/,http://commons.apache.org/proper/commons-pool/download_pool.cgi
2. Redis配置文件
在src文件夹下面新建一个redis.properties文件,设置连接Redis的一些属性。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" > <!-- 2.配置通知对象 --> <bean name="redisAdvice" class="com.samton.common.redis.RedisAdvice" ></bean> <!-- 3.开启使用注解完成织入 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="50" /> <property name="maxIdle" value="10" /> <property name="maxWaitMillis" value="1000" /> <property name="testOnBorrow" value="true" /> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="jedisPoolConfig" /> <constructor-arg index="1" value="127.0.0.1" type="java.lang.String"/> <constructor-arg index="2" value="6379" type="int" /> </bean> </beans>
记住一定要在 spring创建jedisPool
的时候,指定参数类型。否则会报错 jedis:Cannot open Redis connection due invalid URI
3. 自定义注解
在src文件夹下面新建一个注解文件;文件内容如下
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface InterfaceCacheableDao { String key(); String fieldKey(); int expireTime() default 3600; }
4. 建立AOP通知类
在src文件夹下面新建一个通知类,用于解析注解统一管理redis;
//通知类 @Aspect public class RedisAdvice { /** * 获取注入对象 */ private RedisUtil redisUtil; public RedisRedisUtil getRedisUtil () { return redisUtil; } public void setRedisUtil (RedisUtil redisUtil) { this.redisUtil= redisUtil; } @SuppressWarnings("unchecked") @Around("@annotation(com.samton.common.redis.dao.InterfaceCacheableDao)") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object result =null; InterfaceCacheableDao cacheable=null; //获取注解上的完整方法 Method proxyMethod = ((MethodSignature)pjp.getSignature()).getMethod(); Method soruceMethod = pjp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes()); cacheable=soruceMethod.getAnnotation(com.samton.common.redis.dao.InterfaceCacheableDao.class); if( null == cacheable ){ cacheable = pjp.getTarget().getClass().getAnnotation(com.samton.common.redis.dao.InterfaceCacheableDao.class); } //解析注解 String fieldKey =parseKey(cacheable.fieldKey(),soruceMethod,pjp.getArgs()); //获取方法的返回类型,让缓存可以返回正确的类型 Class returnType=((MethodSignature)pjp.getSignature()).getReturnType(); //使用redis 的hash进行存取,易于管理 result= redisUtil.hget(cacheable.key(), fieldKey,returnType); if( null == result ){ try { result=pjp.proceed(); Assert.notNull(fieldKey); redisUtil.hset(cacheable.key(),fieldKey, result,cacheable.expireTime()); } catch (Throwable e) { e.printStackTrace(); } } return result; } /** * 获取缓存的key * key 定义在注解上,支持SPEL表达式 * @param pjp * @return */ private String parseKey(String key,Method method,Object [] args){ if(!key.startsWith("#")){ return key; } //获取被拦截方法参数名列表和参数 用于匹配spel 表达式的值 LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); String [] paraNameArr=u.getParameterNames(method); //使用SPEL进行key的解析 ExpressionParser parser = new SpelExpressionParser(); //SPEL上下文 StandardEvaluationContext context = new StandardEvaluationContext(); //把方法参数放入SPEL上下文中 for(int i=0;i<paraNameArr.length;i++){ context.setVariable(paraNameArr[i], args[i]); } return parser.parseExpression(key).getValue(context,String.class); } }
4. 测试
在某个方法上面加上注解
@InterfaceCacheableDao(key="channeDao",fieldKey="#channelId",expireTime=20) public List test(int channelId) { ...... }
大功告成