spring aop的案例(二)缓存配置

时间:2021-11-22 23:46:07

缓存,为什么使用缓存?

重复的查询操作会让数据库做一些无用工作,缓存的引入让数据库减少了IO操作,减少了服务器的压力。ehcache是Java里最常用的一个缓存框架,它分为页面缓存和业务缓存,我们这里只说业务缓存。


  1. 首先新建一个ehcache.xml

    <ehcache>   
    <!-- <diskStore path="F://ehcache//dir"/>-->
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
    maxElementsInMemory="1000"
    eternal="false"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120"
    overflowToDisk="true"
    />

    <cache name="DEFAULT_CACHE"
    maxElementsInMemory="10000"
    eternal="false"
    timeToIdleSeconds="300000"
    timeToLiveSeconds="600000"
    overflowToDisk="true"
    />

    </ehcache>

    ehcache.xml中的diskStore 配置有本地缓存和IO缓存,java.io.tmpdir为IO缓存,需要消耗一定的服务器性能。

  2. cache操作,新增缓存和删缓存

    public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean 
    {

    private static final Log logger = LogFactory.getLog(MethodCacheInterceptor.class);

    private Cache cache;

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

    public MethodCacheInterceptor() {
    super();
    }

    /**
    * 拦截Service/DAO的方法,并查找该结果是否存在,如果存在就返回cache中的值,
    * 否则,返回数据库查询结果,并将查询结果放入cache
    */

    public Object invoke(MethodInvocation invocation) throws Throwable {
    String targetName = invocation.getThis().getClass().getName();
    String methodName = invocation.getMethod().getName();
    Object[] arguments = invocation.getArguments();
    Object result;

    logger.info("发现对象缓存来自 " + cache.getName());

    String cacheKey = getCacheKey(targetName, methodName, arguments);
    Element element = cache.get(cacheKey);

    if (element == null) {
    logger.info("保持方法,得到的结果和方法创建缓存........!");
    result = invocation.proceed();
    element = new Element(cacheKey, (Serializable) result);
    cache.put(element);
    }
    return element.getObjectValue();
    }

    /**
    * 获得cache key的方法,cache key是Cache中一个Element的唯一标识
    * cache key包括 包名+类名+方法名,如com.co.cache.service.UserServiceImpl.getAllUser
    */

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

    /**
    * implement InitializingBean,检查cache是否为空
    */

    public void afterPropertiesSet() throws Exception {
    Assert.notNull(cache, "需要一个高速缓存。请使用setCache(Cache)创建它。");
    }

    }

    public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean
    {

    private static final Log logger = LogFactory.getLog(MethodCacheAfterAdvice.class);

    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);
    logger.info("删除缓存 " + cacheKey);
    }
    }
    }

    public void afterPropertiesSet() throws Exception {
    Assert.notNull(cache, "需要一个缓存. 请使用setCache(Cache) 创建它.");
    }

    }
  3. spring-cache.xml配置


    <!-- 引用ehCache的配置 -->
    <bean id="defaultCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation">
    <value>classpath:ehcache.xml</value>
    </property>
    </bean>

    <!-- 定义ehCache的工厂,并设置所使用的Cache name -->
    <bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
    <property name="cacheManager">
    <ref local="defaultCacheManager"/>
    </property>
    <property name="cacheName">
    <value>DEFAULT_CACHE</value>
    </property>
    </bean>

    <!-- find/create cache拦截器 -->
    <bean id="methodCacheInterceptor" class="com.iitdev.cache.MethodCacheInterceptor">
    <property name="cache">
    <ref local="ehCache" />
    </property>
    </bean>
    <!-- flush cache拦截器 -->
    <bean id="methodCacheAfterAdvice" class="com.iitdev.cache.MethodCacheAfterAdvice">
    <property name="cache">
    <ref local="ehCache" />
    </property>
    </bean>

    <bean id="methodCachePointCut" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    <property name="advice">
    <ref local="methodCacheInterceptor"/>
    </property>
    <property name="mappedNames">
    <list>
    <value>find*</value>
    <value>get*</value>
    <value>search*</value>
    <value>select*</value>
    </list>
    </property>
    </bean>
    <bean id="methodCachePointCutAdvice" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    <property name="advice">
    <ref local="methodCacheAfterAdvice"/>
    </property>
    <property name="mappedNames">
    <list>
    <value>modify*</value>
    <value>delete*</value>
    <value>insert*</value>
    <value>save*</value>
    </list>
    </property>
    </bean>
  4. 使用自动装配bean设置缓存拦截器

    <!-- 自动装配事务到bean -->
    <bean id="autoTrx" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
    <list>
    <value>*BS</value>
    </list>
    </property>
    <property name="interceptorNames">
    <list>
    <value>trxInterceptor</value>
    <value>methodCachePointCutAdvice</value>
    <value>methodCachePointCut</value>
    </list>
    </property>
    </bean>