8分钟阅读

在春天缓存用ehcache注释

con (Msceng)是一个快速学习者,对于表现代码的热情。他'在Android和Web服务开发中的一位专家,并喜欢AR。

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

  • 它可以通过简单地包括项目中的jar来设置。不需要额外的安装步骤。
  • 它在与应用程序相同的过程中运行,所以它快速。运行不需要额外的服务。

简而言之,Ehcache是​​任何纯java应用程序的伟大选择。

此外, ehcache spring注释 通过简单地将注释添加到可缓存的方法,允许将无缝集成到任何Spring应用程序中,而无需修改方法实现。

Ehcache是​​Spring Projects的一个很好的缓存解决方案。

虽然Ehcache提供了直接的,富有的API以编程方式操纵缓存,但本文主要关注 提升您的春季应用程序 以ehcache spring注释为一种不太侵入的方式。我们将在Tomcat中设置Spring MVC项目并部署RESTFUL Web服务。然后,EHCache将集成到Web服务。

项目概况

我们将在示例项目的上下文中展示Ehcache注释。我们会设置一个 春天 基于MVC的Web服务托管在a上 Tomcat 8. server.

我在Eclipse中开发了该项目,可以按照说明安装 这里 .

可以下载最新稳定版的Tomcat,Tomcat 8,可以下载 这里 .

当然,这些特定平台不是Ehcache的要求;您可以随时选择您喜欢的IDE和服务器。

ehcache弹簧注释jar可用 这里 。正如我们所看到的,每个版本都有两个罐子:一个带有依赖性和一个没有。具有依赖性的那个还包括Ehcache 2和Spring 3,这是ehcache注释所必需的。如果我们下载依赖关系并将其添加到我们的构建路径,它更容易设置。

Ehcache Spring注释也与弹簧4兼容,但必须单独配置。如果项目将在不久的将来支持EHCACH 3,则目前尚不清楚。对于那些使用或打算使用的人Ehcache 3,不建议本文中讨论的注释方法。

最后,我们将使用Maven来管理一切。 Maven通过大多数Eclipse安装预先包装,但也可以获得 这里 。 Spring MVC和EHCache Spring注释依赖关系可以相当容易地添加,如本文后面显示的。

项目设置

如果您之前从未设置过春季项目,则可能会发现 Stefan Varga在主题上的帖子 informative.

对于此演示,我们将使用Maven设置基本项目 原型 maven-archetype-webapp。整体文件结构将如下所示:

初始弹簧项目结构。

Create a directory, src/main/java, with three packages: com.toptal.blog, com.toptal.blog.cache, and com.toptal.blog.service. Our application source will go in the these packages, as described further down.

Let’s define a Tomcat servlet called “springrest” in web.xml:

<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>

Unless explicitly specified otherwise, a Spring MVC DispatcherServlet will look for an XML configuration file named {servlet-name}-servlet.xml in the directory WEB-INF. Let’s create a configuration file called springrest-servlet.xml. To enable Spring process controller methods annotated with @RequestMapping, let’s simply add <mvc:annotation-driven /> to this file. Also, let’s define the base package for Spring to automatically scan and register beans by adding <context:component-scan base-package="com.toptal.blog" />. The springrest-servlet.xml configuration becomes:

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

一个简单的RESTful Web服务

Now that our project is properly configured, let’s implement a simple “message service” API. In our base package, project.toptal.blog, we’ll add 春天 RestControllerWithEhCache.java, with one GET method to get a message by ID, and one POST method to set a message by ID:

@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;  
   }
}

We’ll define the MessageService class in com.toptal.blog.service. It will access messages stored in our System of Records (SOR). In a production app, the SOR would be something like a relational database. For simplicity, we will use a 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 );
   }
}

Now, if we export the project as a WAR and deploy it in Tomcat, we should be able to set a message, for example “test_message”, for ID=1, by creating an HTTP POST request at http://localhost:8080/EhCacheExample/message/set/1/test_message. We should then be able to get “test_message” back with an HTTP GET request at http://localhost:8080/EhCacheExample/message/1. I used 失眠 作为一个方便的休息客户,要做我的测试。

插入ehcache spring注释

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

Ehcache Spring注释使Ehcache轻松且无缝地部署在您的应用中。

第1步:更新依赖项以使用EHCache Spring注释

Add the ehcache spring注释 dependency in Maven’s pom.xml:

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

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

春天 has a built-in EhCache cache manager, org.springframework.cache.ehcache.EhCacheManagerFactoryBean. This is suitable for most caching situations, but I have found defining a custom cache manager to be useful because it allows me to control the cache either programmatically, or with annotations, using the same cache manager. This article focuses on annotations, but let’s go ahead and define a custom cache manager so we will be ready in case we need it. If you prefer to stick with the default cache manager , you can skip this step.

We’ll define the new class in 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
    * }
    * */
}

Enable it by updating springrest-servlet.xml as follows:

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

第3步:配置EHCache

Finally, create the EhCache configuration file ehcache.xml in the classpath. By default, Eclipse will include src/main/resources in the classpath, and we’ll place the file here. This file is required for EhCache to function properly. It defines the cache names and some properties of each cache, such as the 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步:测试缓存

Now, with everything set up and ready to go, using EhCache should be easy and happy work. We can simply add @Cacheable to the method or class we want to cache. For example, I added @Cacheable to the getMessage method in MessageService. It’s that easy!

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

To test that our cache is working, we can create a message for ID=1 by issuing an HTTP POST request at http://localhost:8080/EhCacheExample/message/set/1/newMessage, and then get the message for ID=1 multiple times, with GET requests to http://localhost:8080/EhCacheExample/message/1. As you can see in the console output below, the web service asks the SOR to get the message the first time we request the message, but not for the next two requests, returning the cached message instead. Because we defined the timeToLiveSeconds to be 10, the web service calls the SOR to get the message again after 10 seconds:

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......

刷新缓存

Now, we are enjoying the speed and convenience a cache gives us, and EhCache is nice enough to refresh by itself every 10 seconds. But what if we would like to have it refreshed immediately after our SOR is updated? EhCache Spring Annotation offers @TriggersRemove to remove specified keys from the cache when the annotated method is called. In our message service API, the cached message should be removed from the cache when setMessage is called. Thus, the next time a getMessage request comes in, the cache will fetch a fresh record from the 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 );
}

缓存管理器使用密钥生成器来生成缓存键。可以找到预定义的缓存密钥生成器列表 这里 . By default, @KeyGenerator consumes both the method name and the passed in parameters to generate the cache key. But since we want the setMessage method to generate the same key as getMessage and delete the cached value associated with that key, we must use only the message ID as the key and eliminate the method name for key generation. We therefore set the key generator’s includeMethod property to be false for both methods. Also, since setMessage has two arguments, we use EhCache’s @PartialCacheKey annotation on the id parameter to specify that it is the only one that should be used by the key generator. Finally, recall that we configured a dedicated cache, messageCache, for this resource type, so using only the ID for the key presents no danger of conflicts with other resources types.

现在,如果我们为具有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注释将Ehcache无缝集成到应用程序中。我们已经展示了Ehcache Spring注释既易于安装(通过添加其Maven依赖关系)和优雅使用(通过向方法添加注释)。

进一步阅读

可以找到ehcache文件 这里 和Ehcache Spring注释文档是 这里 .

此外,请查看本文中描述的示例项目 GitHub. .