/* * Copyright 2009-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License i distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.paoding.rose.jade.statement.cached; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.paoding.rose.jade.annotation.Cache; import net.paoding.rose.jade.annotation.CacheDelete; import net.paoding.rose.jade.annotation.SQLType; import net.paoding.rose.jade.statement.Statement; import net.paoding.rose.jade.statement.StatementMetaData; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanWrapperImpl; /** * {@link CachedStatement} 封装了支持Cache的逻辑 * * @author 王志亮 [qieqie.wang@gmail.com] * */ public class CachedStatement implements Statement { /** * 实际底层Statemenet,比如就是数据库操作的实际执行语句 */ private final Statement realStatement; /** * 注解在DAO方法上的 {@link Cache},如果没有则为null * <p> * 仅在该语句为查询语句时侯此有效,即如果某个更新语句的DAO方法上也注解了 {@link Cache} 在这里也仍保留null */ private final Cache cacheAnnotation; /** * 注解在该语句上的 {@link CacheDelete},如果没有则为null * <p> * * 可使用在各种语句上,甚至事查询语句上(很悲剧的:我也不知道为何有这种用法,执行一次查询还会附带删除神马Cache的啊?真的有吗?) */ private final CacheDelete cacheDeleteAnnotation; /** * cache服务接口 */ private final CacheProvider cacheProvider; /** * * @param cacheProvider * @param realStatement */ public CachedStatement(CacheProvider cacheProvider, Statement realStatement) { this.realStatement = realStatement; this.cacheProvider = cacheProvider; StatementMetaData metaData = realStatement.getMetaData(); SQLType sqlType = metaData.getSQLType(); cacheDeleteAnnotation = metaData.getMethod().getAnnotation(CacheDelete.class); Cache cacheAnnotation = metaData.getMethod().getAnnotation(Cache.class); if (sqlType == SQLType.READ) { this.cacheAnnotation = cacheAnnotation; } else { this.cacheAnnotation = null; if (cacheAnnotation != null) { Log logger = LogFactory.getLog(CachedStatement.class); logger.warn("@" + Cache.class.getName() + " is invalid for a " // + sqlType + " SQL:" + metaData.getSQL()); } } } @Override public StatementMetaData getMetaData() { return realStatement.getMetaData(); } @Override public Object execute(Map<String, Object> parameters) { Object value = null; if (cacheAnnotation == null) { value = realStatement.execute(parameters); } else { CacheInterface cache = cacheProvider.getCacheByPool(// getMetaData(), cacheAnnotation.pool()); String cacheKey = buildKey(cacheAnnotation.key(), parameters); value = cache.get(cacheKey); if (value == null) { value = realStatement.execute(parameters); cache.set(cacheKey, value, cacheAnnotation.expiry()); } } if (cacheDeleteAnnotation != null) { CacheInterface cache = cacheProvider.getCacheByPool(// getMetaData(), cacheDeleteAnnotation.pool()); for (String key : cacheDeleteAnnotation.key()) { String cacheKey = buildKey(key, parameters); cache.delete(cacheKey); } } return value; } // 参数的模板 private static final Pattern PATTERN = Pattern.compile("\\:([a-zA-Z0-9_\\.]*)"); /** * 查找模板 KEY 中所有的 :name, :name.property 参数替换成实际值。 * * @param key - 作为模板的 KEY * @param parameters - 传入的参数 * * @return 最终的缓存 KEY * @author 廖涵 in355hz@gmail.com */ private static String buildKey(String key, Map<String, Object> parameters) { // 匹配符合 :name 格式的参数 Matcher matcher = PATTERN.matcher(key); if (matcher.find()) { StringBuilder builder = new StringBuilder(); int index = 0; do { // 提取参数名称 final String name = matcher.group(1).trim(); Object value = null; // 解析 a.b.c 类型的名称 int find = name.indexOf('.'); if (find >= 0) { // 用 BeanWrapper 获取属性值 Object bean = parameters.get(name.substring(0, find)); if (bean != null) { value = new BeanWrapperImpl(bean) .getPropertyValue(name.substring(find + 1)); } } else { // 获取参数值 value = parameters.get(name); } // 拼装参数值 builder.append(key.substring(index, matcher.start())); builder.append(value); index = matcher.end(); } while (matcher.find()); // 拼装最后一段 builder.append(key.substring(index)); return builder.toString(); } return key; } }