バックグラウンド
これが私の動作する(簡略化された)GenericDao
インターフェースであり、次のいずれかによって実装されますDomainDao
。
GenericDao.java
@NoRepositoryBean
public interface GenericDao<E extends Persistable<K>, K extends Serializable> extends JpaRepository<E, K> {
public List<E> findAll();
public E persist(E entity);
}
GenericDaoImpl.java
public class GenericDaoImpl<E extends Persistable<K>, K extends Serializable> extends SimpleJpaRepository<E, K> implements GenericDao<E, K> {
private final JpaEntityInformation<E, ?> entityInformation;
private final EntityManager em;
private final Class<E> type;
public GenericDaoImpl(JpaEntityInformation<E, ?> entityInformation, EntityManager em) {
super(entityInformation, em);
this.entityInformation = entityInformation;
this.em = em;
this.type = entityInformation.getJavaType();
}
@Override
public List<E> findAll() {
return super.findAll();
}
@Override
@Transactional
public E persist(E entity) {
if (entityInformation.isNew(entity) || !EntityUtils.isPrimaryKeyGenerated(type) && !em.contains(entity)) {
em.persist(entity);
}
return entity;
}
}
たとえば、ドメインFoo
とを管理するにはBar
、次のように2つのインターフェイスを作成する必要があります。
FooDao.java
public interface FooDao extends GenericDao<Foo, Integer> {
}
BarDao.java
public interface BarDao extends GenericDao<Bar, Integer> {
}
の@Autowired
注釈は、適切なエンティティと主キータイプを使用してSpring
自動的にインスタンス化されます。GenericDaoImpl
問題
現在、EhCacheとEhCache Spring Annotationsモデルを使用して、DAOにキャッシュプロセスを追加しようとしています。
GenericDao.java
@NoRepositoryBean
public interface GenericDao<E extends Persistable<K>, K extends Serializable> extends JpaRepository<E, K> {
@Cacheable(cacheName = "dao")
public List<E> findAll();
@TriggersRemove(cacheName = "dao")
public E persist(E entity);
}
applicationContext.xml
<ehcache:annotation-driven cache-manager="ehCacheManager" />
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
ehcache.xml
<cache name="dao"
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
memoryStoreEvictionPolicy="LFU" />
の使用に関する問題はGenericDao
、キャッシュが互いにDomainDao
独立してそれぞれを管理する必要があることです。たとえば、現在の構成では、を呼び出してから、を呼び出すとfooDao.findAll()
、barDao.persist(new Bar())
によって生成されたキャッシュfooDao.findAll()
がリセットされます。これは、同じキャッシュが使用されているはずですが、使用されてい<cache name="dao" />
ないためです。
トレイル
私は自分自身を実装しようとしましたCacheKeyGenerator
、それは呼び出しのタイプを考慮に入れますDomainDao
:
applicationContext.xml
<ehcache:annotation-driven cache-manager="ehCacheManager" default-cache-key-generator="daoCacheKeyGenerator" />
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
<bean id="daoCacheKeyGenerator" class="myapp.dao.support.DaoCacheKeyGenerator" />
DaoCacheKeyGenerator.java
public class DaoCacheKeyGenerator implements CacheKeyGenerator<DaoCacheKey> {
@Override
public DaoCacheKey generateKey(MethodInvocation methodInvocation) {
Class<?> clazz = methodInvocation.getThis().getClass().getInterfaces()[0];
Method method = methodInvocation.getMethod();
String methodName = method.getName();
Class<?>[] parameterClasses = method.getParameterTypes();
return new DaoCacheKey(clazz, methodName, parameterClasses);
}
@Override
public DaoCacheKey generateKey(Object... data) {
return null;
}
}
DaoCacheKey.java
public class DaoCacheKey implements Serializable {
private static final long serialVersionUID = 338466521373614710L;
private Class<?> clazz;
private String methodName;
private Class<?>[] parameterClasses;
public DaoCacheKey(Class<?> clazz, String methodName, Class<?>[] parameterClasses) {
this.clazz = clazz;
this.methodName = methodName;
this.parameterClasses = parameterClasses;
}
@Override
public boolean equals(Object obj) { // <-- breakpoint
if (obj instanceof DaoCacheKey) {
DaoCacheKey other = (DaoCacheKey) obj;
if (clazz.equals(other.clazz)) {
// if @TriggersRemove, reset any cache generated by a find* method of the same DomainDao
boolean removeCache = !methodName.startsWith("find") && other.methodName.startsWith("find");
// if @Cacheable, check if the result has been previously cached
boolean getOrCreateCache = methodName.equals(other.methodName) && Arrays.deepEquals(parameterClasses, other.parameterClasses);
return removeCache || getOrCreateCache;
}
}
return false;
}
@Override
public int hashCode() { // <-- breakpoint
return super.hashCode();
}
}
上記の問題DaoCacheKey
は、equals
メソッドが呼び出されない(プログラムが少なくとも壊れることはない)が、呼び出されるhashCode
ため、アルゴリズムを適用できないことです。
質問
誰かがすでにそのようなキャッシュを管理しましたか?はいの場合、どのように?私の試みは適切ですか?はいの場合、equals
メソッドを呼び出す代わりに、メソッドを呼び出す方法を教えてhashCode
ください。既存のCacheKeyGenerator
?はいの場合、どれですか?