1 spring与ehcache结合使用,需要导入如下的包:ehcache , commons-logging , cglib , asm , spring的jar包具体版本可以选择最新。
2 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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
- default-lazy-init="true">
- <!-- 在spring里配置cache就和在spring配置数据库一样, -->
- <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
- <property name="configLocation">
- <value>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.rmn190.MethodCache</value>
- </property>
- </bean>
- <bean id="methodCacheInterceptor" class="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>.*getList</value>
- </list>
- </property>
- </bean>
- <bean id = "personManager" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target">
- <!--<bean class="manager.PersonManagerImpl"/>-->
- <ref local="personManagerTarget"/>
- </property>
- <property name="interceptorNames">
- <list>
- <value>methodCachePointCut</value>
- </list>
- </property>
- </bean>
- <bean id = "personManagerTarget" class="manager.PersonManagerImpl"/>
- </beans>
ehcache配置文件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.
- -->
- <!-- maxElementsInMemory设定内存中创建对象的最大值 -->
- <!-- eternal设置元素(译注:内存中对象)是否永久驻留。如果是,将忽略超 时限制且元素永不消亡。-->
- <!-- overflowToDisk设置当内存中缓存达到 maxInMemory 限制时元素是否可写到磁盘上 -->
- <!-- timeToIdleSeconds设置某个元素消亡前的停顿时间。 也就是在一个元素消亡之前,两次访问时间的最大时间间隔值。
- 这只能在元素不是永久驻留时有效(译注:如果对象永恒不灭,则 设置该属性也无用)。
- 如果该值是 0 就意味着元素可以停顿无穷长的时间。
- -->
- <!-- timeToLiveSeconds为元素设置消亡前的生存时间。 也就是一个元素从构建到消亡的最大时间间隔值。 这只能在元素不是永久驻留时有效。
- -->
- <!-- diskPersistent是否disk store在虚拟机启动时持久化。默认为false -->
- <!-- diskExpiryThreadIntervalSeconds运行disk终结线程的时间,默认为120秒 -->
- <defaultCache
- maxElementsInMemory="10000"
- eternal="false"
- overflowToDisk="true"
- timeToIdleSeconds="500"
- timeToLiveSeconds="1000"
- diskPersistent="false"
- diskExpiryThreadIntervalSeconds="120"/>
- <cache name="com.rmn190.MethodCache"
- maxElementsInMemory="10"
- eternal="false"
- timeToIdleSeconds="200"
- timeToLiveSeconds="300"
- overflowToDisk="true"
- />
- </ehcache>
4 测试类如下:
主类:
- package main;
- import java.util.List;
- import manager.PersonManagerImpl;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- /*
- * 当没有导入cglib的jar包时,会抛出如下的异常:
- * 信息: Initializing EHCache CacheManager
- Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personManager': FactoryBean threw exception on object creation; nested exception is org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
- Caused by: org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
- at org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(DefaultAopProxyFactory.java:65)
- at org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy(ProxyCreatorSupport.java:106)
- at org.springframework.aop.framework.ProxyFactoryBean.getSingletonInstance(ProxyFactoryBean.java:297)
- at org.springframework.aop.framework.ProxyFactoryBean.getObject(ProxyFactoryBean.java:227)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectFromFactoryBean(AbstractBeanFactory.java:1236)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1207)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:262)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
- at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:733)
- at main.HelloEhcacheSpring.main(HelloEhcacheSpring.java:15)
- */
- /*
- * 加入cglib,而没加入asm的jar包时,抛出如下异常:
- * 信息: Initializing EHCache CacheManager
- Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personManager': FactoryBean threw exception on object creation; nested exception is java.lang.NoClassDefFoundError: org/objectweb/asm/Type
- Caused by: java.lang.NoClassDefFoundError: org/objectweb/asm/Type
- at net.sf.cglib.core.TypeUtils.parseType(TypeUtils.java:180)
- at net.sf.cglib.core.KeyFactory.<clinit>(KeyFactory.java:66)
- at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:69)
- at org.springframework.aop.framework.Cglib2AopProxy.createEnhancer(Cglib2AopProxy.java:224)
- at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:151)
- at org.springframework.aop.framework.ProxyFactoryBean.getProxy(ProxyFactoryBean.java:342)
- at org.springframework.aop.framework.ProxyFactoryBean.getSingletonInstance(ProxyFactoryBean.java:297)
- at org.springframework.aop.framework.ProxyFactoryBean.getObject(ProxyFactoryBean.java:227)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectFromFactoryBean(AbstractBeanFactory.java:1236)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1207)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:262)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
- at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:733)
- at main.HelloEhcacheSpring.main(HelloEhcacheSpring.java:32)
- Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type
- at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
- at java.security.AccessController.doPrivileged(Native Method)
- at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
- at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
- at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
- ... 14 more
- */
- /*
- * 这里使用了ehcache与spring结合,这里并没用用到数据库,用spring只是用来管理bean,这里用ehcache就相当于数据库,存放对象信息
- */
- @SuppressWarnings({"unchecked"})
- public class HelloEhcacheSpring {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- PersonManagerImpl personManager = (PersonManagerImpl) context.getBean("personManagerTarget");//配置了spring就可以从配置文件里找到对应的接口实现类,再生成实例对象,以完成业务处理
- for(int i=0;i<5;i++) {
- showPersonsInfo(personManager);
- }
- }
- private static void showPersonsInfo(PersonManagerImpl personManager) {
- //要是没有cache时,那么这里会直接从PersonmanagerImpl类的实例对象获取到数据,这里配置了cache后,就会先跳到cache去更新cache,再往下执行
- List<String> persons = personManager.getList();
- for(String person : persons) {
- System.out.println(person);
- }
- }
- }
数据访问时,触发ehcache的更新:
- package intercepter;
- import java.io.Serializable;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- import org.springframework.beans.factory.InitializingBean;
- import net.sf.ehcache.Cache;
- import net.sf.ehcache.Element;
- public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean{
- private Cache cache;
- public void setCache(Cache cache) {
- this.cache = cache;
- }
- /*
- * 首先有一点要明白的是:invoke的触发都在由于DAO或sevlet的数据访问时才会调用到
- */
- //invoke方法会在spring配置文件里的,指明的cache拦截的方法的调用时,自动触发它,如这个项目里,当运行HelloEhcacheSpring.java类时,在showPersonsInfo方法里调用到personManager.getList()方法时,它就会先调到这里来执行,执行完才行下执行它的业务
- public Object invoke(MethodInvocation invocation) throws Throwable {
- String targetName = invocation.getThis().getClass().getName();//这个表示哪个类调用(或触发)了这个MethodCacheInterceptor,如里的:manager.PersonMagagerImpl
- String methodName = invocation.getMethod().getName();//这个表示哪个方法触发了这个类(MethodCacheInterceptor)方法(invoke)的调用,如这里的:getList
- Object[] arguments = invocation.getArguments();//调用的参数,这里没有参数
- Object result;
- String cacheKey = getCacheKey(targetName, methodName, arguments);//这里得出的是:manager.PersonManagerImpl.getList
- Element element = cache.get(cacheKey);
- if (element == null) {
- // call target/sub-interceptor
- result = invocation.proceed();//这个就是调用数据访问方法,如这里是调用manager.PersonManagerImpl.getList(),并用result保存执行的结果(数据访问的结果),如这里调用了getList()方法,会先打印出"get Person from DB" ,然后将结果集放入到result里面去,这里由于使用的是自己配置只能放入10个元素的ehcache,所以这里的result是ArrayList<E> ,它里面存放的是elementData[10],并将getList得到的结果放入到elementData里面去了
- System.out.println("set into cache");
- // cache method result
- //下面方法执行后,将cacheKey与数据集连起来,cacheKey是用来标识这个element的标志,我们可以有多个element(各自是来自不同的数据访问方法而形成的),区分它们就是用cacheKey,
- element = new Element(cacheKey, (Serializable) result);//这里的新生成后的element,含有cacheKey,还在element创建时间,访问时间,还有命令次数等cache的属性,我觉得它就像是一个小cache一样,下次要不要更新它就要看它的这些属性来决定。
- cache.put(element);//放入cache中
- }
- System.out.println("out cache");//完成cache操作
- return element.getValue();
- }
- 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();
- }
- public void afterPropertiesSet() throws Exception {
- if(null == cache) {
- throw new IllegalArgumentException("Cache should not be null.");
- }
- }
- }
数据提供类:
- package manager;
- import java.util.ArrayList;
- import java.util.List;
- @SuppressWarnings("unchecked")
- public class PersonManagerImpl {
- private static List persons;
- static {
- persons = new ArrayList();
- persons.add("Wang");
- persons.add("zang");
- persons.add("Li");
- persons.add("song");
- persons.add("yan");
- }
- public List getList() {
- System.out.println("getPerons from DB");
- return persons;
- }
- }