luckystar +
send mail to luckystar sina weibo
关于订阅 luckystar's blog » Project »
分类:
标签:

结合Spring AOP和EHCache实现查找时将结果放入缓存,在更新或删除操作时清除缓存的功能。
项目结构如下: img 依赖的Jars如下: img

ehcache.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
         monitoring="autodetect">
    <!--
    <diskStore path="java.io.tmpdir" /> -->
    <diskStore path="d:/cachetmpdir"/>
    <defaultCache maxElementsInMemory="10000" eternal="false"
                  timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
                  maxElementsOnDisk="10000000" diskPersistent="false"
                  diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />

    <cache name="dbCache" maxElementsInMemory="10000"
           maxElementsOnDisk="1000" eternal="false" overflowToDisk="true"
           diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LFU" />
</ehcache>

applicationContext-cache.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:ehcache="http://www.springframework.org/schema/cache"
       xmlns:cache="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
    <bean id="defaultCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="ehcache.xml"></property>
    </bean>

    <bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="defaultCacheManager"></property>
        <property name="cacheName" value="dbCache"></property>
    </bean>

    <!--find/create Cache拦截器-->
    <bean id="methodCacheInterceptor" class="com.hyxt.cache.ehcache.demo.MethodCacheInterceptor">
        <property name="cache" ref="ehCache"></property>
    </bean>

    <!--update/delete Cache拦截器-->
    <bean id="methodCacheAfterAdvice" class="com.hyxt.cache.ehcache.demo.MethodCacheAfterReturningAdvice">
        <property name="cache" ref="ehCache"></property>
    </bean>

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

    <bean id="methodCachePointcutAfterReturning" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="methodCacheAfterAdvice"></property>
        <property name="patterns">
            <list>
                <value>.*create.*</value>
                <value>.*update.*</value>
                <value>.*delete.*</value>
            </list>
        </property>

    </bean>
</beans>

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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <import resource="applicationContext-cache.xml"></import>
    <context:component-scan base-package="com.hyxt"></context:component-scan>

    <bean id="testServiceTarget" class="com.hyxt.cache.ehcache.demo.TestService"></bean>
    <bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="testServiceTarget"></property>
        <property name="interceptorNames">
            <list>
                <value>methodCacheAfterReturningAdvice</value>
                <value>methodCachePointcutAfterReturning</value>
            </list>
        </property>
    </bean>
</beans>

MethodCacheInterceptor.java:

package com.hyxt.cache.ehcache.demo;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

/**
 * 该拦截器的作用是在执行方法时查询/新建Cache。
 * Created by qince on 2015/3/23.
 */
public class MethodCacheInterceptor implements MethodInterceptor,InitializingBean {
    private final static Log log = LogFactory.getLog(MethodCacheInterceptor.class);
    private Cache cache;

    public Cache getCache() {
        return cache;
    }

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

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(cache,"Need a cache,please use setCache(Cache) to create it!");
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // 类名+方法名+方法参数作为Cache Key
        String className = methodInvocation.getThis().getClass().getName();
        String methodName = methodInvocation.getMethod().getName();
        Object[] arguments = methodInvocation.getArguments();

        String cacheKey = getCacheKey(className, methodName, arguments);
        log.debug("cacheKey:" + cacheKey);

        Element element = null;
        synchronized (this) {
            element = cache.get(cacheKey);
            if (null == element) {
                log.info("未从缓存查找到数据,从数据库查询。。");

                Object result = methodInvocation.proceed();
                element = new Element(cacheKey,result);
                cache.put(element);
            }
            else {
                log.info("从缓存中查找到数据 :" + cacheKey);
            }
        }

        return element.getValue();
    }

    public String getCacheKey(String className,String methodName,Object[] arguments) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(className).append(".").append(methodName);
        if (null != arguments) {
            for (Object argument : arguments) {
                stringBuffer.append(".").append(argument);
            }
        }
        return stringBuffer.toString();
    }
}

MethodCacheAfterReturningAdvice.java:

package com.hyxt.cache.ehcache.demo;

import net.sf.ehcache.Cache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.lang.reflect.Method;
import java.util.List;

/**
 * 该类的作用是执行update/delete操作时,清除缓存
 * Created by qince on 2015/3/23.
 */
public class MethodCacheAfterReturningAdvice implements AfterReturningAdvice,InitializingBean {
    private final static Log log = LogFactory.getLog(MethodCacheInterceptor.class);
    private Cache cache;

    public Cache getCache() {
        return cache;
    }

    public void setCache(Cache cache) {
        this.cache = cache;
    }
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        String className =o1.getClass().getName();
        System.out.println("className;" + className);
//        System.out.println("o:" + o.getClass().getName());
        System.out.println("method:" + method.getClass().getName());
        List cacheKeys =cache.getKeys();

        if (null != cacheKeys) {
            for (int i=0;i<cacheKeys.size();i++) {
                String cacheKey = cacheKeys.get(i).toString();
                if (cacheKey.startsWith(className)) {
                    cache.remove(cacheKey);
                    log.info("清除缓存 : " + cacheKey);
                }
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(cache, "Need a cache,please use setCache(Cache) to create it!");
    }
}

TestDao.java:

package com.hyxt.cache.ehcache.demo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;

/**
 * Created by qince on 2015/3/23.
 */
@Repository
public class TestDao {
    Log log = LogFactory.getLog(TestDao.class);
    public Object getObject(String name) {
        log.info("从数据库查找,name=" + name);
        return "hello " + name;
    }

    public void updateObject(String name) {
        log.info("更新数据库");
    }
}

TestService.java:

package com.hyxt.cache.ehcache.demo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * Created by qince on 2015/3/23.
 */
public class TestService {
    private final static Log LOG = LogFactory.getLog(TestService.class);
    @Autowired
    private TestDao testDao;

    public Object getObject(String name) {
        return testDao.getObject(name);
    }

    public void updateObject(String name) {
        testDao.updateObject(name);
    }
}

EHCacheTest.java:

package com.hyxt.cache.ehcache.demo;

import org.omg.CORBA.portable.ApplicationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by qince on 2015/3/23.
 */
public class EHCacheTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        TestService testService = (TestService) applicationContext.getBean("testService");
        System.out.println("第一次查找并创建Cache。");
        testService.getObject("test");
        System.out.println("=============================");
        System.out.println("第二次从Cache中查找。");
        testService.getObject("test");
        System.out.println("=============================");
        System.out.println("第三次清除Cache。");
        testService.updateObject("test");
        System.out.println("=============================");
        System.out.println("第四次从数据库查找并放入Cache。");
        testService.getObject("test");
    }
}

执行结果: img

作者:qincidong
出处:http://qincidong.github.io/blog/2015/03/24/spring-ehcache.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
分类: 标签:
友荐云推荐