使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署
来源:互联网 发布:阿里云ecs搭建淘宝客 编辑:程序博客网 时间:2024/05/16 12:39
概述
在分布式 web 项目中,通常即需要本地缓存提高程序性能,也需要共享缓存在多机之间交换数据。本文介绍了使用Spring缓存抽象机制混合部署的方法。
Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,使用Spring缓存抽象,程序员仅需要使用少量的注释就实现了对象的缓存,不必了解复杂的面向对象的编程(AOP)技术。
Spring 的缓存技术相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition, 而且支持 Ehcache 2.x, Gemfire cache, Caffeine, Guava caches 以及 JSR-107 兼容的缓存 (例如 Ehcache 3.x)产品。
本文第一部分简单介绍注释驱动的缓存技术,第二部分介绍使用 Redis 做共享缓存,第三部分介绍混合部署。
第一部分:注释驱动的缓存技术简介
这里假设你对Java缓存有一些了解,这里主要介绍 Spring4,EhCache3 的配置方法。其他配置请参考 Spring官网(英文)文档:
1. 配置
配置类如下:
@Configuration@EnableCachingpublic class CacheConfig {// http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-store-configuration-jsr107//http://stackoverflow.com/questions/39386830/using-ehcache-3-with-spring-annotations-not-using-spring-boot@Beanpublic JCacheCacheManager jcacheCacheManager(){JCacheCacheManager cm = new JCacheCacheManager();cm.setCacheManager(jsr107cacheManager());return cm;}@Beanpublic CacheManager jsr107cacheManager(){//http://www.ehcache.org/documentation/3.1/107.htmlCachingProvider provider = Caching.getCachingProvider();CacheManager cacheManager = provider.getCacheManager(); MutableConfiguration<Long, String> configuration = new MutableConfiguration<Long, String>() // Cannot set type for store! this may be a bug in spring or ehCache //.setTypes(Long.class, String.class) .setStoreByValue(false) .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE)); cacheManager.createCache("foo", configuration);return cacheManager;}}
@Configuration 表示这是一个配置类
@EnableCaching 启动 Cache 注释
第一个 Bean 声明 Spring Cache 的 CacheManager 抽象管理接口对象。该对象是 JSR107 缓存规范的一个适配器(Adapter)
第二个 Bean 是 JSR107规范缓存的管理对象。Caching.getCachingProvider() 能正确找到注册的具体实现模块,如 EhCache3。然后创建了 “foo” 缓存区域。
2. 加载配置
在程序启动时:
public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();ctx.register(PersistenceJDBCConfig.class);ctx.register(CacheConfig.class);ctx.register(RedisConfig.class);ctx.refresh();如果你不了解 Spring 配置类的加载,建议阅读:使用 Java 配置进行 Spring bean 管理
3. Maven 依赖
<!-- spring cache support --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${springframework.version}</version></dependency><!-- ehcache 3 & JSR107 --><dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> <version>3.1.3</version></dependency><dependency> <groupId>javax.cache</groupId> <artifactId>cache-api</artifactId> <version>1.0.0</version></dependency>
注意:必须添加 ehcache3 让 JSR107 模块找到实现。
4.缓存应用
@Service@Transactionalpublic class CacheService {@Cacheable("foo")public Foo findBook(String name) {System.out.print("cache....or not?\n");return new Foo("jdbc test1");}}假设你需要缓存结果,仅需要在@Service对象的方法上注释 @Cachable("foo") 即可实现该业务对象的缓存。
除 @Cacheable 外,常用的还有 @CachePut、@CacheEvict 注释,具体使用见:注释驱动的 Spring cache 缓存介绍 这些内容在新版本中没有变化。
注意:
(1)注意缓存与交易的关系。建议缓存在服务以上层使用,在 数据访问层(DAO)中谨慎使用!!!
(2)如果你喜欢JSR的注释,请参考Spring官方文档(英文)。
第二部分:使用 Redis 做共享缓存
Redis 的中文介绍:http://www.redis.cn/
1. 配置
@Configuration@EnableCachingpublic class RedisConfig extends CachingConfigurerSupport {@Beanpublic JedisConnectionFactory redisConnectionFactory() {JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();// DefaultsredisConnectionFactory.setHostName("127.0.0.1");redisConnectionFactory.setPort(6379);return redisConnectionFactory;}@Beanpublic RedisTemplate<String, String> redisTemplate(RedisConnectionFactory rf) {RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();redisTemplate.setConnectionFactory(rf);return redisTemplate;}@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);// Number of seconds before expiration. Defaults to unlimited (0)cacheManager.setDefaultExpiration(10); // Sets the default expire time (in seconds)return cacheManager;}}
注意:设置 Cache 过期时间要合适,太长就长期有效,太短你看不到测试结果。建议 10-30秒。
2. Maven 依赖
<!-- redis cache related.....start --><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>1.6.0.RELEASE</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.7.3</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.2</version></dependency><!-- redis cache related.....end -->
其中,commons-pool2 是 访问 Redis 服务器的链接池需要的依赖。
具体代码见:Redis 缓存 + Spring 的集成示例 ,作者写的很不错。
第三部分:EhCache 与 Redis 混合部署支持
1. 原理与代码
通过前面的配置,我们发现 Spring 缓存抽象 就是在其他 Cache 管理程序基础上提出了自己的抽象体系,即利用适配器模式建立了通用的 Cache 管理体系。
找到 org.springframework.cache.CacheManager API文档,发现改接口相当简单。我们需要做的工作就是将两个 Manager 组合一下。 代码:
MixCacheManager 源代码:
public class MixCacheManager implements CacheManager {private CacheManager redisCacheManager;private CacheManager memCacheManager;private String redisPrefix = "redis-"; public Cache getCache(String arg0) {if (arg0.startsWith(redisPrefix))return redisCacheManager.getCache(arg0);else return memCacheManager.getCache(arg0); }public Collection<String> getCacheNames() {Collection<String> cacheNames = new ArrayList<String>();if (redisCacheManager != null) {cacheNames.addAll(redisCacheManager.getCacheNames());}if (memCacheManager != null) {cacheNames.addAll(memCacheManager.getCacheNames());}return cacheNames;}// getting & setting ...}
该类非常简单。注意:redisCacheManager 和 memCacheManager 都是实现了 org.springframework.cache.CacheManager 接口的类。MixCacheManager也实现了该接口。
getCacheNames 的任务就是拼接所以的 Cache 区域;
getCache 就是根据应用需要的 Cache 名字,返回合适的 Cache。这里指定“redis-”开头的名字,使用共享缓存。
2. 配置
修改 RedisConfig 类,添加
// Problem with Autowiring & No unique bean// http://stackoverflow.com/questions/2699608/problem-with-autowiring-no-unique-bean@Bean@Primarypublic CacheManager cacheManager(RedisCacheManager redisCacheManager,JCacheCacheManager jcacheCacheManager) {MixCacheManager cacheManager = new MixCacheManager();cacheManager.setRedisCacheManager(redisCacheManager);cacheManager.setMemCacheManager(jcacheCacheManager);return cacheManager;}@Primary 是让 Spring Cache 知道,现在 org.springframework.cache.CacheManager 三个实现中,你该使用混合实现。
3.测试与使用
测试使用的服务代码:
@Service@Transactionalpublic class CacheService {@Cacheable("foo")public Foo findBook(String name) {System.out.print("cache....or not?\n");return new Foo("jdbc test1");}@Cacheable("redis-foo")public Foo findBookRedis(String name) {System.out.print("cache Redis....or not?\n");return new Foo("jdbc test1");}}
测试的使用代码:
public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();ctx.register(PersistenceJDBCConfig.class);ctx.register(CacheConfig.class);ctx.register(RedisConfig.class);ctx.refresh();CacheService cs = ctx.getBean(CacheService.class);cs.findBook("naan1");cs.findBook("naan1");cs.findBook("naan1");cs.findBook("new1");cs.findBookRedis("redis");cs.findBookRedis("redis");cs.findBookRedis("redis");cs.findBookRedis("redis-new");
输出结果:
cache....or not?cache....or not?cache Redis....or not?cache Redis....or not?
在 Redis 控制台上输入 keys * 看到建立的 key。
总结:
(1)Redis 与 内存缓存 混合使用非常简单实用。
(2)设计模式就是 Java 的魂。了解设计模式,就能看代码猜出有趣的实现。
- 使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署
- spring使用ehcache缓存
- spring+ehCache+redis多级缓存自定义实现
- Ehcache 2.0:后写式缓存和JTA支持
- Spring+ehcache+redis两级缓存--缓存实战篇(1)
- Spring+ehcache+redis两级缓存--缓存实战篇(1)
- Spring + ehcache + redis两级缓存--缓存实战篇(1)
- Spring Boot中的缓存支持(一)注解配置与EhCache使用
- Spring Boot中的缓存支持(一)注解配置与EhCache使用
- Spring Boot中的缓存支持(一)注解配置与EhCache使用
- Spring Boot中的缓存支持(一)注解配置与EhCache使用
- Spring Boot中的缓存支持(一)注解配置与EhCache使用
- Spring Boot中的缓存支持(一)注解配置与EhCache使用
- Spring+redis缓存使用
- 【EhCache】Java缓存框架使用EhCache结合Spring AOP
- Ehcache系列一:Ehcache 整合Spring 使用页面、对象缓存
- 【EhCache】Java缓存框架使用EhCache结合Spring AOP
- 【EhCache】Java缓存框架使用EhCache结合Spring AOP
- 程序员应当知道的小工具
- linux的七种文件类型
- 数据结构实验之图论八:欧拉回路
- 策略模式表单验证
- SOCKET REUSE_ADDR RESUE_PORT FW FROM stackoverflow
- 使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署
- gradle插件开发如何读取安卓根目录的preperties
- ffmpeg处理RTMP流媒体的命令大全
- 关于微信小程序你所需要掌握的技能
- Debian/Ubuntu的man手册不全的问题
- adb
- Part 76 - ValidateInput attribute in mvc 允许文本框输入html标签
- Unity->IOS遇到的坑 --记账本
- java小程序打包成.exe文件