spring整合redis
web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:conf/app-context.xml </param-value> </context-param>
app-context.xml
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <import resource="app-cache.xml" /> </beans>
app-cache.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- Cache的Redis Template --> <bean id="cacheRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="cacheRedisConnectionFactory" /> <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> <!-- 配置缓存 --> <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManagerEx"> <constructor-arg ref="cacheRedisTemplate" /> <!-- 默认Key有效期24小时(3600*24) --> <property name="defaultExpiration" value="3600" /> <property name="usePrefix" value="true" /> <property name="expires"> <map> <!-- Database Keys --> <entry key="CACHE:CBM_MAG:COMPANY" value="600" /> <entry key="CACHE:CBM_MAG:PRODUCT" value="600" /> <entry key="CACHE:CBM_COMMON:DATA_DICT_CONTENT" value="600" /> <entry key="CACHE:BUSINESS:CAR_TYPE" value="600" /> <entry key="CACHE:BUSINESS:CAR_TYPE" value="600" /> <entry key="CACHE:BUSINESS:DEVICE_SUMMARY" value="900" /> <entry key="CACHE:CLOUD:ALARM_REALTIME" value="180" /> <entry key="CACHE:CLOUD:ALARM_SUMMARY_REALTIME" value="3600" /> <entry key="CACHE:CLOUD:ALARM_SUMMARY" value="3600" /> <entry key="CACHE:CLOUD:ALARM_DAILY" value="3600" /> <entry key="CACHE:CLOUD:ALARM_MONTHLY" value="3600" /> <entry key="CACHE:CLOUD:DEVICE_DAILY" value="3600" /> <entry key="CACHE:CLOUD:DEVICE_MONTHLY" value="3600" /> <entry key="CACHE:CLOUD:DEVICE_STATS" value="3600" /> <entry key="CACHE:CLOUD:CAPACITY_DAILY" value="3600" /> <entry key="CACHE:CLOUD:CAPACITY_MONTHLY" value="3600" /> <entry key="CACHE:CLOUD:WORK_DURATION_DAILY" value="3600" /> <entry key="CACHE:CLOUD:WORK_DURATION_MONTHLY" value="3600" />
。。。。。
</map>
</property>
</bean> <!-- Key生成策略配置 --> <bean id="defaultKeyGenerator" class="com.foton.m2m.basic.core.cache.DefaultKeyGenerator" />
<!-- 开启spring缓存注解 --> <cache:annotation-driven cache-manager="cacheManager" key-generator="defaultKeyGenerator" /> </beans>
/** * 实现spring cache的默认缓存实现策略 * * @author gaolixiang2 2017年6月20日 */ public class DefaultKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { return new DefaultKey(target, method, params).getString(); } }
public class DefaultKey implements Serializable { private static final long serialVersionUID = 1930236297081366076L; /** 调用目标对象全类名 */ private String targetClassName; /** 调用目标方法名称 */ private String methodName; /** 调用目标参数 */ private Object[] params; private final int hashCode; public DefaultKey(Object target, Method method, Object[] elements) { this.targetClassName = target.getClass().getName(); this.methodName = generatorMethodName(method); if (ArrayUtils.isNotEmpty(elements)) { this.params = new Object[elements.length]; for (int i = 0; i < elements.length; i++) { Object ele = elements[i]; if (ele instanceof Persistable) { try { Map<String, ? extends Object> properties = BeanUtils.describe(ele); this.params[i] = properties; } catch (Exception e) { this.params[i] = ele; } } else if (ele instanceof Class) { this.params[i] = ((Class) ele).getName(); } else { this.params[i] = ele; } } } this.hashCode = generatorHashCode(); } public String getString() { return targetClassName + ":" + methodName + ":" + hashCode; } private String generatorMethodName(Method method) { StringBuilder builder = new StringBuilder(); Class<?>[] types = method.getParameterTypes(); if (ArrayUtils.isNotEmpty(types)) { builder.append("("); for (Class<?> type : types) { String name = type.getName(); builder.append(name + ","); } builder.append(")"); } return method.getName() + builder.toString().hashCode(); } // 生成hashCode private int generatorHashCode() { final int prime = 31; int result = 1; result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); result = prime * result + hashCode(params); result = prime * result + ((targetClassName == null) ? 0 : targetClassName.hashCode()); return result; } @SuppressWarnings({ "rawtypes", "unchecked" }) public static int hashCode(Object a[]) { if (a == null) return 0; int result = 1; for (int i = 0; i < a.length; i++) { Object element = a[i]; if (element == null) { result = 31 * result + (i + "null").hashCode(); } else if (element instanceof Collection) { Collection<?> collection = (Collection) element; int j = 0; for (Object subElement : collection) { result = 31 * result + (subElement == null ? (j + "snull").hashCode() : subElement.hashCode()); j++; } } else if (element.getClass().isArray()) { Object[] subElement = (Object[]) element; for (int j = 0; j < subElement.length; j++) { result = 31 * result + (subElement == null ? (j + "snull").hashCode() : subElement.hashCode()); } } else if (element instanceof Map) { Map map = (Map) element; Set<Map.Entry> entrySet = map.entrySet(); int j = 0; for (Map.Entry<?, ?> subElement : entrySet) { result = 31 * result + (subElement == null ? (j + "snull").hashCode() : subElement.hashCode()); j++; } } else { result = 31 * result + element.hashCode(); } } return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DefaultKey other = (DefaultKey) obj; if (hashCode != other.hashCode) return false; if (methodName == null) { if (other.methodName != null) return false; } else if (!methodName.equals(other.methodName)) return false; if (!Arrays.equals(params, other.params)) return false; if (targetClassName == null) { if (other.targetClassName != null) return false; } else if (!targetClassName.equals(other.targetClassName)) return false; return true; } @Override public final int hashCode() { return hashCode; }
调用:
@Cacheable(value = Constants.BUSINESS_CACHE_NAME_PREFIX + "SERVICER", unless = "#result.size() eq 0") public List<Map<String, Object>> findMapGroupByProvince(Long companyId, Long productId, Long brandId) { ... }
说明:Spring cache key 生成策略 类名+方法名+参数信息
补充:关于生成策略多种多样,foton使用的策略是类路径hashcode + 方法hashcode + 参数hashcode 这样存储命中率比较低节约空间
DefaultKey.java