Spring Boot Ehcache Example – Spring Boot Ehcache实例

最后修改: 2019年 1月 19日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Let’s look at an example of using Ehcache with Spring Boot. We’ll use Ehcache version 3 as this provides an implementation of a JSR-107 cache manager.

让我们看看在Spring Boot中使用Ehcache的一个例子。我们将使用Ehcache第3版,因为它提供了一个JSR-107缓存管理器的实现。

The example is a simple REST service that produces the square of a number.

这个例子是一个简单的REST服务,产生一个数字的平方。

2. Dependencies

2.依赖性

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>2.7.2</version></dependency>
<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
    <version>1.1.1</version>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.8.1</version>
</dependency>     

3. Example

3.例子

Let’s create a simple REST controller which calls a service to square a number and returns the result as a JSON string:

让我们创建一个简单的REST控制器,调用一个服务为一个数字取整,并将结果以JSON字符串的形式返回。

@RestController
@RequestMapping("/number", MediaType.APPLICATION_JSON_UTF8_VALUE)
public class NumberController {

    // ...

    @Autowired
    private NumberService numberService;

    @GetMapping(path = "/square/{number}")
    public String getSquare(@PathVariable Long number) {
        log.info("call numberService to square {}", number);
        return String.format("{\"square\": %s}", numberService.square(number));
    }
}

Now let’s create the service.

现在我们来创建服务。

We annotate the method with @Cacheable so that Spring will handle the caching. As a result of this annotation, Spring will create a proxy of the NumberService to intercept calls to the square method and call Ehcache.

我们用@Cacheable来注解该方法,这样Spring将处理缓存。由于这个注解,Spring将创建一个NumberService的代理来拦截对square方法的调用并调用Ehcache。

We need to provide the name of the cache to use and optionally the key. We can also add a condition to restrict what is cached:

我们需要提供要使用的缓存的名称和可选的密钥。我们还可以添加一个条件来限制缓存的内容。

@Service
public class NumberService {

    // ...
    @Cacheable(
      value = "squareCache", 
      key = "#number", 
      condition = "#number>10")
    public BigDecimal square(Long number) {
        BigDecimal square = BigDecimal.valueOf(number)
          .multiply(BigDecimal.valueOf(number));
        log.info("square of {} is {}", number, square);
        return square;
    }
}

Finally, let’s create our main Spring Boot application:

最后,让我们创建我们的主Spring Boot应用程序。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. Cache Configuration

4.缓存配置

We need to add Spring’s @EnableCaching annotation to a Spring bean so that Spring’s annotation-driven cache management is enabled.

我们需要向Spring Bean添加Spring的@EnableCaching注解,以便启用Spring的注解驱动的缓存管理。

Let’s create a CacheConfig class:

让我们创建一个CacheConfig类。

@Configuration
@EnableCaching
public class CacheConfig {
}

Spring’s auto-configuration finds Ehcache’s implementation of JSR-107. However, no caches are created by default.

Spring的自动配置找到了Ehcache对JSR-107的实现。然而,默认情况下没有创建缓存。

Because neither Spring nor Ehcache looks for a default ehcache.xml file. We add the following property to tell Spring where to find it:

因为Spring和Ehcache都没有寻找一个默认的ehcache.xml文件。我们添加以下属性来告诉Spring在哪里找到它。

spring.cache.jcache.config=classpath:ehcache.xml

Let’s create an ehcache.xml file with a cache called squareCache:

让我们创建一个ehcache.xml文件,其中有一个名为squareCache的缓冲区:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.ehcache.org/v3"
    xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
    xsi:schemaLocation="
            http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
            http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">

    <cache alias="squareCache">
        <key-type>java.lang.Long</key-type>
        <value-type>java.math.BigDecimal</value-type>
        <expiry>
            <ttl unit="seconds">30</ttl>
        </expiry>

        <listeners>
            <listener>
                <class>com.baeldung.cachetest.config.CacheEventLogger</class>
                <event-firing-mode>ASYNCHRONOUS</event-firing-mode>
                <event-ordering-mode>UNORDERED</event-ordering-mode>
                <events-to-fire-on>CREATED</events-to-fire-on>
                <events-to-fire-on>EXPIRED</events-to-fire-on>
            </listener>
        </listeners>

        <resources>
            <heap unit="entries">2</heap>
            <offheap unit="MB">10</offheap>
        </resources>
    </cache>

</config>

And let’s also add the cache event listener which logs both CREATED and EXPIRED cache events:

我们也来添加缓存事件监听器,它可以记录CREATEDEXPIRED缓存事件。

public class CacheEventLogger 
  implements CacheEventListener<Object, Object> {

    // ...

    @Override
    public void onEvent(
      CacheEvent<? extends Object, ? extends Object> cacheEvent) {
        log.info(/* message */,
          cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
    }
}

5. In Action

5.行动中

We can use Maven to start this app by running mvn spring-boot:run.

我们可以使用Maven,通过运行mvn spring-boot:run来启动这个应用。

Then open up a browser and access the REST service on port 8080.

然后打开浏览器,访问8080端口的REST服务。

If we go to http://localhost:8080/number/square/12then we’ll get back {“square”:144}, and in the log we’ll see:

如果我们去http://localhost:8080/number/square/12那么我们会得到回报{“平方”:144},在日志中我们会看到。

INFO [nio-8080-exec-1] c.b.cachetest.rest.NumberController : call numberService to square 12
INFO [nio-8080-exec-1] c.b.cachetest.service.NumberService : square of 12 is 144
INFO [e [_default_]-0] c.b.cachetest.config.CacheEventLogger : Cache event CREATED for item with key 12. Old value = null, New value = 144

We can see the log message from the square method of NumberService, and the CREATED event from the EventLogger. If we then refresh the browser we will only see the following added to the log:

我们可以看到来自NumberServicesquare方法的日志信息,以及EventLogger的CREATED事件。如果我们再刷新浏览器,我们将只看到以下内容被添加到日志中:

INFO [nio-8080-exec-2] c.b.cachetest.rest.NumberController : call numberService to square 12

The log message in the square method of NumberService isn’t being invoked. This shows us that the cached value is being used.

NumberServicesquare方法中的日志信息没有被调用。这表明我们正在使用缓存的值。

If we wait 30 seconds for the cached item to expire and refresh the browser we’ll see an EXPIRED event, and the value added back into the cache:

如果我们等待30秒,让缓存的项目过期,然后刷新浏览器,我们会看到一个EXPIRED事件,并将该值添加回缓存中。

INFO [nio-8080-exec-1] (...) NumberController : call numberService to square 12
INFO [e [_default_]-1] (...) CacheEventLogger : Cache event EXPIRED for item with key 12. Old value = 144,New value = null
INFO [nio-8080-exec-1] (... )NumberService : square of 12 is 144
INFO [e [_default_]-1] (...) CacheEventLogger : Cache event CREATED for item with key 12. Old value = null, New value = 144

If we enter http://localhost:8080/number/square/3 into the browser, we get the correct answer of 9, but the value isn’t cached.

如果我们在浏览器中输入http://localhost:8080/number/square/3,我们会得到正确的答案9,但是这个值没有被缓存。

This is because of the condition we used on the @Cacheable annotation to only cache values for numbers higher than 10.

这是因为我们在@Cacheable注解上使用了条件,只对高于10的数字进行缓存。

6. Conclusion

6.结语

In this quick tutorial, we showed how to set up Ehcache with Spring Boot.

在这个快速教程中,我们展示了如何用Spring Boot设置Ehcache。

As always, the code can be found on GitHub.

一如既往,代码可以在GitHub上找到。