当前位置: 代码迷 >> 编程 >> Spring缓存机制的懂得
  详细解决方案

Spring缓存机制的懂得

热度:2109   发布时间:2013-02-26 00:00:00.0
Spring缓存机制的理解

在Spring缓存机制中,包括了两个方面的缓存操作:1.缓存某个方法返回的结果;2.在某个方法执行前或后清空缓存。

下面写两个类来模拟Spring的缓存机制:

复制代码
package com.sin90lzc.java.test;/** * 一个简单的Dao接口,我们要对这个接口的方法提供缓存的功能 * @author Tim * */public interface Dao {    Object select();    void save(Object obj);}
复制代码
复制代码
package com.sin90lzc.java.test;import java.util.HashMap;import java.util.Map;/** * 实现缓存功能,在Spring中,该类可以看作是Advice * @author Tim * */public class Cache {    private static final Map<String, Object> cache = new HashMap<String, Object>();        /**     * 把对象添加到缓存中去     * @param key     * @param value     */    public void checkIn(String key, Object value) {        if (!cache.containsKey(key)) {            cache.put(key, value);        }    }    /**     * 从缓存中找对象     * @param key     * @return     */    public Object checkOut(String key) {        if (cache.containsKey(key)) {            return cache.get(key);        }        return null;    }        /**     * 在方法执行前清除缓存     */    public void clearCacheBeforeMethod(){        cache.clear();    }        /**     * 在方法执行后清除缓存     */    public void clearCacheAfterMethod(){        cache.clear();    }}
复制代码
复制代码
package com.sin90lzc.java.test;/** * Dao的代理对象,它不仅仅完成主要的查询,存储操作,还实现了缓存 * @author Tim * */public class DaoProxy implements Dao {    private Cache cache;//该对象实现了缓存的功能    private Dao daoImpl;//完成主要查询,存储操作的Dao实现类,注意,这是一个Dao的实现类    public Object select() {        //在执行方法前,尝试从缓存中取出结果并返回,如果没找到,则执行实际的操作。        Object obj = cache.checkOut("DaoProxy.select");        boolean hasCache = false;        if (obj != null) {            hasCache = true;            return obj;        }                //实际的查询操作        obj = daoImpl.select();                //如果在缓存中找不到该方法的结果,缓存该结果        if (!hasCache) {            cache.checkIn("DaoProxy.select", obj);        }        return obj;    }    @Override    public void save(Object obj) {        //在执行方法前清除缓存        cache.clearCacheBeforeMethod();        //实际的操作        daoImpl.save(obj);        //在执行方法后清除缓存        cache.clearCacheAfterMethod();    }    public void setCache(Cache cache) {        this.cache = cache;    }    public void setDao(Dao dao) {        this.daoImpl = dao;    }}
复制代码

从代码中可以看到,真正完成缓存功能的类是Cache,真正完成Dao(数据的增删查改)功能的类是Dao的实现类,这就是实现了实际业务(Dao)与功能(缓存)的分离。实际的Dao操作与缓存功能是如何结合起来的呢?这就是通过代理对象。我们可以注意到ProxyDao的真正身份也是一个Dao,是它把Dao操作与缓存结合起来的。这三个类恰恰说明了AOP的本质。

2.EHCache

Spring仅仅是提供了对缓存的支持,但它并没有任何的缓存功能的实现,spring使用的是第三方的缓存框架来实现缓存的功能。其中,spring对EHCache提供了很好的支持。下面我们以EHCache为例来介绍spring的缓存配置。

在介绍Spring的缓存配置之前,我们先看一下EHCache是如何配置。

复制代码
<?xml version="1.0" encoding="UTF-8" ?><ehcache>    <!-- 定义默认的缓存区,如果在未指定缓存区时,默认使用该缓存区 -->    <defaultCache maxElementsInMemory="500" eternal="true"        overflowToDisk="false" memoryStoreEvictionPolicy="LFU">    </defaultCache>    <!-- 定义名字为"dao.select"的缓存区 -->    <cache name="dao.select" maxElementsInMemory="500" eternal="true"        overflowToDisk="false" memoryStoreEvictionPolicy="LFU" /></ehcache>
复制代码

3.Spring缓存机制中的Advice

由于Spring的缓存机制是基于Spring的AOP,那么在Spring Cache中应该存在着一个Advice。没错,在Spring Cache中的Advice是存在的,它就是org.springframework.cache.Cache。我们看一下它的接口定义:

复制代码
/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.cache;/** * Interface that defines the common cache operations. * * <b>Note:</b> Due to the generic use of caching, it is recommended that * implementations allow storage of <tt>null</tt> values (for example to * cache methods that return {@code null}). * * @author Costin Leau * @since 3.1 */public interface Cache {    /**     * Return the cache name.     */    String getName();    /**     * Return the the underlying native cache provider.     */    Object getNativeCache();    /**     * Return the value to which this cache maps the specified key. Returns     * <code>null</code> if the cache contains no mapping for this key.     * @param key key whose associated value is to be returned.     * @return the value to which this cache maps the specified key,     * or <code>null</code> if the cache contains no mapping for this key     */    ValueWrapper get(Object key);    /**     * Associate the specified value with the specified key in this cache.     * <p>If the cache previously contained a mapping for this key, the old     * value is replaced by the specified value.     * @param key the key with which the specified value is to be associated     * @param value the value to be associated with the specified key     */    void put(Object key, Object value);    /**     * Evict the mapping for this key from this cache if it is present.     * @param key the key whose mapping is to be removed from the cache     */    void evict(Object key);    /**     * Remove all mappings from the cache.     */    void clear();    /**     * A (wrapper) object representing a cache value.     */    interface ValueWrapper {        /**         * Return the actual value in the cache.         */        Object get();    }}
复制代码

evict,put方法就是Advice的功能方法,或者可以这样去理解。

但spring并不是直接使用org.springframework.cache.Cache,spring把Cache对象交给org.springframework.cache.CacheManager来管理,下面是org.springframework.cache.CacheManager接口的定义:

复制代码
/* * Copyright 2002-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.cache;import java.util.Collection;/** * A manager for a set of {@link Cache}s. * * @author Costin Leau * @since 3.1 */public interface CacheManager {    /**     * Return the cache associated with the given name.     * @param name cache identifier (must not be {@code null})     * @return associated cache, or {@code null} if none is found     */    Cache getCache(String name);    /**     * Return a collection of the caches known by this cache manager.     * @return names of caches known by the cache manager.     */    Collection<String> getCacheNames();}
复制代码

在spring对EHCache的支持中,org.springframework.cache.ehcache.EhCacheManager就是org.springframework.cache.CacheManager的一个实现

复制代码
  <!--         该Bean是一个org.springframework.cache.CacheManager对象        属性cacheManager是一个net.sf.ehcache.CacheManager对象     -->    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">        <property name="cacheManager">            <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">                <property name="configLocation" value="classpath:ehcache-config.xml"></property>            </bean>        </property>    </bean>
复制代码

 

4.基于xml配置方式配置缓存

在上一节中,我们得到了cacheManagr,那么我们就可以对某些方法配置缓存了。下面是基于xml方式的缓存配置

复制代码
<beans xmlns="http://www.springframework.org/schema/beans"    xmlns:cache="http://www.springframework.org/schema/cache"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd     http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context-3.1.xsd     http://www.springframework.org/schema/cache     http://www.springframework.org/schema/cache/spring-cache-3.1.xsd     http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd     ">    <context:component-scan base-package="com.sin90lzc"></context:component-scan>    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">        <property name="cacheManager">            <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">                <property name="configLocation" value="classpath:ehcache-config.xml"></property>            </bean>        </property>    </bean>    <cache:advice id="cacheAdvice" cache-manager="cacheManager">        <cache:caching>            <cache:cacheable cache="dao.select" method="select"                key="#id" />            <cache:cache-evict cache="dao.select" method="save"                key="#obj" />        </cache:caching>    </cache:advice>    <aop:config>        <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* com.sin90lzc.train.spring_cache.simulation.DaoImpl.*(..))"/>    </aop:config></beans>
复制代码

 

5.注解驱动的缓存配置

复制代码
<beans xmlns="http://www.springframework.org/schema/beans"    xmlns:cache="http://www.springframework.org/schema/cache"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd     http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context-3.1.xsd     http://www.springframework.org/schema/cache     http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">    <context:component-scan base-package="com.sin90lzc"></context:component-scan>    <!--         该Bean是一个org.springframework.cache.CacheManager对象        属性cacheManager是一个net.sf.ehcache.CacheManager对象     -->    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">        <property name="cacheManager">            <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">                <property name="configLocation" value="classpath:ehcache-config.xml"></property>            </bean>        </property>    </bean>        <cache:annotation-driven /></beans>
复制代码
复制代码
package com.sin90lzc.train.spring_cache.simulation;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Component;@Componentpublic class DaoImpl implements Dao {    /**     * value定义了缓存区(缓存区的名字),每个缓存区可以看作是一个Map对象     * key作为该方法结果缓存的唯一标识,     */    @Cacheable(value = { "dao.select" },key="#id")    @Override    public Object select(int id) {        System.out.println("do in function select()");        return new Object();    }    @CacheEvict(value = { "dao.select" }, key="#obj")    @Override    public void save(Object obj) {        System.out.println("do in function save(obj)");    }}
复制代码


  相关解决方案