【spring指南系列】使用Spring缓存数据

本指南将指导您完成在Spring所托管bean上启用缓存的过程。

What you’ll build

您将构建一个应用程序,在一个简单的book repository中启用缓存。

What you’ll need

How to complete this guide

与大多数【Spring 入门指南】一样(Spring Guides),您可以从头开始并完成每个步骤,也可以绕过已经熟悉的基本设置步骤。 无论如何,你最终得到工作代码。

当你做完这一切, 你可以根据 gs-caching/complete中的代码检查结果.

Build with Gradle

首先你设置一个基本的构建脚本。 你可以使用任何你喜欢的一个来构建项目,当使用Spring构建应用程序时,但是需要使用GradleMaven 来写你的代码。 如果你不熟悉任何一个,请参考使用Gradle构建Java项目使用Maven构建Java项目

Create the directory structure

在您选择的项目目录中,创建以下子目录结构; 例如,在 nix系统上使用`mkdir -p src / main / java / hello’:

└── src
    └── main
        └── java
            └── hello

Create a Gradle build file

下面是 initial Gradle build file

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.3.RELEASE")
    }
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
jar {
    baseName = 'gs-caching'
    version =  '0.1.0'
}
repositories {
    mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
    compile("org.springframework.boot:spring-boot-starter-cache")
}

Spring Boot gradle插件提供了许多方便的功能:

  • 它收集类路径上的所有jar,并构建一个单独的,可运行的“über-jar”,这使得执行和传递服务更加方便。
  • 它搜索public static void main()方法来标记为可运行类。
  • 它提供了一个内置的依赖解析器,设置版本号匹配Spring Boot dependencies. 你可以覆盖任何你想要的版本,但它会默认为Boot的选择的版本集。

Build with Maven

首先你设置一个基本的构建脚本。 你可以使用任何你喜欢的一个来构建项目,当使用Spring构建应用程序,但是需要使用Maven来构建你的代码。 如果你不熟悉Maven,请参考使用Maven构建Java项目.

Create the directory structure

在您选择的项目目录中,创建以下子目录结构; 例如,在 nix系统上使用`mkdir -p src / main / java / hello’:

└── src
    └── main
        └── java
            └── hello

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.springframework</groupId>
    <artifactId>gs-caching</artifactId>
    <version>0.1.0</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
    </parent>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Spring Boot Maven插件 提供了许多方便的功能:

  • 它收集类路径上的所有jar,并构建一个单独的,可运行的“über-jar”,这使得执行和运输服务更加方便。
  • 它搜索public static void main()方法来标记为可运行类。
  • 它提供了一个内置的依赖解析器,设置版本号匹配Spring Boot dependencies. 你可以覆盖任何你想要的版本,但它会默认为Boot的选择的版本集。

Build with your IDE

Create a book repository

首先,让我们为你的book创建一个非常简单的模型

src/main/java/hello/Book.java

package hello;
public class Book {
    private String isbn;
    private String title;
    public Book(String isbn, String title) {
        this.isbn = isbn;
        this.title = title;
    }
    public String getIsbn() {
        return isbn;
    }
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    @Override
    public String toString() {
        return "Book{" + "isbn='" + isbn + '\'' + ", title='" + title + '\'' + '}';
    }
}

和该model的存储库:

src/main/java/hello/BookRepository.java

package hello;
public interface BookRepository {
    Book getByIsbn(String isbn);
}

您可以使用Spring Data在很多的SQL或NoSQL stores中提供repository仓库的实现,但是出于本指南的目的, 将使用模拟一些延迟(网络服务,慢延迟等)进行简单地的实现。

src/main/java/hello/SimpleBookRepository.java

package hello;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
    @Override
    public Book getByIsbn(String isbn) {
        simulateSlowService();
        return new Book(isbn, "Some book");
    }
    // Don't do this at home     private void simulateSlowService() {
        try {
            long time = 3000L;
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

simulateSlowService是故意在每个getByIsbn调用中插入一个三秒延迟。 这是一个例子,稍后,你可以通过加入缓存来看到加速的效果。

Using the repository

接下来,连接repository库并使用它访问一些书。

src/main/java/hello/Application.java

package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@ SpringBootApplication是一个方便的注解,添加了以下所有内容:

  • @ Configuration将类标记为应用程序上下文的bean定义的来源。
  • @ EnableAutoConfiguration告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。
  • 通常你会为Spring MVC应用程序添加@ EnableWebMvc,但是Spring Boot在类路径上看到 spring-webmvc 时会自动添加它。这将应用程序标记为Web应用程序,并激活关键行为,如设置一个“DispatcherServlet”。
  • @ ComponentScan告诉Spring在hello包中寻找其他组件,配置和服务,允许它找到控制器。

main()方法使用Spring Boot的SpringApplication.run()方法来启动应用程序。你有注意到一行XML?没有 web.xml 文件。这个Web应用程序是100%纯Java,你不必处理配置任何管道或基础设施。

还有一个CommandLineRunner,注入BookRepository和 用不同的参数调用它几次。

src/main/java/hello/AppRunner.java

package hello;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
    private final BookRepository bookRepository;
    public AppRunner(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
    @Override
    public void run(String... args) throws Exception {
        logger.info(".... Fetching books");
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
        logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
        logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
        logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
    }
}

如果你尝试在此时运行应用程序,您会注意到它很慢,即使您几次检索完全相同的书。

2014-06-05 12:15:35.783  ... : .... Fetching books
2014-06-05 12:15:40.783  ... : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
2014-06-05 12:15:43.784  ... : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
2014-06-05 12:15:46.786  ... : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}

从时间戳可以看出,每本书花了大约三秒钟来检索,即使它是相同的标题被重复抓取。

Enable caching

让我们在你的SimpleBookRepository上启用缓存,这样书就会被缓存在books缓存中。

src/main/java/hello/SimpleBookRepository.java

package hello;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
    @Override
    @Cacheable("books")
    public Book getByIsbn(String isbn) {
        simulateSlowService();
        return new Book(isbn, "Some book");
    }
    // Don't do this at home     private void simulateSlowService() {
        try {
            long time = 3000L;
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

您现在需要启用缓存注解的处理

src/main/java/hello/Application.java

package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@EnableCaching注解触发检查并处理每个Spring bean用于存在对公共方法的缓存注解。如果找到这样的注解,则自动创建代理以拦截方法调用并相应地处理缓存行为。

缓存处理的相应注解是Cacheable CachePutCacheEvict.有关更多详细信息,可以参考javadocs和文档

Spring Boot会自动配置一个合适的CacheManager,作为相关缓存。有关更多详细信息,请参阅Spring Boot文档

我们的示例不使用特定的缓存库,因此我们的缓存存储是使用ConcurrentHashMap的简单回退。缓存抽象支持各种各样的缓存库,并完全符合JSR-107(JCache)。

Build an executable JAR

您可以使用Gradle或Maven从命令行运行应用程序。 或者,您可以构建单个可执行文件,其中包含所有必需的依赖关系,类和资源,并运行它。 这使得在整个开发生命周期中,易于跨不同环境将服务作为应用程序进行发布,维护版本和部署等等。

如果您使用Gradle,可以使用./gradlew bootRun运行应用程序。 或者你可以使用./gradlew build来构建JAR文件。 然后可以运行JAR文件:

java -jar build/libs/gs-caching-0.1.0.jar

如果您使用Maven,可以使用./mvnw spring-boot:run运行应用程序。 或者你可以用./mvnw clean package构建JAR文件。 然后可以运行JAR文件:

java -jar target/gs-caching-0.1.0.jar

**上面的过程将创建一个可运行的JAR。 您也可以选择
build a classic WAR file

Test the application

现在缓存已启用,您可以再次执行它,并通过添加或不使用相同的isbn的额外调用查看差异。 你应该可以看到其产生明显的区别。

2016-09-01 11:12:47.033  .. : .... Fetching books
2016-09-01 11:12:50.039  .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
2016-09-01 11:12:53.044  .. : isbn-4567 -->Book{isbn='isbn-4567', title='Some book'}
2016-09-01 11:12:53.045  .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
2016-09-01 11:12:53.045  .. : isbn-4567 -->Book{isbn='isbn-4567', title='Some book'}
2016-09-01 11:12:53.045  .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
2016-09-01 11:12:53.045  .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}

This excerpt from the console shows that the first time to fetch each title took three seconds, but each subsequent call was near instantaneous.

从控制台的这段日志显示,第一次获取每个标题花了三秒钟,但每个后续的访问接近瞬间。

最后

恭喜! 你刚刚通过Springcache在托管bean上启用了缓存。

系列回顾:

【spring指南系列】使用Redis进行消息传递

【spring指南系列】计划任务

【spring指南系列】使用RESTful Web服务

【spring 指南系列】如何更好的设计RESTful API

[ 转载请保留原文出处、译者和译文链接。]

    原文作者:知秋z
    原文地址: https://zhuanlan.zhihu.com/p/24796537
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞