本篇实例摘自《JavaEE企业应用实战(第四版)》李刚
前期准备
需要EhCache环境,使用ehcache-core-2.4.3.jar和slf4j-api-1.6.1.jar(不一定要这个版本的),这两个包可以在Hibernate解压出来的文件夹中->lib/optional/ehcache文件夹里面找到。之后复制到WEB-INF/lib文件夹中即可。
示例
先配置四个缓存区,类和方法在进入缓存区的时候需要指定缓冲区的名字,在src文件夹下创建一个专门配置EhCache的xml文件——ehcache.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir" />
<!-- 配置默认的缓存区 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<!-- 配置名为users的缓存区 -->
<cache name="users"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600" />
<cache name="users1"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600" />
<cache name="users2"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600" />
</ehcache>
之后在beans.xml文件中引入这个配置文件,需要在beans标签里面添加cache的支持,我是这样写的
<?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:c="http://www.springframework.org/schema/c"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.service"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:ehcache.xml"
p:shared="false"
/>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cacheManager-ref="ehCacheManager"
/>
</beans>
其中EhCacheManagerFactoryBean是一个工厂Bean,它的产品就是CacheManager对象。接下来是UserService接口
package com.service;
import com.entity.User;
public interface UserService {
public User getUserByNameAndAge(String name, int age);
public User getAnotherUser(String name, int age);
}
它的实现类
package com.service.impl;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.entity.User;
import com.service.UserService;
@Service("userServiceImpl")
@Cacheable(value="users")
public class UserServiceImpl implements UserService {
@Override
public User getUserByNameAndAge(String name, int age) {
// TODO Auto-generated method stub
System.out.println("--正在执行getUserByNameAndAge()查询方法--");
return new User(name, age);
}
@Override
public User getAnotherUser(String name, int age) {
// TODO Auto-generated method stub
System.out.println("正在执行getAnotherUser()查询方法");
return new User(name+"hh", age);
}
@CacheEvict(value="users")
public void evictUser(String name, int age) {
System.out.println("正在清空" + name + "," + age + "对应的缓存");
}
@CacheEvict(value="users", allEntries=true)
public void evictAll() {
System.out.println("正在清空整个缓存");
}
}
在类上写@Cacheable(value=”users”)是指对这个类的所有方法都缓存,如果写在类里的面的方法上面就是对该方法缓存。value=”users”是指缓存区的名字,在这里是缓存到users缓存区中。
测试代码
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
User user1 = userServiceImpl.getUserByNameAndAge("张三", 12);
User user2 = userServiceImpl.getAnotherUser("李四", 20);
userServiceImpl.evictUser("李四", 20);
User user3 = userServiceImpl.getAnotherUser("李四", 20);
System.out.println("user2 ? user3=" + (user2 == user3));
User user4 = userServiceImpl.getUserByNameAndAge("张三", 12);
System.out.println("user1 ? user4=" + (user1 == user4));
userServiceImpl.evictAll();
User user5 = userServiceImpl.getAnotherUser("张三", 12);
User user6 = userServiceImpl.getAnotherUser("李四", 20);
System.out.println("user1 ? user5=" + (user1 == user5));
System.out.println("user3 ? user6=" + (user3 == user6));
执行的效果如下
这里user2和user3不相等是因为创建user3的时候user2已经从缓存区消除了,所以user3是新创建的,user1和user4是相等的是因为创建user1的时候已经把UserServiceImpl中接收(String name, Integer age)参数的且参数是(“张三”,12)的“方法”已经缓存了所以在此使用这个类里面的参数相同的方法时就会使用到缓存区的内容。之后通过使用evictAll()来使用@CacheEvict(value=”users”, allEntries=true)去清除users缓存区的全部内容,所以user5和user6都是新的,因为这时缓存区已经设置为空了。使用缓存需要注意的是:
1. 如果@Cacheable用于修饰类那么程序调用了该类的任意方法时,只要传入的参数相同,Spring就会使用缓存
2. 在使用@Cacheable的时候可能会出现BeanNotOfRequiredType的错误,可以在beans.xml文件中加入
3. @CachePut和@Cacheable很像,区别在于@CachePut每次都会去执行这个方法,不管缓存区是否已有数据,这样做是为了保证方法能够被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新
4. 不同的缓存区不能共享缓存数据,users1缓存区的数据不能别users2所使用