Trying to use EhCache using Spring and a custom GenericDao interface that extends the Hibernate's JpaRepository

北慕城南 提交于 2019-12-04 17:51:29

Here is the working solution I finally adopted. Just few precisions: my domains all implement the Persistable interface of Spring. Moreover, since I'm using reflection, I'm not sure the time saved by the caching process won't be a bit reduced...

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 (using the gentyref library)

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();
    }

}

Hope that could help ;)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!