Spring+Hibernate+EHcache配置

大量数据流动是web应用性能问题常见的原因,而缓存被广泛的用于优化数据库应用。cache被设计为通过保存从数据库里load的数据来减少应用和数据库之间的数据流动。数据库访问只有当检索的数据不在cache里可用时才必要。hibernate可以用两种不同的对象缓存:first-level cache 和 second-level cache。first-level cache和Session对象关联,而second-level cache是和Session Factory对象关联。 

        缺省地,hibernate已经使用基于每个事务的first-level cache。Hibernate用first-level cache主要是减少在一个事务内的sql查询数量。例如,如果一个对象在同一个事务内被修改多次,hibernate将只生成一个包括所有修改的UPDATE SQL语句。为了减少数据流动,second-level cache在Session Factory级的不同事务之间保持load的对象,这些对象对整个应用可用,不只是对当前用户正在运行的查询。这样,每次查询将返回已经load在缓存里的对象,避免一个或更多潜在的数据库事务。 

下载ehcache,hibernate3.2必须要ehcache1.2以上才能支持。可以修改log4j配置文件log4j.logger.net.sf.hibernate.cache=debug查看日志 

1.在类路径上ehcache.xml: 



<ehcache> 

    <!-- Sets the path to the directory where cache .data files are created. 

         If the path is a Java System Property it is replaced by 
         its value in the running VM. 

         The following properties are translated: 
         user.home - User's home directory 
         user.dir - User's current working directory 
         java.io.tmpdir - Default temp file path --> 
    <diskStore path="java.io.tmpdir"/> 


    <!--Default Cache configuration. These will applied to caches programmatically created through 
        the CacheManager. 

        The following attributes are required: 

        maxElementsInMemory            - Sets the maximum number of objects that will be created in memory 
        eternal                        - Sets whether elements are eternal. If eternal, timeouts are ignored and the 
                                         element is never expired. 
        overflowToDisk                 - Sets whether elements can overflow to disk when the in-memory cache 
                                         has reached the maxInMemory limit. 

        The following attributes are optional: 
        timeToIdleSeconds              - Sets the time to idle for an element before it expires. 
                                         i.e. The maximum amount of time between accesses before an element expires 
                                         Is only used if the element is not eternal. 
                                         Optional attribute. A value of 0 means that an Element can idle for infinity. 
                                         The default value is 0. 
        timeToLiveSeconds              - Sets the time to live for an element before it expires. 
                                         i.e. The maximum time between creation time and when an element expires. 
                                         Is only used if the element is not eternal. 
                                         Optional attribute. A value of 0 means that and Element can live for infinity. 
                                         The default value is 0. 
        diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine. 
                                         The default value is false. 
        diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value 
                                         is 120 seconds. 
        --> 

    <defaultCache 
        maxElementsInMemory="10000" 
        eternal="false" 
        overflowToDisk="true" 
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        diskPersistent="false" 
        diskExpiryThreadIntervalSeconds="120"/> 
        
    <!-- See http://ehcache.sourceforge.net/documentation/#mozTocId258426 for how to configure caching for your objects --> 
</ehcache> 


2.applicationContext-hibernate.xml里Hibernate SessionFactory配置:<!-- Hibernate SessionFactory --> 
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="dataSource" ref="dataSource"/> 
        <property name="configLocation"><value>classpath:hibernate.cfg.xml</value></property> 
        <!-- The property below is commented out b/c it doesn't work when run via 
             Ant in Eclipse. It works fine for individual JUnit tests and in IDEA ?? 
        <property name="mappingJarLocations"> 
            <list><value>file:dist/appfuse-dao.jar</value></list> 
        </property> 
        --> 
        <property name="hibernateProperties"> 
            <props> 
                <prop key="hibernate.dialect">@HIBERNATE-DIALECT@</prop> 
                <!--<prop key="hibernate.show_sql">true</prop>--> 
                <prop key="hibernate.max_fetch_depth">3</prop> 
                <prop key="hibernate.hibernate.use_outer_join">true</prop> 
                <prop key="hibernate.jdbc.batch_size">10</prop> 
                <prop key="hibernate.cache.use_query_cache">true</prop> 
                <prop key="hibernate.cache.use_second_level_cache">true</prop> 
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 
                <!-- 
                <prop key="hibernate.use_sql_comments">false</prop> 
                --> 
                <!-- Create/update the database tables automatically when the JVM starts up 
                <prop key="hibernate.hbm2ddl.auto">update</prop> --> 
                <!-- Turn batching off for better error messages under PostgreSQL 
                <prop key="hibernate.jdbc.batch_size">0</prop> --> 
            </props> 
        </property> 
        <property name="entityInterceptor"> 
           <ref local="auditLogInterceptor"/> 
        </property> 
    </bean> 


说明:如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、 list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置hibernate.cache.use_query_cache true 才行 

3.model类里采用Xdoclet生成*.hbm.xml里的cache xml标签,即<cache usage="read-only"/> 
/** 
* @hibernate.class table="WF_WORKITEM_HIS" 
* @hibernate.cache usage="read-write" 

*/ 


4.对于"query cache",需要在程序里编码: 

        getHibernateTemplate().setCacheQueries(true); 
        return getHibernateTemplate().find(hql); 
Spring AOP+EHCache简单缓存系统解决方案 

需要使用Spring来实现一个Cache简单的解决方案,具体需求如下:使用任意一个现有开源Cache Framework,要求可以Cache系统中Service或则DAO层的get/find等方法返回结果,如果数据更新(使用Create/update/delete方法),则刷新cache中相应的内容。 MethodCacheInterceptor.java 


Java代码 
package com.co.cache.ehcache;    
   
import java.io.Serializable;    
   
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;    
   
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.debug("Find object from cache is " + cache.getName());    
            
        String cacheKey = getCacheKey(targetName, methodName, arguments);    
        Element element = cache.get(cacheKey);    
   
        if (element == null) {    
            logger.debug("Hold up method , Get method result and create cache........!");    
            result = invocation.proceed();    
            element = new Element(cacheKey, (Serializable) result);    
            cache.put(element);    
        }    
        return element.getValue();    
    }    
   
    /**   
     * 获得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, "Need a cache. Please use setCache(Cache) create it.");    
    }    
   

package com.co.cache.ehcache; 

import java.io.Serializable; 

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; 

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.debug("Find object from cache is " + cache.getName()); 
  
   String cacheKey = getCacheKey(targetName, methodName, arguments); 
   Element element = cache.get(cacheKey); 

   if (element == null) { 
    logger.debug("Hold up method , Get method result and create cache........!"); 
    result = invocation.proceed(); 
    element = new Element(cacheKey, (Serializable) result); 
    cache.put(element); 
   } 
   return element.getValue(); 


/** 
* 获得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, "Need a cache. Please use setCache(Cache) create it."); 






上面的代码中可以看到,在方法public Object invoke(MethodInvocation invocation) 中,完成了搜索Cache/新建cache的功能。 


Java代码 
Element element = cache.get(cacheKey); 
Element element = cache.get(cacheKey); 


这句代码的作用是获取cache中的element,如果cacheKey所对应的element不存在,将会返回一个null值 


Java代码 
result = invocation.proceed(); 
result = invocation.proceed(); 


这句代码的作用是获取所拦截方法的返回值,详细请查阅AOP相关文档。 

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


Java代码 
package com.co.cache.ehcache;    
   
import java.lang.reflect.Method;    
import java.util.List;    
   
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;    
   
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.debug("remove cache " + cacheKey);    
            }    
        }    
    }    
   
    public void afterPropertiesSet() throws Exception {    
        Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it.");    
    }    
   

package com.co.cache.ehcache; 

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

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; 

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.debug("remove cache " + cacheKey); 
    } 
   } 


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





上面的代码很简单,实现了afterReturning方法实现自AfterReturningAdvice接口,方法中所定义的内容将会在目标方法执行后执行,在该方法中 

Java代码 
String className = arg3.getClass().getName(); 
String className = arg3.getClass().getName(); 
的作用是获取目标class的全名,如:com.co.cache.test.TestServiceImpl,然后循环cache的key list,remove cache中所有和该class相关的element。 

随后,开始配置ehCache的属性,ehCache需要一个xml文件来设置ehCache相关的一些属性,如最大缓存数量、cache刷新的时间等等. 
ehcache.xml 


Java代码 
<ehcache>    
    <diskStore path="c:\\myapp\\cache"/>    
    <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> 
<diskStore path="c:\\myapp\\cache"/> 
<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> 
配置每一项的详细作用不再详细解释,有兴趣的请google下 ,这里需要注意一点defaultCache标签定义了一个默认的Cache,这个Cache是不能删除的,否则会抛出No default cache is configured异常。另外,由于使用拦截器来刷新Cache内容,因此在定义cache生命周期时可以定义较大的数值,timeToIdleSeconds="300000" timeToLiveSeconds="600000",好像还不够大? 

然后,在将Cache和两个拦截器配置到Spring,这里没有使用2.0里面AOP的标签。 
cacheContext.xml 


Java代码 
<?xml version="1.0" encoding="UTF-8"?>    
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">    
<beans>    
    <!-- 引用ehCache的配置 -->    
    <bean id="defaultCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">    
      <property name="configLocation">    
        <value>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.co.cache.ehcache.MethodCacheInterceptor">    
      <property name="cache">    
        <ref local="ehCache" />    
      </property>    
    </bean>    
    <!-- flush cache拦截器 -->    
    <bean id="methodCacheAfterAdvice" class="com.co.cache.ehcache.MethodCacheAfterAdvice">    
      <property name="cache">    
        <ref local="ehCache" />    
      </property>    
    </bean>    
        
    <bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">    
      <property name="advice">    
        <ref local="methodCacheInterceptor"/>    
      </property>    
      <property name="patterns">    
        <list>    
            <value>.*find.*</value>    
            <value>.*get.*</value>    
        </list>    
      </property>    
    </bean>    
    <bean id="methodCachePointCutAdvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">    
      <property name="advice">    
        <ref local="methodCacheAfterAdvice"/>    
      </property>    
      <property name="patterns">    
        <list>    
          <value>.*create.*</value>    
          <value>.*update.*</value>    
          <value>.*delete.*</value>    
        </list>    
      </property>    
    </bean>    
</beans> 
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
<!-- 引用ehCache的配置 --> 
<bean id="defaultCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> 
   <property name="configLocation"> 
   <value>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.co.cache.ehcache.MethodCacheInterceptor"> 
   <property name="cache"> 
   <ref local="ehCache" /> 
   </property> 
</bean> 
<!-- flush cache拦截器 --> 
<bean id="methodCacheAfterAdvice" class="com.co.cache.ehcache.MethodCacheAfterAdvice"> 
   <property name="cache"> 
   <ref local="ehCache" /> 
   </property> 
</bean> 

<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
   <property name="advice"> 
   <ref local="methodCacheInterceptor"/> 
   </property> 
   <property name="patterns"> 
   <list> 
    <value>.*find.*</value> 
    <value>.*get.*</value> 
   </list> 
   </property> 
</bean> 
<bean id="methodCachePointCutAdvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
   <property name="advice"> 
   <ref local="methodCacheAfterAdvice"/> 
   </property> 
   <property name="patterns"> 
   <list> 
    <value>.*create.*</value> 
    <value>.*update.*</value> 
    <value>.*delete.*</value> 
   </list> 
   </property> 
</bean> 
</beans> 


上面的代码最终创建了两个"切入点",methodCachePointCut和methodCachePointCutAdvice,分别用于拦截不同方法名的方法,可以根据需要任意增加所需要拦截方法的名称。 
需要注意的是 


Java代码 
<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> 
<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> 


如果cacheName属性内设置的name在ehCache.xml中无法找到,那么将使用默认的cache(defaultCache标签定义). 

事实上到了这里,一个简单的Spring + ehCache Framework基本完成了,为了测试效果,举一个实际应用的例子,定义一个TestService和它的实现类TestServiceImpl,里面包含 

两个方法getAllObject()和updateObject(Object Object),具体代码如下 
TestService.java 


Java代码 
package com.co.cache.test;    
   
import java.util.List;    
   
public interface TestService {    
    public List getAllObject();    
   
    public void updateObject(Object Object);    

package com.co.cache.test; 

import java.util.List; 

public interface TestService { 
public List getAllObject(); 

public void updateObject(Object Object); 



TestServiceImpl.java 


Java代码 
package com.co.cache.test;    
   
import java.util.List;    
   
public class TestServiceImpl implements TestService    
{    
    public List getAllObject() {    
        System.out.println("---TestService:Cache内不存在该element,查找并放入Cache!");    
        return null;    
    }    
   
    public void updateObject(Object Object) {    
        System.out.println("---TestService:更新了对象,这个Class产生的cache都将被remove!");    
    }    

package com.co.cache.test; 

import java.util.List; 

public class TestServiceImpl implements TestService 

public List getAllObject() { 
   System.out.println("---TestService:Cache内不存在该element,查找并放入Cache!"); 
   return null; 
    } 

public void updateObject(Object Object) { 
   System.out.println("---TestService:更新了对象,这个Class产生的cache都将被remove!"); 
    } 



使用Spring提供的AOP进行配置 
applicationContext.xml 


Java代码 
<?xml version="1.0" encoding="UTF-8"?>    
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">    
   
<beans>    
    <import resource="cacheContext.xml"/>    
        
    <bean id="testServiceTarget" class="com.co.cache.test.TestServiceImpl"/>    
        
    <bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">    
      <property name="target">    
          <ref local="testServiceTarget"/>    
      </property>    
      <property name="interceptorNames">    
        <list>    
          <value>methodCachePointCut</value>    
          <value>methodCachePointCutAdvice</value>    
        </list>    
      </property>    
    </bean>    
</beans> 
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 

<beans> 
<import resource="cacheContext.xml"/> 

<bean id="testServiceTarget" class="com.co.cache.test.TestServiceImpl"/> 

    <bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean"> 
   <property name="target"> 
    <ref local="testServiceTarget"/> 
   </property> 
   <property name="interceptorNames"> 
   <list> 
    <value>methodCachePointCut</value> 
    <value>methodCachePointCutAdvice</value> 
   </list> 
   </property> 
</bean> 
</beans> 


这里一定不能忘记import cacheContext.xml文件,不然定义的两个拦截器就没办法使用了。 

最后,写一个测试的代码 
MainTest.java 


Java代码 
package com.co.cache.test;    
   
import org.springframework.context.ApplicationContext;    
import org.springframework.context.support.ClassPathXmlApplicationContext;    
   
public class MainTest{    
    public static void main(String args[]){    
        String DEFAULT_CONTEXT_FILE = "/applicationContext.xml";    
        ApplicationContext context = new ClassPathXmlApplicationContext(DEFAULT_CONTEXT_FILE);    
        TestService testService = (TestService)context.getBean("testService");    
   
        System.out.println("1--第一次查找并创建cache");    
        testService.getAllObject();    
            
        System.out.println("2--在cache中查找");    
        testService.getAllObject();    
            
        System.out.println("3--remove cache");    
        testService.updateObject(null);    
            
        System.out.println("4--需要重新查找并创建cache");    
        testService.getAllObject();    
    }       

package com.co.cache.test; 

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class MainTest{ 
public static void main(String args[]){ 
   String DEFAULT_CONTEXT_FILE = "/applicationContext.xml"; 
   ApplicationContext context = new ClassPathXmlApplicationContext(DEFAULT_CONTEXT_FILE); 
   TestService testService = (TestService)context.getBean("testService"); 

   System.out.println("1--第一次查找并创建cache"); 
   testService.getAllObject(); 
  
   System.out.println("2--在cache中查找"); 
   testService.getAllObject(); 
  
   System.out.println("3--remove cache"); 
   testService.updateObject(null); 
  
   System.out.println("4--需要重新查找并创建cache"); 
   testService.getAllObject(); 




运行,结果如下 


Java代码 
1--第一次查找并创建cache    
---TestService:Cache内不存在该element,查找并放入Cache!    
2--在cache中查找    
3--remove cache    
---TestService:更新了对象,这个Class产生的cache都将被remove!    
4--需要重新查找并创建cache    
---TestService:Cache内不存在该element,查找并放入Cache! 
1--第一次查找并创建cache 
---TestService:Cache内不存在该element,查找并放入Cache! 
2--在cache中查找 
3--remove cache 
---TestService:更新了对象,这个Class产生的cache都将被remove! 
4--需要重新查找并创建cache 
---TestService:Cache内不存在该element,查找并放入Cache! 


可以看到,第一步执行getAllObject(),执行TestServiceImpl内的方法,并创建了cache,在第二次执行getAllObject()方法时,由于cache有该方法的缓存,直接从cache中get出方法的结果,所以没有打印出TestServiceImpl中的内容,而第三步,调用了updateObject方法,和TestServiceImpl相关的cache被remove,所以在第四步执行时,又执行TestServiceImpl中的方法,创建Cache。 



注意的问题 

我们知道,Cache为ehcache.XML配置文件里面所定义的缓存类别,获取某一特定的缓存类别的方法如下: 
Cache cache= cacheManager.getCache(cacheName); 
cacheName为想获取的缓存类别名。然后象下面方法把某一对象放入上面定义的缓存: 
cache.put(new Element(key,(Serializable)value)); 
key为 放入该缓存中的对象的索引值,value为放入该缓存中key所对应的对象。我们看到,放入缓存中的value必须序列化,Java原生类型 char、int ,原生类型的包装类String、Character、Integer、Number...和集合List的实现类ArrayList都已经实现了Serializable接口,它们都可以直接放到缓存中。这里要注意的是,在方法返回值中经常用到的Iterator,并没有实现Serializable接口,所以Cache 不能缓存返回值类型为Iterator的方法。 
    还有一点要注意的是,如果我们要做缓存的方法是在bean的生命周期的初始化阶段调用的(例如setter,init),此时方法缓存拦截器还没被调用执行,那么缓存将不起作用,如做了下面的配置: 
<bean id="OrganizationManagerMethodCache" class="org.springFramework.aop.framework.ProxyFactoryBean"> 
    <property name="target"> 
        <bean class="com.wzj.rbac.ServiceFacade.OrganizationManager" init-method="init" autowire="byName"/>     
    </property> 
    <property name="interceptorNames"> 
       <list> 
            <value>methodCachePointCut</value> 
        </list> 
     </property> 
</bean> 
在init初始方法里面调用的缓存方法将失效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值