概述
首先请阅读Spring Cache抽象-基于XML的配置声明(基于ConcurrentMap的配置),本篇博文基于XML的配置,使用了Ehcache缓存管理器。
基于Java类注解的EhCache请阅读 Spring Cache抽象-使用Java类注解的方式整合EhCache
完整示例
pom.xml增加依赖
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>${ehcache.version}</version> </dependency>
版本为 : <ehcache.version>2.10.4</ehcache.version>
数据库表数据(Oracle):
实体类
package com.xgj.cache.springCacheXmlEhCache.domain; import java.io.Serializable; /** * * * @ClassName: LittleArtisan * * @Description: Java中的缓存和序列化是息息相关的,注意实现Serializable接口 * * @author: Mr.Yang * * @date: 2017年10月2日 下午1:40:53 */ public class LittleArtisan implements Serializable { private static final long serialVersionUID = 1L; private String artisanId; private String artisanName; private String artisanDesc; public String getArtisanId() { return artisanId; } public void setArtisanId(String artisanId) { this.artisanId = artisanId; } public String getArtisanName() { return artisanName; } public void setArtisanName(String artisanName) { this.artisanName = artisanName; } public String getArtisanDesc() { return artisanDesc; } public void setArtisanDesc(String artisanDesc) { this.artisanDesc = artisanDesc; } public static long getSerialversionuid() { return serialVersionUID; } }
服务层
package com.xgj.cache.springCacheXmlEhCache.service; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowCallbackHandler; import com.xgj.cache.springCacheXmlEhCache.domain.LittleArtisan; /** * * * @ClassName: LittleArtisanSpringCacheService * * @Description: * * @author: Mr.Yang * * @date: 2017年10月4日 上午12:41:32 */ public class LittleArtisanSpringCacheService { private Logger logger = Logger .getLogger(LittleArtisanSpringCacheService.class); private static final String selectArtisanSQL = "select artisan_id ,artisan_name ,artisan_desc from little_artisan where artisan_name = ?"; private JdbcTemplate jdbcTemplate; @Autowired public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * * * @Title: getArtisan * * @Description: getArtisan 通过在xml中配置 缓存数据 * * @param artisanName * @return * * @return: LittleArtisan */ public LittleArtisan getArtisan(String artisanName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 System.out.println("查找Artisan:" + artisanName); return getFromDB(artisanName); } /** * * * @Title: reloadArtisan * * @Description: 清除缓存 * * * @return: void */ public void reloadArtisan() { System.out.println("cache cleared"); } /** * * * @Title: getFromDB * * @Description: 从数据库中获取LittleArtisan * * @param artisanName * @return * * @return: LittleArtisan */ private LittleArtisan getFromDB(String artisanName) { System.out.println("getFromDB"); final LittleArtisan littleArtisan = new LittleArtisan(); jdbcTemplate.query(selectArtisanSQL, new Object[] { artisanName }, new RowCallbackHandler() { @Override public void processRow(ResultSet rs) throws SQLException { littleArtisan.setArtisanId(rs.getString("artisan_id")); littleArtisan.setArtisanName(rs .getString("artisan_name")); littleArtisan.setArtisanDesc(rs .getString("artisan_desc")); } }); return littleArtisan; } }
ehcache的配置文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir" /> <cache name="littleArtisan" maxEntriesLocalHeap="100" maxEntriesLocalDisk="1000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <persistence strategy="localTempSwap" /> </cache> </ehcache>
Spring-EhCache配置文件
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!-- 扫描注入注解,比如@Autowired --> <context:component-scan base-package="com.xgj.cache.springCacheXml"/> <!-- 使用context命名空间,加载数据库的properties文件 --> <context:property-placeholder location="classpath:spring/jdbc.properties" /> <!-- 数据库 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <!-- 配置namedParameterJdbcTemplate模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> <!-- 定义需要使用缓存的类 --> <bean id="littleArtisanSpringCacheService" class="com.xgj.cache.springCacheXmlEhCache.service.LittleArtisanSpringCacheService"/> <!-- 缓存管理器 Ehcache实现--> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcacheManager"/> <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache/ehcache-spring.xml"/> <!-- 缓存定义 --> <cache:advice id="cacheAdvice" cache-manager="cacheManager" > <cache:caching cache="littleArtisan"> <!-- 公共缓存littleArtisan --> <cache:cacheable method="getArtisan" key="#artisanName"/> <!-- getArtisan使用 Cacheable --> <cache:cache-evict method="reloadArtisan" all-entries="true"/><!-- reloadArtisan使用 CacheEvict --> </cache:caching> </cache:advice> <!-- 切面增强 --> <aop:config> <aop:pointcut id="cachePoint" expression="execution(* com.xgj.cache.springCacheXmlEhCache.service.LittleArtisanSpringCacheService.*(..))" /> <aop:advisor advice-ref="cacheAdvice" pointcut-ref="cachePoint"/> </aop:config> </beans>
上面的配置使用了一个Spring提供的EhCacheCacheManager来生成一个Spring的CacheManager,其接收一个Ehcache的CacheManager,因为真正用来存入缓存数据的还是Ehcache。
Ehcache的CacheManager是通过Spring提供的EhCacheManagerFactoryBean来生成的,其可以通过指定ehcache的配置文件位置来生成一个Ehcache的CacheManager。
若未指定则将按照Ehcache的默认规则取classpath根路径下的ehcache.xml文件,若该文件也不存在,则获取Ehcache对应jar包中的ehcache-failsafe.xml文件作为配置文件。
单元测试
package com.xgj.cache.springCacheXmlEhCache.service; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.xgj.cache.springCacheXmlEhCache.domain.LittleArtisan; public class TestXmlCacheEhcache { ClassPathXmlApplicationContext context = null; LittleArtisanSpringCacheService service = null; LittleArtisan littleArtisan; @Before public void initContext() { // 启动Spring 容器 context = new ClassPathXmlApplicationContext( "classpath:com/xgj/cache/springCacheXmlEhCache/conf_spring_ehcache.xml"); } @Test public void testXmlCache() { service = context.getBean("littleArtisanSpringCacheService", LittleArtisanSpringCacheService.class); // 第一次 从数据库加载 littleArtisan = service.getArtisan("littleArtisan"); printArtisan(); // 第二次 从缓存加载 littleArtisan = service.getArtisan("littleArtisan"); printArtisan(); // 清空缓存 service.reloadArtisan(); // 再次查询,从数据库加载 service.getArtisan("littleArtisan"); printArtisan(); // 又查询,从缓存加载 service.getArtisan("littleArtisan"); printArtisan(); } private void printArtisan() { System.out.println(littleArtisan.getArtisanName() + "||" + littleArtisan.getArtisanDesc()); } @After public void releaseContext() { if (context != null) { context.close(); } } }
日志输出
2017-10-04 11:12:56,227 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@683a412e: startup date [Wed Oct 04 11:12:56 BOT 2017]; root of context hierarchy 2017-10-04 11:12:56,324 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/cache/springCacheXmlEhCache/conf_spring_ehcache.xml] 2017-10-04 11:12:57,559 INFO [main] (EhCacheManagerFactoryBean.java:130) - Initializing EhCache CacheManager 查找Artisan:littleArtisan getFromDB littleArtisan||EhCache littleArtisan||EhCache cache cleared 查找Artisan:littleArtisan getFromDB littleArtisan||EhCache littleArtisan||EhCache 2017-10-04 11:12:58,901 INFO [main] (AbstractApplicationContext.java:984) - Closing org.springframework.context.support.ClassPathXmlApplicationContext@683a412e: startup date [Wed Oct 04 11:12:56 BOT 2017]; root of context hierarchy 2017-10-04 11:12:58,901 INFO [main] (EhCacheManagerFactoryBean.java:187) - Shutting down EhCache CacheManager
日志分析
第一次从数据库中加载,第二次没有打印getFromDB,说明是从缓存中取的数据。 然后清空缓存,第一次从数据库中加载,第二次从缓存中取的数据。
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster