在 Spring 中使用 @EhCache 注解作为缓存

news2024/10/17 12:34:07

文章目录

    • 项目概况
    • 项目设置
    • 一个简单的 RESTful Web 服务
      • Spring 整合 EhCache
      • 第 1 步:更新依赖项以使用 EhCache Spring 注解
      • 第 2 步:设置自定义缓存管理器
      • 第 3 步:配置 EhCache
      • 第 4 步:测试缓存
    • 刷新缓存
    • 总结
    • 推荐阅读文章

EhCache 是一种广泛使用的纯 Java 缓存,可以轻松地与大多数流行的 Java 框架集成,例如 SpringHibernate

它通常被认为是 Java 应用程序最方便的选择,因为它可以轻松集成到项目中。EhCache Spring Annotations 允许无缝集成到任何 Spring 应用程序中,只需向可缓存方法添加注释即可,而无需修改方法实现。本文重点介绍如何使用 EhCache Spring Annotations 提升您的 Spring 应用程序。


EhCache 是一种广泛使用的纯 Java 缓存,可以轻松地与大多数流行的 Java 框架集成,例如 SpringHibernate。它通常被认为是 Java 应用程序最方便的选择,因为它可以轻松集成到项目中。特别:

  • 只需将 JAR 包含在项目中即可。无需额外的安装步骤。
  • 与应用程序在相同的进程中运行,因此速度很快。无需其他服务即可运行。

简而言之,EhCache 是任何纯 Java 应用程序的绝佳选择。

在这里插入图片描述

虽然 EhCache 提供了简单、丰富的 API 来以编程方式操作缓存,但本文主要关注使用 EhCache Spring Annotations 以侵入性较小的方式提升 Spring 应用程序。我们将设置一个 Spring MVC 项目,并在 Tomcat 中部署一个 RESTful Web 服务。然后,EhCache 将集成到 Web 服务中。

项目概况

我们将在示例项目的上下文中演示 EhCache Annotations。我们将设置一个托管在 Tomcat 8 服务器上的基于 Spring MVC 的 Web 服务。

我在 Eclipse 中开发了该项目,可以按照Eclipse下载的说明进行安装。

当然,这些特定平台不是 EhCache 的要求;您始终可以选择自己喜欢的 IDE 和服务器。

EhCache Spring Annotations JAR 可Spring-EhCache下载获得。正如我们所看到的,每个版本都有两个 JAR:一个有依赖项,一个没有依赖项。具有依赖项的还包括 EhCache 2 和 Spring 3,它们是 EhCache 注解工作所必需的。如果我们下载带有依赖项的那个并将其添加到我们的构建路径中,则设置起来会更容易。

EhCache Spring Annotations 也与 Spring 4 兼容,但必须单独配置。目前尚不清楚该项目是否会在不久的将来支持 EhCache 3。对于正在使用或打算使用 EhCache 3 的用户,不建议使用本文中讨论的注释方法。

最后,我们将使用 Maven 来管理所有内容。Maven 预装在大多数 Eclipse 安装中,但也可以Maven官网获取。Spring MVCEhCache Spring Annotations 依赖项可以相当容易地添加,如本文后面所示。

项目设置

如果您以前从未设置过 Spring 项目,您可能还会发现 SpringMVC搭建过程提供了丰富的信息。

在本演示中,我们将使用 Maven官网 maven-archetype-webapp 设置一个基本项目。整体文件结构将如下所示:

在这里插入图片描述

创建一个目录 src/main/java,其中包含三个包:com.toptal.blogcom.toptal.blog.cachecom.toptal.blog.service。我们的应用程序源将进入这些包中,如下所述。

让我们在 web.xml 中定义一个名为 “springrest” 的 Tomcat servlet:

<web-app>
   ...
   <servlet>
      <servlet-name>springrest</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>springrest</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>

除非另有明确说明,否则 Spring MVC DispatcherServlet 将在目录 WEB-INF 中查找名为 {servlet-name}-servlet.xml 的 XML 配置文件。让我们创建一个名为 springrest-servlet.xml 的配置文件。要启用带有 @RequestMapping 注释的 Spring 进程控制器方法,我们只需将 <mvc:annotation-driven /> 添加到此文件中即可。此外,让我们定义 Spring 的基本包,以便通过添加 <context:component-scan base-package="com.toptal.blog" /> .springrest-servlet.xml 配置将变为:

<beans ... >
   <mvc:annotation-driven />
   <context:component-scan base-package="com.toptal.blog" />
</beans>

一个简单的 RESTful Web 服务

现在,我们的项目已正确配置,让我们实现一个简单的 “消息服务” API。在我们的基础包 project.toptal.blog 中,我们将添加 SpringRestControllerWithEhCache.java ,其中包含一个按 ID 获取消息的 GET 方法,以及一个按 ID 设置消息的 POST 方法:

@RestController  
@RequestMapping( "/" )
public class SpringRestControllerWithEhCache {
   @Autowired
   MessageService messageService;
   
   @RequestMapping( value = "/message/{id}", method = RequestMethod.GET )
   public String getMessage( @PathVariable Integer id ) {
      String message = messageService.getMessage( id );
      System.out.println( "get message ["+message+"] at "+new Date() );
      return message;
   }
   
   @RequestMapping( value = "/message/set/{id}/{message}", method = RequestMethod.POST )
   public String setMessage( @PathVariable Integer id, @PathVariable String message ) { 
      System.out.println( "set message ["+message+"] at "+new Date() );
      messageService.setMessage( id, message );
      return message;  
   }
}

我们将在 com.toptal.blog.service 中定义 MessageService 类。它将访问存储在我们的记录系统 (SOR) 中的消息。在生产应用程序中,SOR 类似于关系数据库。为简单起见,我们将使用 HashMap

@Service
public class MessageService {
   private ConcurrentHashMap<Integer, String> messages
   = new ConcurrentHashMap<Integer, String>();
   
   public String getMessage( Integer id ) {
      System.out.println( "Getting data from SOR......" );
      return messages.get( id );
   }

   public void setMessage( Integer id, String message ){
      messages.put( id, message );
   }
}

现在,如果我们将项目导出为 WAR 并将其部署到 Tomcat 中,我们应该能够通过在 中创建 HTTP POST 请求来为 ID=1 设置一条消息,例如“test_message http://localhost:8080/EhCacheExample/message/set/1/test_message ”。然后,我们应该能够通过 HTTP GET 请求的 “test_message” 返回 http://localhost:8080/EhCacheExample/message/1 。我使用 Insomnia 作为方便的 REST 客户端来进行测试。

Spring 整合 EhCache

现在让我们让 EhCache 为我们工作。只需几个快速步骤即可配置我们的项目以正确运行 EhCache。

在这里插入图片描述

第 1 步:更新依赖项以使用 EhCache Spring 注解

在 Maven 的 pom.xml中添加 EhCache Spring Annotations 依赖项:

<!-- ehcache -->
<dependency>
   <groupId>com.googlecode.ehcache-spring-annotations</groupId>
   <artifactId>ehcache-spring-annotations</artifactId>
   <version>1.2.0</version>
</dependency>

第 2 步:设置自定义缓存管理器

Spring 有一个内置的 EhCache 缓存管理器 org.springframework.cache.ehcache.EhCacheManagerFactoryBean 。这适用于大多数缓存情况,但我发现定义自定义缓存管理器非常有用,因为它允许我使用相同的缓存管理器以编程方式或通过注释控制缓存。本文重点介绍 annotations,但让我们继续定义一个自定义缓存管理器,以便在需要时做好准备。如果您更喜欢坚持使用 默认缓存管理器 ,您可以跳过此步骤。

我们将在 : com.toptal.blog.cache.CustomCacheManager

public class CustomCacheManager extends net.sf.ehcache.CacheManager{

   public CustomCacheManager(){
      super();
   }

   /* Add your own cache methods here.
    * 
    * public void myCustomCacheMethod(){
    *    // your code here
    * }
    * */
}

通过更新springrest-servlet.xml来启用它,如下所示:

   ...
   <ehcache:annotation-driven cache-manager="customCacheManager" />
   <bean id="customCacheManager"
         class="com.toptal.blog.cache.CustomCacheManager"
         scope="singleton"></bean>
   ...

第 3 步:配置 EhCache

最后,在 Classpath 中创建 EhCache 配置文件ehcache.xml。默认情况下,Eclipse 将在 classpath 中包含 src/main/resources,我们将文件放在这里。此文件是 EhCache 正常运行所必需的。它定义缓存名称和每个缓存的一些属性,例如 timeToLiveSeconds

<ehcache xmlms:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd">
   <diskStore path="cache" />
   <cache
      name="messageCache"
      maxElementsInMemory="10000"
      eternal="false"
      timeToIdleSeconds="0"
      timeToLiveSeconds="10"
      overflowToDisk="false"
      memoryStoreEvictionPolicy="LFU" />      
</ehcache>

第 4 步:测试缓存

现在,一切都设置好了,使用 EhCache 应该是一件简单而愉快的工作。我们可以简单地将 @Cacheable 添加到我们想要缓存的方法或类中。例如,我将 @Cacheable 添加到 MessageService 中的 getMessage 方法中。就是这么简单!

@Cacheable( cacheName = "messageCache" )
public String getMessage( Integer id ) {
   System.out.println( "Getting data from SOR......" );
   return messages.get( id );
}

要测试我们的缓存是否正常工作,我们可以通过在 处 http://localhost:8080/EhCacheExample/message/set/1/newMessage 发出 HTTP POST 请求来创建一条 ID=1 的消息,然后多次获取 ID=1 的消息,并向 . http://localhost:8080/EhCacheExample/message/1 如下面的控制台输出所示,Web 服务在我们第一次请求消息时要求 SOR 获取消息,但在接下来的两个请求中不请求,而是返回缓存的消息。由于我们将 timeToLiveSeconds 定义为 10,因此 Web 服务会在 10 秒后调用 SOR 再次获取消息:

set message [newMessage] at Sun Dec 06 23:55:39 MST 2015
get message [newMessage] at Sun Dec 06 23:55:42 MST 2015
Getting data from SOR......
get message [newMessage] at Sun Dec 06 23:55:47 MST 2015
get message [newMessage] at Sun Dec 06 23:55:49 MST 2015
get message [newMessage] at Sun Dec 06 23:55:54 MST 2015
Getting data from SOR......

刷新缓存

现在,我们正在享受缓存给我们带来的速度和便利,而且 EhCache 足够好,每 10 秒自行刷新一次。但是,如果我们想在 SOR 更新后立即刷新它,该怎么办?EhCache Spring Annotation 提供了@TriggersRemove,以便在调用带注释的方法时从缓存中删除指定的键。在我们的消息服务 API 中,当调用 setMessage 时,应该从缓存中删除缓存的消息。因此,下次收到 getMessage 请求时,缓存将从 SOR 中获取新记录:

@Cacheable(
   cacheName = "messageCache",
   keyGenerator = @KeyGenerator (                             // method name is not included in cache key to work with @TriggersRemove
                     name = "HashCodeCacheKeyGenerator",
                     properties = @Property( name="includeMethod", value="false" )))  
public String getMessage( Integer id ) {
   System.out.println( "Getting data from SOR......" );
   return messages.get( id );
}

@TriggersRemove(
   cacheName = "messageCache",
   keyGenerator = @KeyGenerator (
                     name = "HashCodeCacheKeyGenerator",
                     properties = @Property( name="includeMethod", value="false" )))
public void setMessage( @PartialCacheKey Integer id, String message ) {
   messages.put( id, message );
}

缓存管理器使用密钥生成器来生成缓存密钥。可在此处找到预定义的缓存密钥生成器列表。默认情况下,@KeyGenerator 使用方法名称和传入的参数来生成缓存键。但是,由于我们希望 setMessage 方法生成与 getMessage 相同的 key,并删除与该 key 关联的缓存值,因此我们必须仅使用消息 ID 作为 key,并消除生成 key 的方法名称。因此,我们将这两个方法的密钥生成器的 includeMethod 属性设置为 false。此外,由于 setMessage 有两个参数,我们在 id 参数上使用 EhCache 的 @PartialCacheKey 注解来指定它是密钥生成器唯一应该使用的参数。最后,回想一下,我们为此资源类型配置了专用缓存 messageCache,因此仅使用键的 ID 不会与其他资源类型发生冲突。

现在,如果我们对 ID=1 的消息执行多个 HTTP 请求,如下所示:

HTTP POST:  http://localhost:8080/EhCacheExample/message/set/1/newMessage1
HTTP GET:http://localhost:8080/EhCacheExample/message/1
HTTP POST: http://localhost:8080/EhCacheExample/message/set/1/newMessage2
HTTP GET:http://localhost:8080/EhCacheExample/message/1

控制台将显示:

set message [newMessage1] at Tue Dec 08 17:53:44 MST 2015
get message [newMessage1] at Tue Dec 08 17:53:47 MST 2015
Getting data from SOR......
set message [newMessage2] at Tue Dec 08 17:53:50 MST 2015
get message [newMessage2] at Tue Dec 08 17:53:53 MST 2015
Getting data from SOR......

总结

最终的项目结构如下所示:

在这里插入图片描述

在此示例中,我们首先创建了一个简单的 Spring MVC RESTful Web 应用程序。无需修改现有应用程序代码的哪怕一行,我们就可以使用 EhCache Spring Annotations 将 EhCache 无缝集成到应用程序中。我们已经证明 EhCache Spring Annotations 既易于安装(通过添加其 Maven 依赖项)又易于使用(通过向方法添加注释)。

推荐阅读文章

1、使用 Spring 框架构建 MVC 应用程序:初学者教程
2、有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
3、如何理解应用 Java 多线程与并发编程?
4、Java Spring 中常用的 @PostConstruct 注解使用总结
5、线程 vs 虚拟线程:深入理解及区别
6、深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
7、10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
8、“打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
9、Java 中消除 If-else 技巧总结
10、线程池的核心参数配置(仅供参考)
11【人工智能】聊聊Transformer,深度学习的一股清流(13)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2215972.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AD报错failed to add class member\net

什么原因导致的我到现在还没弄懂&#xff0c;总之解决方法是在PCB端删除所有现有的并且可删除的nets与components。下次问题复现了再补充截图&#xff08;不想再遇到了球球了这种玄学问题&#xff09;。 网络截图&#xff1a; 解决步骤&#xff1a;设计->类 把可删除的网络…

【论文翻译】HTVGNN:一种用于交通流量预测的混合时间变化图神经网络

题目A Novel Hybrid Time-Varying Graph Neural Network For Traffic Flow Forecasting论文链接https://arxiv.org/pdf/2401.10155v4关键词交通流预测&#xff0c;图神经网络&#xff0c;Transformer&#xff0c;多头自注意力 摘要 实时且精确的交通流量预测对于智能交通系统的…

OpenAI的Swarm是一个实验性质的多智能体编排框架

先上文档&#xff0c;然后解释&#xff0c;然后是代码 OpenAI的Swarm是一个实验性质的多智能体编排框架&#xff0c;旨在简化多智能体系统的构建、编排和部署。以下是对Swarm的详细介绍&#xff1a; 一、核心概念和特点 智能体&#xff08;Agent&#xff09;&#xff1a; Swar…

目标检测——Libra R-CNN算法解读

论文&#xff1a;Libra R-CNN: Towards Balanced Learning for Object Detection (2019.4.4) 作者&#xff1a;Jiangmiao Pang, Kai Chen, Jianping Shi, Huajun Feng, Wanli Ouyang, Dahua Lin 链接&#xff1a;https://arxiv.org/abs/1904.02701 代码&#xff1a;https://git…

计算机毕业设计 基于Python的汽车销售管理系统的设计与实现 Python毕业设计 Python毕业设计选题【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Android Settings 设置项修改

Settings 设置项 在 Android 系统上,WRITE_SETTINGS 这个权限从 API 1 就已经开始有了。 通过在 app 中设置权限 android.permission.WRITE_SETTINGS 允许 app 读/写 系统设置。 在官方文档的描述中,还有一段注意事项: Note: If the app targets API level 23 or higher,…

live2d 实时虚拟数字人形象页面显示,对接大模型

live2dSpeek 测试不用gpu可以正常运行 https://github.com/lyz1810/live2dSpeek 运行的话还需要额外下载https://github.com/lyz1810/edge-tts支持语音 ## 运行live2dSpeek >npm install -g http-server >http-server . ## 运行edge-tts python edge-tts.py

前端布局与响应式设计综合指南(二)

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Css篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Css篇专栏内容:前端布局与响应式设计综合指南(二) 目录 23、行内元素和块级元素&#xff1f;img算什么&…

【全网最全】AI产品经理面试高频100题答案解析

详细的目录如下&#xff0c;需要的小伙伴可以详细看一下~ 第一章&#xff1a;机器学习和深度学习的关系 第二章&#xff1a;机器学习7大经典算法 算法一&#xff1a;K近邻算法【分类算法】 1.1 KNN 算法的实现原理 1.2 KNN应用场景举例&#xff1a;预测候选人能不能拿到 O…

DVWA | Files Upload(文件上传)通关笔记

概念 **文件上传漏洞**是网络安全中常见的漏洞之一&#xff0c;攻击者可以利用该漏洞上传恶意文件&#xff0c;进而在服务器上执行恶意代码、绕过权限验证或获取敏感数据。文件上传漏洞主要发生在允许用户上传文件的Web应用程序中&#xff0c;比如图像、文档上传功能等。 ###…

3-3 AUTOSAR RTE 对SR Port的实现

返回总目录->返回总目录<- 目录 一、前言 二、显式访问 三、隐式访问 四、队列调用(Queued) 五、无效数据元素 一、前言 RTE作为SWC和BSW之间的通信机构,支持Sender-Receiver方式实现ECU内及ECU间的通信。 对于Sender-Receiver Port支持三种模式: 显式访问:若…

JavaScript全面指南(二)

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Javascript篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript全面指南(二) 目录 21、说明如何使用JavaScript提交表单&#xff1f; 2…

Java_EE(反射技术)

反射机制介绍: 什么是反射Java反射机制是Java语言一个很重要的特性&#xff0c;它使得Java具有了“动态性”。在Java程序运行时&#xff0c;对于任意的一个类&#xff0c;我们能不能知道这个类有哪些属性和方法呢&#xff1f;对于任意的一个对象&#xff0c;我们又能不能调用它…

【NTN 卫星通信】卫星通信的专利

1 概述 好久没有看书了&#xff0c;最近买了本讲低轨卫星专利的书&#xff0c;也可以说是一个分析报告。推荐给喜欢的朋友。 2 书籍截图 图1 封面 图2 波音低轨卫星专利演进 图3 低轨卫星关键技术专利发展阶段 图4 第一页 3 参考文献 产业专利分析报告–低轨卫星通信技术

信息收集-DNS收集

使用各种公开资源尽可能获取更多的的信息&#xff0c;收集的范围包括DNS服务器、路由关系、whois数据库、电子邮件、电话号码、个人信息和公司信息等 以www.testfire.net为例 DNS收集 关注域名注册者、联系方式、邮件信息、子域名等信息 whois查询 kali的集成工具&#xf…

Gin框架操作指南04:GET绑定

官方文档地址&#xff08;中文&#xff09;&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;没用过Gin的读者强烈建议先阅读第一节&#xff1a;Gin操作指南&#xff1a;开山篇。 本节演示GET绑定&#xff0c;包括绑定表单数据至自定义结构体&#xff0c;绑定查询…

运行Springboot + Vue 项目

前言&#xff1a;很多小白拿到java SpringBoot Vue前后端分离的项目却不知道怎么运行起来&#xff0c;这里博主就带领小白们一起将项目运行起来吧&#xff01; 一、环境准备 java后端软件&#xff1a;Idea、jdk、mysql、Navicat&#xff08;可用其他代替&#xff0c;如dbea…

获取vue实例

需要注意的是&#xff0c;无论通过哪种方式获取元素&#xff0c;如果元素为 vue 组件&#xff0c;则需要在子组件中使用 defineExpose 进行暴露。 在父组件中&#xff0c;我们静态绑定 childRef&#xff1a; 在子组件中&#xff0c;我们需要通过defineExpose函数&#xff0c;手…

05 奶牛与书架

题目&#xff1a; 贪心&#xff1a; #include<bits/stdc.h> using namespace std; #define M 100005 int a[M];bool cmp(int n1,int n2) {return n1>n2; }int main() {int N,B;cin>>N>>B;for(int i1;i<N;i){cin>>a[i];}sort(a1,aN1,cmp);int su…

昆虫分类与检测系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]

昆虫分类与检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Visio…