关于spring与EHcache的集成

ehcache.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="ehcache.xsd">
	<diskStore path="java.io.tmpdir" />

	<defaultCache maxElementsInMemory="10000" eternal="false"
		timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false" />
	<!-- 配置自定义缓存 maxElementsInMemory:缓存中允许创建的最大对象数 eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。 
		timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前, 两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效, 
		如果该值是 0 就意味着元素可以停顿无穷长的时间。 timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值, 
		这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。 overflowToDisk:内存不足时,是否启用磁盘缓存。 memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。 -->

	<cache name="mobileCache" maxElementsInMemory="10000" eternal="false"
		overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="3600"
		memoryStoreEvictionPolicy="LFU" />

</ehcache> 


spring配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<context:annotation-config />
	<context:component-scan base-package="com.wallet.*" />
	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="wallet-web"></property>
		<!-- value 对应persistence.xml中的 persistence-unit name -->
	</bean>

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>


	<span style="color:#FF9966;"><strong><!-- 配置eh缓存管理器 -->
	<!--配置缓存管理器 -->
	<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>com.easyway.MethodCache</value>
		</property>
	</bean>

	<!-- 自定义缓存拦截器 -->
	<bean id="methodCacheInterceptor" class="com.wallet.core.intercepter.MethodCacheInterceptor">
		<property name="cache">
			<ref local="methodCache" />
		</property>
	</bean>

	<!-- 自定义拦截器 -->
	<bean id="methodCachePointCut"
		class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="advice">
			<ref local="methodCacheInterceptor" />
		</property>
		<!-- 下面的配置就使得在数据访问时,cache将拦截从数据库获取的数据,与cache数据比较,如有就不放入cache,没有就放入,更新到数据库去,也是先存入cache,再更新到数据库中去 -->
		<property name="patterns">
			<list>
				<value>.*findAll</value>
				<value>.*selectByCondis</value>
				<value>.*selectAll</value>
			</list>
		</property>
	</bean>

	<!-- flush cache拦截器 -->
	<bean id="methodCacheAfterAdvice" class="com.wallet.core.intercepter.MethodCacheAfterAdvice">
		<property name="cache">
			<ref local="methodCache" />
		</property>
	</bean>

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

	<!-- 声明一个服务 -->

	<bean id="cascadeEventServiceTarget"
		class="com.wallet.myWallet.service.impl.CascadeEventServiceImpl" />

	<bean id="fixedExpensesAccountServiceTarget"
		class="com.wallet.myWallet.service.impl.FixedExpensesAccountServiceImpl" />

	<!-- 相关的服务 -->
	<bean id="cascadeEventService" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target">
			<ref local="cascadeEventServiceTarget" />
		</property>
		<property name="interceptorNames">
			<list>
				<value>methodCachePointCut</value>
			</list>
		</property>
	</bean>

	<bean id="fixedExpensesAccountService" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target">
			<ref local="fixedExpensesAccountServiceTarget" />
		</property>
		<property name="interceptorNames">
			<list>
				<value>methodCachePointCut</value>
				<value>methodCachePointCutAdvice</value>
			</list>
		</property>
	</bean></strong></span>

	<tx:annotation-driven transaction-manager="txManager" />

</beans>

spring与ehcache集成的相关配置主要在上色不分,其中主要用到了两个拦截器一个是 methodCacheInterceptor主要用于对查询数据进行缓存; methodCacheAfterAdvice主要用于对save/update/delete的方法进行缓存。

methodCacheInterceptor


/**
 * 方法拦截器,主要针对查询方法进行缓存,
 * 用户每次查询会现在缓存中根据cacheKey查找相应的数据,
 * 有的话就只从缓存中取,没有的话就去数据库中查找,并将查询结果存到缓存中 
 */
public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean {

    private static final Logger log = Logger.getLogger(MethodCacheInterceptor.class);

    private Cache cache;

    public void setCache(Cache cache) {
        this.cache = cache;
    }

    public void afterPropertiesSet() throws Exception {
        log.info(cache + " A cache is required. Use setCache(Cache) to provide one.");
    }

    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 = null;
        synchronized (this) {
            element = cache.get(cacheKey);
            if (element == null) {
                log.info(cacheKey + "加入到缓存: " + cache.getName());
                System.out.println("加入到缓存");
                // 调用实际的方法
                result = invocation.proceed();
                element = new Element(cacheKey, (Serializable) result);
                cache.put(element);
            } else {
                log.info(cacheKey + "使用缓存: " + cache.getName());
                System.out.println("使用缓存");
            }
        }
        return element.getValue();
    }

    /**
     * <b>function:</b> 返回具体的方法全路径名称 参数
     * 
     * @author hoojo
     * @createDate 2012-7-2 下午06:12:39
     * @param targetName 全路径
     * @param methodName 方法名称
     * @param arguments 参数
     * @return 完整方法名称
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     */
    private String getCacheKey(String targetName, String methodName, Object[] arguments)
        throws Exception {
        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(getArgument(arguments[i]));
            }
        }
        return sb.toString();
    }

    /**
     * 因为查询的参数是一个实体类,所以通过反射的方式获取实体类中的属性以及属性值作为cacheKey的一部分
     * 
     * @param object
     * @return
     * @throws InstantiationException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws NoSuchFieldException
     * @throws SecurityException
     */
    private String getArgument(Object object) throws Exception {

        StringBuffer sb = new StringBuffer();
        if(object!=null && !"".equals(object)){
            System.out.println(object.getClass().getName());
            Method[] methods = object.getClass().getDeclaredMethods();
            for (Method m : methods) {
                if (m.getName().startsWith("get")) {
                    String fieldName = m.getName().substring(3, m.getName().length()).toLowerCase();
                    Object obj1 = m.invoke(object, null);
                    if (obj1 != null && !"".equals(obj1)) {
                        sb.append(fieldName).append(obj1);
                    }
                }
            }   
        }
        return sb.toString();
    }

}

methodCacheAfterAdvice


/**
 * 拦截器MethodCacheAfterAdvice,作用是在用户进行create/update/delete操作时来刷新/remove相关cache内容,
 * 这个拦截器实现了AfterReturningAdvice接口,将会在所拦截的方法执行后执行在public void afterReturning(Object arg0, Method
 * arg1, Object[] arg2, Object arg3)方法中所预定的操作
 */
public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean {


    private Cache cache;

    public void setCache(Cache cache) {
        this.cache = cache;
    }

    public MethodCacheAfterAdvice() {
        super();
    }

    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3)
        throws Throwable {
        String className = arg3.getClass().getName();
        List list = cache.getKeys();
        for (int i = 0; i < list.size(); i++) {
            String cacheKey = String.valueOf(list.get(i));
            if (cacheKey.startsWith(className)) {
                cache.remove(cacheKey);
            }
        }
    }

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it.");
    }

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值