• 概述
  • 工程结构
  • 源码

概述

Spring Cache抽象-之缓存注解这篇博文中我们介绍了SpringCache抽象注解的使用方式

既然这是一个抽象,我们需要一个具体的缓存存储实现。比价流行的有:基于JDK java.util.concurrent.ConcurrentMap的缓存,EhCache,Gemfire缓存,Caffeine,Guava缓存和兼容JSR-107的缓存等等。这里我们使用Ehcache来实现这个缓存。

同时,我们使用EhCacheManagerFactoryBean的configLocation属性指定Ehcache的设置。如果未明确指定,则默认为ehcache.xml。


工程结构

以及EhCache的配置文件:

pom.xml 关键的依赖

<properties>            <springframework.version>4.3.9.RELEASE</springframework.version><ehcache.version>2.10.4</ehcache.version>
</properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${springframework.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${springframework.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${springframework.version}</version></dependency><!-- EHCache --><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>${ehcache.version}</version></dependency><!-- SLF4J/Logback --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.7</version></dependency>     </dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.2</version><configuration><source>1.7</source><target>1.7</target></configuration></plugin></plugins></build>
</project>

ehcache.xml

<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="products" maxEntriesLocalHeap="100"maxEntriesLocalDisk="1000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600"memoryStoreEvictionPolicy="LFU" transactionalMode="off"><persistence strategy="localTempSwap" /></cache>
</ehcache>
  • 我们设置一个名为’products’的缓存。

  • 最多100个products将保存在内存[堆叠]存储中,

  • 最多1000个products将被保留在DiskStore中

  • 指定的路径为“java.io.tmpdir”,它指的是默认的临时文件路径。

  • 如果product闲置超过5分钟,寿命超过10分钟,products缓存将会过期


实体类

package com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain;import java.io.Serializable;public class Product implements Serializable {private static final long serialVersionUID = 123L;private String name;private double price;/*** * * @Title:Product* * @Description:构造函数* * @param name* @param price*/public Product(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}}

Product接口

package com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.service;import com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product;public interface ProductService {Product getByName(String name);Product updateProduct(Product product);void refreshAllProducts();
}

接口实现类 及缓存配置

package com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.service;import java.util.ArrayList;
import java.util.List;import org.apache.log4j.Logger;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product;/*** * * @ClassName: ProductServiceImpl* * @Description:@Service标注的服务层* * @author: Mr.Yang* * @date: 2017年10月3日 下午5:22:30*/@Service("productService")
public class ProductServiceImpl implements ProductService {private static final Logger logger = Logger.getLogger(ProductServiceImpl.class);private static List<Product> products;static {products = getDummyProducts();}@Cacheable(cacheNames = "products", key = "#name", condition = "#name != 'HTC'", unless = "#result==null")@Overridepublic Product getByName(String name) {logger.info("<!----------Entering getByName()--------------------->");for (Product product : products) {if (product.getName().equalsIgnoreCase(name)) {return product;}}return null;}@CachePut(cacheNames = "products", key = "#product.name", unless = "#result==null")@Overridepublic Product updateProduct(Product product) {logger.info("<!----------Entering updateProduct()--------------------->");for (Product p : products) {if (p.getName().equalsIgnoreCase(product.getName())) {p.setPrice(product.getPrice());return p;}}return null;}@CacheEvict(cacheNames = "products", allEntries = true)@Overridepublic void refreshAllProducts() {}private static List<Product> getDummyProducts() {products = new ArrayList<Product>();products.add(new Product("IPhone", 500));products.add(new Product("Samsung", 600));products.add(new Product("HTC", 800));return products;}}

关键配置类 ,以及加载enhance

package com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.configuration;import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;@EnableCaching
@Configuration
@ComponentScan(basePackages = "com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache")
public class AppConfig {@Beanpublic CacheManager cacheManager() {return new EhCacheCacheManager(ehCacheCacheManager().getObject());}@Beanpublic EhCacheManagerFactoryBean ehCacheCacheManager() {EhCacheManagerFactoryBean factory = new EhCacheManagerFactoryBean();factory.setConfigLocation(new ClassPathResource("ehcache/ehcache.xml"));factory.setShared(true);return factory;}
}

单元测试

package com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache;import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;import com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.configuration.AppConfig;
import com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product;
import com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.service.ProductService;public class SpringCacheWithEhCacheTest {private static final Logger logger = Logger.getLogger(SpringCacheWithEhCacheTest.class);AbstractApplicationContext context = null;@Beforepublic void initContext() {context = new AnnotationConfigApplicationContext(AppConfig.class);}@Testpublic void test() {ProductService service = (ProductService) context.getBean("productService");logger.info("IPhone ->" + service.getByName("IPhone"));logger.info("IPhone ->" + service.getByName("IPhone"));logger.info("IPhone ->" + service.getByName("IPhone"));logger.info("HTC ->" + service.getByName("HTC"));logger.info("HTC ->" + service.getByName("HTC"));logger.info("HTC ->" + service.getByName("HTC"));Product product = new Product("IPhone", 550);service.updateProduct(product);logger.info("IPhone ->" + service.getByName("IPhone"));logger.info("IPhone ->" + service.getByName("IPhone"));logger.info("IPhone ->" + service.getByName("IPhone"));logger.info("Refreshing all products");service.refreshAllProducts();logger.info("IPhone [after refresh]->" + service.getByName("IPhone"));logger.info("IPhone [after refresh]->" + service.getByName("IPhone"));logger.info("IPhone [after refresh]->" + service.getByName("IPhone"));}@Afterpublic void releaseContext() {((AbstractApplicationContext) context).close();}}

输出结果分析

2017-10-03 20:54:55,026  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7bd1a567: startup date [Tue Oct 03 20:54:55 BOT 2017]; root of context hierarchy
2017-10-03 20:54:55,858  INFO [main] (EhCacheManagerFactoryBean.java:130) - Initializing EhCache CacheManager
2017-10-03 20:54:56,711  INFO [main] (ProductServiceImpl.java:40) - <!----------Entering getByName()--------------------->
2017-10-03 20:54:56,715  INFO [main] (SpringCacheWithEhCacheTest.java:32) - IPhone ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,716  INFO [main] (SpringCacheWithEhCacheTest.java:33) - IPhone ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,716  INFO [main] (SpringCacheWithEhCacheTest.java:34) - IPhone ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,717  INFO [main] (ProductServiceImpl.java:40) - <!----------Entering getByName()--------------------->
2017-10-03 20:54:56,717  INFO [main] (SpringCacheWithEhCacheTest.java:36) - HTC ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@68c06cac
2017-10-03 20:54:56,717  INFO [main] (ProductServiceImpl.java:40) - <!----------Entering getByName()--------------------->
2017-10-03 20:54:56,717  INFO [main] (SpringCacheWithEhCacheTest.java:37) - HTC ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@68c06cac
2017-10-03 20:54:56,718  INFO [main] (ProductServiceImpl.java:40) - <!----------Entering getByName()--------------------->
2017-10-03 20:54:56,718  INFO [main] (SpringCacheWithEhCacheTest.java:38) - HTC ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@68c06cac
2017-10-03 20:54:56,724  INFO [main] (ProductServiceImpl.java:52) - <!----------Entering updateProduct()--------------------->
2017-10-03 20:54:56,734  INFO [main] (SpringCacheWithEhCacheTest.java:43) - IPhone ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,735  INFO [main] (SpringCacheWithEhCacheTest.java:44) - IPhone ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,735  INFO [main] (SpringCacheWithEhCacheTest.java:45) - IPhone ->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,736  INFO [main] (SpringCacheWithEhCacheTest.java:47) - Refreshing all products
2017-10-03 20:54:56,741  INFO [main] (ProductServiceImpl.java:40) - <!----------Entering getByName()--------------------->
2017-10-03 20:54:56,741  INFO [main] (SpringCacheWithEhCacheTest.java:50) - IPhone [after refresh]->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,742  INFO [main] (SpringCacheWithEhCacheTest.java:51) - IPhone [after refresh]->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,742  INFO [main] (SpringCacheWithEhCacheTest.java:52) - IPhone [after refresh]->com.xgj.cache.springCacheAnno.CompleteDemoWithEhCache.domain.Product@1a8f392
2017-10-03 20:54:56,742  INFO [main] (AbstractApplicationContext.java:984) - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7bd1a567: startup date [Tue Oct 03 20:54:55 BOT 2017]; root of context hierarchy
2017-10-03 20:54:56,744  INFO [main] (EhCacheManagerFactoryBean.java:187) - Shutting down EhCache CacheManager

查看ProductServiceImpl中的 getName方法中的@Cacheable注解可知

@Cacheable(cacheNames = "products", key = "#name", condition = "#name != 'HTC'", unless = "#result==null")

HTC不缓存, 结果为空不缓存。

查看输出,第一次查询 IPhone Samsung HTC ,分别从慢速设备中加载, 当第二次第三次查询IPhone Samsung ,可以看到 并没有输出

logger.info("<!----------Entering getByName()--------------------->");

可知,其从缓存中加载。

因为不缓存HTC,所以每次查询HTC都从会执行方法,从慢速设备中查询。

当调用service.updateProduct(product); 我们使用的@CachePut注解更新缓存, 然后service.getByName(“IPhone”),缓存没有被清空,所以依然是从缓存中获取。

随后,service.refreshAllProducts(); 将缓存全部清掉,再此查询service.getByName(“IPhone”),然后再此查询可以看到输出了<!----------Entering getByName()--------------------->,紧接着的第二次第三次,是从缓存中获取的数据.


源码

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

Spring Cache抽象-使用Java类注解的方式整合EhCache相关推荐

  1. Spring Cache抽象-基于XML的配置声明(基于EhCache的配置)

    概述 完整示例 pomxml增加依赖 数据库表数据Oracle 实体类 服务层 ehcache的配置文件 Spring-EhCache配置文件 单元测试 日志输出 日志分析 示例源码 概述 首先请阅读 ...

  2. mybatis java类注解式_Spring整合Mybatis注解方式

    Spring整合Mybatis(注解方式) 环境准备 jar包: Spring所需依赖:spring-context.spring-aspects.aspectjrt.aspectjweaver.sp ...

  3. Spring Cache抽象-缓存注解

    文章目录 概述 Spring缓存的基本原理 @Cacheable :主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 键生成器 带条件的缓存 @Cacheable 注解参数说明 示例-缓存管理 ...

  4. Spring Cache抽象-基于XML的配置声明(基于ConcurrentMap的配置)

    概述 示例 项目结构 数据库表数据Oracle 实体类 服务层 Spring配置文件 单元测试 日志输出 日志分析 示例源码 概述 Spring Cache基于注解的配置 如果不想使用注解或者由于其他 ...

  5. Spring Cache抽象-使用SpEL表达式

    概述 SpEl表达式 概述 在Spring Cache注解属性中(比如key,condition和unless),Spring的缓存抽象使用了SpEl表达式,从而提供了属性值的动态生成及足够的灵活性. ...

  6. mybatis java类注解式_mybatis注解详解

    http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html mybatis的原身是ibatis,现在已经脱离了apache基金会,新官网是http://ww ...

  7. Spring Cache抽象-缓存管理器

    概述 SimpleCacheManager NoOpCacheManager ConcurrentMapCacheManager CompositeCacheManager 概述 CacheManag ...

  8. java spring获取bean_普通Java类获取Spring的Bean的方法

    普通Java类获取Spring的Bean的方法 在SSH集成的前提下.某些情况我们需要在Action以外的类中来获得Spring所管理的Service对象. 之前我在网上找了好几好久都没有找到合适的方 ...

  9. java类加入到spring容器_普通java类加入spring容器的四种方式

    今天在自己开发的工具类中使用了spring注入的方式调用了其他类,但是发生的报错,在整理了后今天小结一下. 首先简单介绍下spring容器,spring容器是整个spring框架的核心,通常我们说的s ...

最新文章

  1. 【UIKit】表格自定义单元格(UITableViewCll)
  2. Java JDBC批处理插入数据操作
  3. 深度学习(神经网络) —— BP神经网络原理推导及python实现
  4. css搜索框变圆脸角,CSS浮动布局
  5. javascript的性能优化tips
  6. McAfee:较之中国美国黑客才最令人害怕
  7. 11.SolrJ索引操作
  8. Ranger-Yarn插件安装
  9. PHP_递归实现无限级分类
  10. python filter map区别_Python:map()、reduce()、filter()的区别
  11. [2019徐州网络赛J题]Random Access Iterator
  12. matlab练习程序(倾斜校正,透视变换)
  13. 关于四川2019ACM省赛热身赛B题的一个证明
  14. Web安全防御从WAF到应用网关
  15. git 远程仓库 remote 使用总结
  16. win10系统在Vs2012工具菜单中添加ildasm.exe工具的操作办法
  17. PHP2018人资面试题
  18. 突破Edge浏览器的签名验证机制
  19. Vulnhub靶机:GEMINI INC_ 1
  20. 向量叉乘判断顺时针还是逆时针

热门文章

  1. 如何在DataFrame 中优雅的增加一行,一列
  2. php 编辑器中使用短代码,php-在WooCommerce短代码输出中更改标记
  3. 基本符号有_MapGIS 10中各种比例尺、符号尺寸计算说明(三)——随图缩放的符号计算...
  4. 109. Leetcode 309. 最佳买卖股票时机含冷冻期 (动态规划-股票交易)
  5. Leetcode 122.买卖股票的最佳时机 II (每日一题 20210618)
  6. BERT论文阅读(一): Pre-training of Deep Bidirectional Transformers for Language Understanding
  7. 论文笔记:Integrating Classification and Association Rule Mining (即,CBA算法介绍)
  8. 手把手干货教学Matlab载波调制
  9. python取三位小数_python保留小数位的三种实现方法
  10. 机器学习第3天:多元线性回归