package org.seasar.caching.interceptor;
import java.io.Serializable;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
/**
* メソッドに対する呼び出しをキャッシュするInterceptor.
*
* Daoに対して適用する場合、以下のように用いる.
* <ul>
* <li>getやfindなどの取得系メソッドに CallCacheInterceptorをセットする
* <li>update,insert,delete,setなどの更新系メソッドに CallCachePurgeInterceptorをセットする
* <li>両Interceptorが同じキャッシュ領域を見に行くように コンストラクタの第二引数を等しいキー文字列にする
* <li>おなじく同一のCacheManagerを参照にいくように第一引数を等しいものにする
* </ul>
*
* 特に以下の点に注意する必要がある
* <ul>
* <li><b>インターセプト先のインスタンスはキャッシュ領域に対してsingletonでなくてはならない.</b>
* キャッシュに格納されているキーに、対象インスタンスを識別する機能がなく、メソッドのシグネチャと引数
* のセットのみをキーとしているため.
* <li>メソッドの引数は全てSerializableでない場合はキャッシュしない.
* <li>メソッドの戻り値型がSerializableでない場合はキャッシュしない.
* <li>例外がスローされた場合はキャッシュしない.
* </ul>
*
* @author TANIGUCHI Hikaru
*/
public class CallCacheInterceptor extends AbstractInterceptor {
private static final Log logger = LogFactory.getLog(CallCacheInterceptor.class);
private final Cache cache;
private final CacheManager cacheManager;
private final String cacheName;
/**
* constructor
*
* @param cacheManager ehCacheのキャッシュマネージャ
* @param cacheName キャッシュ名称(キャッシュマネージャに対するキー)
* @throws CacheException
*/
public CallCacheInterceptor(CacheManager cacheManager, String cacheName) throws CacheException {
this.cacheManager = cacheManager;
this.cacheName = cacheName;
if (!cacheManager.cacheExists(cacheName)) {
cacheManager.addCache(cacheName);
}
this.cache = cacheManager.getCache(cacheName);
}
public Object invoke(MethodInvocation invocation) throws Throwable {
// 全ての引数がSerializableでないとキャッシュの問い合わせ・追加に意味はない
if (!isAllArgumentsSerializable(invocation) || !isReturnTypeSerializable(invocation)) {
return invocation.proceed();
}
// 引数は全てSerializableなので CallDescriptionが生成可能。キャッシュ問い合わせ
CallDescription description = new CallDescription(invocation);
Element element = cache.get(description);
if (element != null) {
Serializable originalResult = element.getValue();
return SerializationUtils.clone(originalResult);
} else {
Object result = invocation.proceed(); // 例外発生時は上位へそのままスロー、キャッシュされない
Element insertElement = new Element(description, (Serializable) result);
cache.put(insertElement);
return SerializationUtils.clone((Serializable)result);
}
}
}package org.seasar.caching.interceptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
public class CallDescription implements Serializable {
private int targetObject;
private Class declaredClass;
private String methodName;
private Class[] methodArguments;
private Object[] argument;
public CallDescription( MethodInvocation invocation ) {
Method method = invocation.getMethod();
argument = invocation.getArguments();
targetObject = System.identityHashCode(invocation.getThis());
declaredClass = method.getDeclaringClass();
methodName = method.getName();
methodArguments = method.getParameterTypes();
}
/**
* @see java.lang.Object#equals(Object)
*/
public boolean equals(Object object) {
if (!(object instanceof CallDescription)) {
return false;
}
CallDescription rhs = (CallDescription) object;
return new EqualsBuilder().append(this.methodArguments, rhs.methodArguments).append(
this.declaredClass, rhs.declaredClass).append(this.argument, rhs.argument).append(
this.methodName, rhs.methodName).append(targetObject, rhs.targetObject).isEquals();
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return new HashCodeBuilder(661437325, -495862237).append(
this.methodArguments).append(this.declaredClass).append(this.argument)
.append(this.methodName).append(targetObject).toHashCode();
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return new ToStringBuilder(this).append(this.methodName).append(this.methodArguments)
.append(this.argument).append(this.targetObject).toString();
}
}
댓글 없음:
댓글 쓰기