2013-01-10 36 views
2

背景尝试使用了Ehcache使用Spring和扩展了Hibernate的JpaRepository

这是我工作的自定义GenericDao接口(简体)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; 
    } 

} 

例如,管理域FooBar,你只需要创建两个接口为:

FooDao.java

public interface FooDao extends GenericDao<Foo, Integer> { 

} 

BarDao.java

public interface BarDao extends GenericDao<Bar, Integer> { 

} 

Spring@Autowired注释将自动实例化具有良好实体和主键类型的GenericDaoImpl


问题

我现在想加上我的DAO高速缓存过程,使用的Ehcache和EhCache Spring Annotations模型。

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方法得到从来没有所谓(中程序永远不会中断t),但是这样做,所以该算法无法得到应用。


问题

有没有人已经成功这样的缓存?如果是的话如何?我的尝试是否相关?如果是,如何使equals方法调用,而不是hashCode之一?通过扩展现有的CacheKeyGenerator?如果是,哪一个?

回答

1

这是我最终采用的工作解决方案。只有很少的精度:我的域都实现了Spring的Persistable界面。此外,由于我使用反射,我不知道在缓存过程节省的时间会不会有点降低...

的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.cache.DaoCacheKeyGenerator" /> 

DaoCacheKeyGenerator。的java(使用gentyref库)

public class DaoCacheKeyGenerator implements CacheKeyGenerator<DaoCacheKey> { 

    @SuppressWarnings("unchecked") 
    @Override 
    public DaoCacheKey generateKey(MethodInvocation methodInvocation) { 
     Method method = methodInvocation.getMethod(); 
     Class<? extends GenericDao<?, ?>> daoType = (Class<? extends GenericDao<?, ?>>) methodInvocation.getThis().getClass().getInterfaces()[0]; 
     Class<? extends Persistable<?>> domainType = getDomainType(daoType); 
     String methodName = method.getName(); 
     Class<?>[] parameterTypes = method.getParameterTypes(); 
     Object[] parameters = methodInvocation.getArguments(); 
     return new DaoCacheKey(domainType, methodName, parameterTypes, parameters); 
    } 

    @SuppressWarnings("unchecked") 
    private Class<? extends Persistable<?>> getDomainType(Class<?> daoType) { 
     Type baseDaoType = GenericTypeReflector.getExactSuperType(daoType, GenericDao.class); 
     ParameterizedType parameterizedBaseDaoType = (ParameterizedType) baseDaoType; 
     return (Class<? extends Persistable<?>>) parameterizedBaseDaoType.getActualTypeArguments()[0]; 
    } 

    @Override 
    public DaoCacheKey generateKey(Object... data) { 
     return null; 
    } 

} 

DaoCacheKey.java

public class DaoCacheKey implements Serializable { 

    private static final long serialVersionUID = 338466521373614710L; 

    private Class<? extends Persistable<?>> domainType; 
    private String methodName; 
    private Class<?>[] parameterTypes; 
    private Object[] parameters; 

    public DaoCacheKey(Class<? extends Persistable<?>> domainType, String methodName, Class<?>[] parameterTypes, Object[] parameters) { 
     this.domainType = domainType; 
     this.methodName = methodName; 
     this.parameterTypes = parameterTypes; 
     this.parameters = parameters; 
    } 

    public Class<? extends Persistable<?>> getDomainType() { 
     return domainType; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return this == obj || obj instanceof DaoCacheKey && hashCode() == obj.hashCode(); 
    } 

    @Override 
    public int hashCode() { 
     return Arrays.hashCode(new Object[] { domainType, methodName, Arrays.asList(parameterTypes), Arrays.asList(parameters) }); 
    } 

} 

ehcache.xml中

<cache name="dao" 
    eternal="false" 
    maxElementsInMemory="10000" 
    overflowToDisk="false" 
    timeToIdleSeconds="86400" 
    timeToLiveSeconds="86400" 
    memoryStoreEvictionPolicy="LFU"> 
    <cacheEventListenerFactory class="myapp.dao.support.cache.DaoCacheEventListenerFactory" /> 
</cache> 

DaoCacheEventListenerFactory.java

public class DaoCacheEventListenerFactory extends CacheEventListenerFactory { 

    @Override 
    public CacheEventListener createCacheEventListener(Properties properties) { 
     return new DaoCacheEventListener(); 
    } 

} 

DaoCacheEventListener.java

public class DaoCacheEventListener implements CacheEventListener { 

    @SuppressWarnings("unchecked") 
    @Override 
    public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException { 
     DaoCacheKey daoCachekey = (DaoCacheKey) element.getKey(); 
     List<Class<? extends Persistable<?>>> impacts = getOneToManyImpacts(daoCachekey.getDomainType()); 
     for (DaoCacheKey daoCachedkey : (List<DaoCacheKey>) cache.getKeys()) { 
      if (impacts.contains(daoCachedkey.getDomainType())) { 
       cache.remove(daoCachedkey); 
      } 
     } 
    } 

    @SuppressWarnings("unchecked") 
    private List<Class<? extends Persistable<?>>> getOneToManyImpacts(Class<? extends Persistable<?>> domainType) { 
     List<Class<? extends Persistable<?>>> impacts = new ArrayList<Class<? extends Persistable<?>>>(); 
     impacts.add(domainType); 
     for (Method method : domainType.getDeclaredMethods()) { 
      if (method.isAnnotationPresent(OneToMany.class)) { 
       ParameterizedType parameterizedType = (ParameterizedType) method.getGenericReturnType(); 
       Class<? extends Persistable<?>> impactedDomainType = (Class<? extends Persistable<?>>) parameterizedType.getActualTypeArguments()[0]; 
       if (!impacts.contains(impactedDomainType)) { 
        impacts.addAll(getOneToManyImpacts(impactedDomainType)); 
       } 
      } 
     } 
     return impacts; 
    } 

    @Override 
    public void notifyElementPut(Ehcache cache, Element element) throws CacheException { 
    } 

    @Override 
    public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException { 
    } 

    @Override 
    public void notifyElementExpired(Ehcache cache, Element element) { 
    } 

    @Override 
    public void notifyElementEvicted(Ehcache cache, Element element) { 
    } 

    @Override 
    public void notifyRemoveAll(Ehcache cache) { 
    } 

    @Override 
    public void dispose() { 
    } 

    @Override 
    public Object clone() throws CloneNotSupportedException { 
     return super.clone(); 
    } 

} 

希望能够帮助;)

+0

你碰到你的应用程序,你必须实现的方式在GenericDao级别无效在高速缓存中各个条目的情况吗?我很想知道实施是什么。 – Glide

相关问题