在实际的项目开发中,肯定会根据具体业务,数据大小,复杂度采用不同的技术实现方式,Ehcache在实际项目开发中一般被用来缓存方法结果集,且可以与Spring无缝集成,完全交由Spring——Aop拦截器来完成,我们只需处理好业务数据获取环节。

1.ehcache.xml配置:

<ehcache>
     <diskStore path="java.io.tmpdir"/>
     <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        overflowToDisk="true"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"/>
    <cache name="gov.csc.ems.cache.METHOD_CACHE"
        maxElementsInMemory="300"
        eternal="false"
        timeToIdleSeconds="600"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
</ehcache>

 2. Spring集成Ehcache配置,cacheManage,methodCache

<bean id="cacheManager"
		class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
		<property name="configLocation">
			<value>classpath:ehcache.xml</value>
		</property>
	</bean>
<bean id="methodCache"
		class="org.springframework.cache.ehcache.EhCacheFactoryBean">
		<property name="cacheManager">
			<ref local="cacheManager" />
		</property>
		<property name="cacheName">
			<value>gov.csc.ems.cache.METHOD_CACHE</value>
		</property>
	</bean>

3. 完成上面的基础配置,Spring是靠拦截器来缓存我们的方法,因此建立我们自己的方法拦截器MethodCacheInterceptor。MethodCacheInterceptor实现了org.aopalliance.intercept.MethodInterceptor接口。

import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
public class MethodCacheInterceptor implements MethodInterceptor,
        InitializingBean {
    private Cache cache;
    /**
     * sets cache name to be used
     */
    public void setCache(Cache cache) {
        this.cache = cache;
    }
    /**
     * Checks if required attributes are provided.
     */
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(cache,
                "A cache is required. Use setCache(Cache) to provide one.");
    }
    /**
     * main method caches method result if method is configured for caching
     * method results must be serializable
     */
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String targetName = invocation.getThis().getClass().getName();
        String methodName = invocation.getMethod().getName();
        Object[] arguments = invocation.getArguments();
        Object result;
        String cacheKey = getCacheKey(targetName, methodName, arguments);
        Element element = cache.get(cacheKey);
        if (element == null) {
            result = invocation.proceed();
            element = new Element(cacheKey, (Serializable) result);
            cache.put(element);
        }
        return element.getValue();
    }
    /**
     * creates cache key: targetName.methodName.argument0.argument1...
     */
    private String getCacheKey(String targetName, String methodName,
            Object[] arguments) {
        StringBuffer sb = new StringBuffer();
        sb.append(targetName).append(".").append(methodName);
        if ((arguments != null) && (arguments.length != 0)) {
            for (int i = 0; i < arguments.length; i++) {
                sb.append(".").append(arguments[i]);
            }
        }
        return sb.toString();
    }
}

 invoke方法中:

String cacheKey = getCacheKey(targetName, methodName, arguments);
        Element element = cache.get(cacheKey);
        if (element == null) {
            result = invocation.proceed();
            element = new Element(cacheKey, (Serializable) result);
            cache.put(element);
        }
        return element.getValue();

 这段代码就是用来缓存我们的方法结果,拦截器先用key(key=className + methodName + arguments)查询缓存,缓存中存在则返回,否则调用invocation.proceed(),根据我们自己的实现查询数据,即第一次查询,以后每次就走缓存。

4.Spring中定义拦截器配置:

<bean id="methodCacheInterceptor"
		class="gov.csc.ems.util.cache.interceptor.MethodCacheInterceptor">
		<property name="cache">
			<ref local="methodCache" />
		</property>
	</bean>

5.Aop正则表达式的切入点配置:

<bean id="methodCachePointCut"
		class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="advice">
			<ref local="methodCacheInterceptor" />
		</property>
		<property name="patterns">
			<list>
				<value>.*</value>
			</list>
		</property>
	</bean>

patterns要拦截的规则,可以拦截指定的方法,如.getOrg*,.getUser*,这里我拦截所有的方法。

6.交给Spring代理

<bean id="codeCacheBean"
		class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target">
			<bean class="gov.csc.ems.util.cache.CodeCache" />
		</property>
		<property name="interceptorNames">
			<list>
				<value>methodCachePointCut</value>
			</list>
		</property>
	</bean>

 其中<bean class="gov.csc.ems.util.cache.CodeCache" />它就是我们缓存的类,缓存就是它里面的所有方法,当我们要用到它里面的方法时,如果此方法配置了缓存拦截,就会先走拦截器。

7.要缓存的方法类CodeCache

public class CodeCache {
	public CodeCache() {
		super();
	}
	public Map getOrgCache() {
                //从数据库查询org
                ......
        }
        public Map getUserCache() {
                //从数据库查询user
                ......
        }
}

8.测试

我这里写了个servlet,根据Spring获取到CodeCache,

CodeCache codeCache=(CodeCache) BeanUtil.getBean("codeCacheBean");
Map codeBasOrgs=codeCache.getOrgCache();
System.out.println(codeBasOrgs.get("0001"));

 分别在拦截器和CodeCache中打上断点,运行发现每次先走拦截器,而且第一次会走CodeCache查询,以后就直接取缓存了。

9.缓存的更新

如新添加了Org或user,CodeCache.getOrgCache.put(key,value)即可添加到缓存。

你可能感兴趣的内容
Spring 之 JMS 监听JMS消息 收藏,4393 浏览
Spring 之 JMS 基于JMS的RPC 收藏,3247 浏览
Spring的BeanFactory和FactoryBean 收藏,10398 浏览
0条评论

dexcoder

这家伙太懒了 <( ̄ ﹌  ̄)>
Owner