说明
redis是一个nosql数据库,具有高速,数据结构对程序员透明【数据类型支持list、set等结构】等特点。
redis的使用前提:
(1.)redis 是一个数据库,和mysql相似,使用redis首先得安装redis数据库;
(2.)为应用程序添加必要的配置:例如mysql中的四要素;
(3.)配置redis相关的AOP【基于方法拦截】;
(4.)使用redis相关的API;
Spring整合redis的相关配置:
<!-- jedis 配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- redis服务器中心 -->
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="poolConfig" ref="poolConfig" />
<property name="port" value="${redis.port}" />
<property name="hostName" value="${redis.host}" />
<property name="password" value="${redis.password}" />
<property name="timeout" value="${redis.timeout}"></property>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
</bean>
<!-- cache配置 -->
<bean id="methodCacheInterceptor" class="com.crossoverJie.intercept.MethodCacheInterceptor">
<property name="redisUtil" ref="redisUtil" />
</bean>
<bean id="redisUtil" class="com.crossoverJie.util.RedisUtil">
<property name="redisTemplate" ref="redisTemplate" />
</bean>
<bean id="dataSourceExchange" class="com.crossoverJie.util.DataSourceExchange" />
<!--配置切面拦截方法 -->
<aop:config>
<!--将com.crossoverJie.service包下的所有select开头的方法加入拦截 去掉select则加入所有方法 -->
<aop:pointcut id="controllerMethodPointcut"
expression="
execution(* com.crossoverJie.service.*.select*(..))" />
<aop:pointcut id="selectMethodPointcut"
expression="
execution(* com.crossoverJie.dao..*Mapper.select*(..))" />
<aop:advisor advice-ref="methodCacheInterceptor"
pointcut-ref="controllerMethodPointcut" />
<!--所有数据库操作的方法加入切面 -->
<aop:aspect ref="dataSourceExchange">
<aop:pointcut id="dataSourcePointcut"
expression="execution(* com.crossoverJie.service.*.*(..))" />
<aop:before pointcut-ref="dataSourcePointcut" method="before" />
<aop:after pointcut-ref="dataSourcePointcut" method="after" />
</aop:aspect>
</aop:config>
编码方法拦截器MethodInterceptor
方法拦截器在目标方法被调用的时候被触发,作为增强业务逻辑存在,方法拦截器主要任务是将需要加入redis中数据添加进redis中;
package com.crossoverJie.intercept;
import com.crossoverJie.util.RedisUtil;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Created by chenjie on 2016/11/16.
*/
public class MethodCacheInterceptor implements MethodInterceptor {
private Logger logger = LoggerFactory.getLogger(MethodCacheInterceptor.class);
private RedisUtil redisUtil;
private List<String> targetNamesList; // 不加入缓存的service名称
private List<String> methodNamesList; // 不加入缓存的方法名称
private Long defaultCacheExpireTime; // 缓存默认的过期时间
private Long xxxRecordManagerTime; //
private Long xxxSetRecordManagerTime; //
/**
* 初始化读取不需要加入缓存的类名和方法名称
*/
public MethodCacheInterceptor() {
try {
// 分割字符串 这里没有加入任何方法
//
String[] targetNames = {};
String[] methodNames = {};
// 加载过期时间设置
defaultCacheExpireTime = 3600L;
xxxRecordManagerTime = 60L;
xxxSetRecordManagerTime = 60L;
// 创建list
targetNamesList = new ArrayList<String>(targetNames.length);
methodNamesList = new ArrayList<String>(methodNames.length);
Integer maxLen = targetNames.length > methodNames.length ? targetNames.length
: methodNames.length;
// 将不需要缓存的类名和方法名添加到list中
for (int i = 0; i < maxLen; i++) {
if (i < targetNames.length) {
targetNamesList.add(targetNames[i]);
}
if (i < methodNames.length) {
methodNamesList.add(methodNames[i]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object value = null;
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
// 不需要缓存的内容
//if (!isAddCache(StringUtil.subStrForLastDot(targetName), methodName)) {
if (!isAddCache(targetName, methodName)) {
// 执行方法返回结果
return invocation.proceed();
}
Object[] arguments = invocation.getArguments();
String key = getCacheKey(targetName, methodName, arguments);
logger.debug("redisKey: " + key);
try {
// 判断是否有缓存
if (redisUtil.exists(key)) {
return redisUtil.get(key);
}
// 写入缓存
value = invocation.proceed();
if (value != null) {
final String tkey = key;
final Object tvalue = value;
new Thread(new Runnable() {
@Override
public void run() {
if (tkey.startsWith("com.service.impl.xxxRecordManager")) {
redisUtil.set(tkey, tvalue, xxxRecordManagerTime);
} else if (tkey.startsWith("com.service.impl.xxxSetRecordManager")) {
redisUtil.set(tkey, tvalue, xxxSetRecordManagerTime);
} else {
redisUtil.set(tkey, tvalue, defaultCacheExpireTime);
}
}
}).start();
}
} catch (Exception e) {
e.printStackTrace();
if (value == null) {
return invocation.proceed();
}
}
return value;
}
/**
* 是否加入缓存
*
* @return
*/
private boolean isAddCache(String targetName, String methodName) {
boolean flag = true;
if (targetNamesList.contains(targetName)
|| methodNamesList.contains(methodName)) {
flag = false;
}
return flag;
}
/**
* 创建缓存key
*
* @param targetName
* @param methodName
* @param arguments
*/
private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sbu = new StringBuffer();
sbu.append(targetName).append("_").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
sbu.append("_").append(arguments[i]);
}
}
return sbu.toString();
}
public void setRedisUtil(RedisUtil redisUtil) {
this.redisUtil = redisUtil;
}
}