整合之道--Spring4整合Ehcache2.10
1 写在前面的话
整合思路
Spring与其它框架的整合一般的思路就是将其它框架当作Spring的Bean管理起来,通常会由Spring提供该bean的基本实现。用户仅仅需配置就可以。
配置中主要告诉Spring须要整合的是什么东西,怎么实现,有些Spring有相应的实现,Spring没有实现的仅仅需实现Spring的相应接口。然后配置一下就OK了。须要载入配置文件的再告诉Spring配置文件的路径就可以。
spring与hibernate的整合就是将hibernate的sessionFactory当作一个bean由spring配置起来,其具体相应实现为org.springframework.orm.hibernate5.LocalSessionFactoryBean(Hibernate5的Spring实现)
关于hibernate的整合參见
Spring整合Ehcache也就是将Ehcache中最核心的CacheManager和Cache交由Spring来管理,在Spring看来也就是两个Bean
2 Ehcache安装
首先看一下怎样单独的使用Ehcache
Ehcache请參考官方
http://www.ehcache.org/generated/2.10.1/html/ehc-all/
从官方的介绍可知。Ehcache的安装过程例如以下
1. 下载Ehcache(依赖SLF4J。所以也要下载SLF4J)。并将其放在classpath中
2. 配置ehcache.xml文件,并将其放在classpath中
本文选择的版本号为Ehcache2.10.0
mavan依赖例如以下
<!--ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.0</version>
</dependency>
<!--ehcache-->
<!--ehcache依赖slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.18</version>
</dependency>
<!--ehcache依赖slf4j-->
<!--slf4j须要log4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.18</version>
</dependency>
<!--slf4j须要log4j-->
<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<!--log4j-->
日志配置例如以下
log4j.properties
#---------------------------------------------------------
# Log4J Settings for log4j 1.2.x (via jakarta-commons-logging)
#
# The five logging levels used by Log are (in order):
#
# 1. DEBUG (the least serious)
# 2. INFO
# 3. WARN
# 4. ERROR
# 5. FATAL (the most serious)
#
#---------------------------------------------------------
# 日志输出级别
#---------------------------------------------------------
log4j.rootLogger=debug, stdout, info_log, error_log
#---------------------------------------------------------
# 输出到控制台
#---------------------------------------------------------
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout=org.apache.log4j.TTCCLayout
#---------------------------------------------------------
# info_log
#---------------------------------------------------------
log4j.appender.info_log=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info_log.File=/usr/logs/SpringCache/info.log
log4j.appender.info_log.Append=true
log4j.appender.info_log.Threshold=INFO
log4j.appender.info_log.layout=org.apache.log4j.PatternLayout
log4j.appender.info_log.DatePattern='.'yyyy-MM-dd
log4j.appender.info_log.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss:SSS} %p [%M] %c %L %m%n
#---------------------------------------------------------
# error_log
#---------------------------------------------------------
log4j.appender.error_log=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error_log.File=/usr/logs/SpringCache/error.log
log4j.appender.error_log.Append=true
log4j.appender.error_log.Threshold=ERROR
log4j.appender.error_log.layout=org.apache.log4j.PatternLayout
log4j.appender.error_log.DatePattern='.'yyyy-MM-dd
log4j.appender.error_log.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss:SSS} %p [%M] %c %L %m%n
Ehcache的配置文件例如以下
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskSpoolBufferSizeMB="30"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<cache name="sampleCache1"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap"/>
</cache>
</ehcache>
ehcache.xml中的配置来自Ehcache官方下载包中的exchache.xml片段。
依照官方说明执行Ehcache演示样例
Ehcache測试程序
package com.gwc.springlearn;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.junit.Test;
/**
* Created by GWCheng on 2016/3/4.
*/
public class TestEhcache {
@Test
public void testEhcache() {
// Creating a CacheManager based on a specified configuration file.
CacheManager manager = CacheManager.newInstance("src/main/resources/ehcache.xml");
// obtains a Cache called sampleCache1, which has been preconfigured in the configuration file
Cache cache = manager.getCache("sampleCache1");
// puts an element into a cache
Element element = new Element("key1", "哈哈");
cache.put(element);
//The following gets a NonSerializable value from an element with a key of key1.
Object value = element.getObjectValue();
System.out.println(value.toString());
manager.shutdown();
}
}
执行结果
本文并非要具体解说Ehcache的使用方法,本文仅仅是通过Ehcache的使用了解其使用方法,以方便与Spring整合。
3 与Spring整合
Ehcache核心类
从官方的介绍来看,Ehcache的核心包含CacheManager、Cache和Element
CacheManager
The CacheManager class is used to manage caches. Creation of, access to, and removal of caches is controlled by a named CacheManager.
CacheManager是Ehcache的核心。CacheManager来管理对cache的创建,訪问和移除操作。
Cache
A Cache is a thread-safe logical representation of a set of data elements, analogous to a cache region in many caching systems.
Cache是一个线程安全的数据集合的逻辑表示,是它就是缓存。
Element
An element is an atomic entry in a cache.
能够理解为缓存中的key-value形式的元素。在程序中通常将须要缓存的对象放在Element中,整合的时候不会用到。
回想一下Spring中的抽象缓存
http://blog.csdn.net/frankcheng5143/article/details/50791757
我们发现Spring对缓存的整合,主要是将CacheManager和Cache分别用Bean配置。
通过上面的分析我们知道Ehcache的核心也是CacheManager和Cache
回想一下Spring对JDK ConcurrentMap-based Cach的配置
<!-- simple cache manager -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<!-- 默认的缓存 -->
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
<!-- 样例中一直使用的"books",也就是那个cacheNames="books" -->
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="books"/>
</set>
</property>
</bean>
那么Spring对Ehcache的整合也就很easy了,将Ehcache的CacheManage和Cache分别交给Spring管理就ok了。
Spring整合Ehcache的配置文件
核心配置例如以下
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/>
<!-- EhCache library setup -->
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml"/>
ehcache.xml仍然採用上面的配置
完整的缓存配置spring-ehcache.xml例如以下
spring-ehcache.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:p="http://www.springframework.org/schema/p"
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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.2.xsd">
<context:component-scan base-package="com.gwc.springlearn"/>
<cache:annotation-driven/>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/>
<!-- EhCache library setup -->
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml"/>
</beans>
4 測试
为了測试的一致性,採用和 Spring文档学习–缓存(Cache Abstraction)
同样的測试用例
项目结构
整合之后的maven依赖
<dependencies>
<!--spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!--spring -->
<!--ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.0</version>
</dependency>
<!--ehcache-->
<!--ehcache依赖slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.18</version>
</dependency>
<!--ehcache依赖slf4j-->
<!--slf4j须要log4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.18</version>
</dependency>
<!--slf4j须要log4j-->
<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<!--log4j-->
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--junit-->
</dependencies>
由于Spring文档学习–缓存(Cache Abstraction)中的缓存名字为“books”。所以改动ehcache.xml的name为“books”
例如以下
<cache name="books"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap"/>
</cache>
执行測试用例,測试用例參考Spring文档学习–缓存(Cache Abstraction)
由于启动或者关闭程序缓存并没有关闭,所以为了測试,在执行之前须要清空缓存。并且这次须要载入spring-ehcache.xml
@ContextConfiguration(locations = {"classpath:spring-ehcache.xml"})
在測试用例中加入例如以下代码
@Before
public void init(){
cacheService.loadBooks();
}
被測试的CacheService不变。CacheService參考Spring文档学习–缓存(Cache Abstraction)
測试@Cacheable
@Test
public void testCacheable() throws BookNotFoundException {
Book book = null;
for (int i = 0; i < 10; i++) {
book = cacheService.findBook("123");
}
cacheService.findBook("456");
cacheService.findBook("456");
cacheService.findBook("456");
}
执行报错例如以下
ERROR net.sf.ehcache.store.disk.DiskStorageFactory - Disk Write of 456 failed:
java.io.NotSerializableException: com.gwc.springlearn.Book
Ehcache被缓存的对象须要实现Serializable接口
改动Book.java
public class Book implements Serializable{
//省略,參考http://blog.csdn.net/frankcheng5143/article/details/50791757
}
继续执行
说明已经讲Ehcache整合到了Spring中。
关于其它方法的測试參考
http://blog.csdn.net/frankcheng5143/article/details/50791757
參考文献
http://www.ehcache.org/generated/2.9.0/pdf/Ehcache_API_Developer_Guide.pdf
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/
http://blog.csdn.net/frankcheng5143/article/details/50791757