目次
アプリケーションにキャッシュを追加する理由
Spring Boot アプリケーションでのキャッシュの実装
SpringBoot はどのようなキャッシュ サポートを提供しますか?
ビルドの依存関係を追加する
への依存関係を追加します。キャッシュ構成
/API/v1/customer/{id}
测试缓存是否正常工作
为什么缓存有时会很危险
缓存更新/失效
缓存复制
嵌入式缓存
远程缓存服务器
缓存自定义
缓存密钥
条件缓存
@CachePut
缓存失效
ホームページ Java &#&チュートリアル SpringBoot が Caffeine を使用してキャッシュを実装する方法

SpringBoot が Caffeine を使用してキャッシュを実装する方法

May 12, 2023 am 11:34 AM
springboot caffeine

アプリケーションにキャッシュを追加する理由

アプリケーションにキャッシュを追加する方法に入る前に、最初に頭に浮かぶ疑問は、なぜアプリケーションでキャッシュを使用する必要があるのか​​ということです。

顧客データを含むアプリケーションがあり、ユーザーが顧客データ (id=100) を取得するために 2 つのリクエストを行ったとします。

これは、キャッシュがない場合に起こることです。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

#ご覧のとおり、リクエストごとに、アプリケーションはデータベースにアクセスしてデータを取得します。データベースからのデータの取得は IO を伴うため、コストがかかる操作です。

ただし、データを一時的に短期間保存できるキャッシュ ストアが中間にある場合は、これらの往復をデータベースに保存し、IO 時に保存できます。

これは、キャッシュを使用した場合の上記のインタラクションがどのように見えるかです。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

Spring Boot アプリケーションでのキャッシュの実装

SpringBoot はどのようなキャッシュ サポートを提供しますか?

  • SpringBoot は、Spring アプリケーションにキャッシュを透過的かつ簡単に追加するために使用できるキャッシュ抽象化のみを提供します。

  • 実際のキャッシュ ストレージは提供されません。

  • ただし、Ehcache、Hazelcast、Redis、Caffee などのさまざまな種類のキャッシュ プロバイダーと連携できます。

  • SpringBoot のキャッシュ抽象化はメソッドに追加できます (アノテーションを使用)

  • 基本的に、Spring フレームワークはメソッドを実行する前にメソッドをチェックします。データはすでにキャッシュされていますか?

  • 「はい」の場合、キャッシュからデータを取得します。

  • それ以外の場合は、メソッドが実行され、データがキャッシュされます。

  • また、キャッシュからデータを更新または削除するための抽象化も提供します。

  • 今回のブログでは、Java 8 ベースの高性能で最適に近いキャッシュ ライブラリである Caffeine を使用してキャッシュを追加する方法を学びます。

application.yaml ファイルで spring.cache.type プロパティを設定することで、どのキャッシュ プロバイダーを使用するかを指定できます。

ただし、属性が指定されていない場合、Spring は追加されたライブラリに基づいてキャッシュ プロバイダーを自動的に検出します。

ビルドの依存関係を追加する

基本的な Spring Boot アプリケーションが稼働していると仮定して、キャッシュの依存関係を追加しましょう。

build.gradle ファイルを開き、次の依存関係を追加して Spring Boot のキャッシュを有効にします

compile('org.springframework.boot:spring-boot-starter-cache')
ログイン後にコピー

次に、Caffeine

compile group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.8.5'
ログイン後にコピー

への依存関係を追加します。キャッシュ構成

次に、Spring Boot アプリケーションでキャッシュを有効にする必要があります。

これを行うには、構成クラスを作成し、アノテーション @EnableCaching を提供する必要があります。

@Configuration
@EnableCaching
public class CacheConfig {
     
}
ログイン後にコピー

現時点ではこのクラスは空のクラスですが、必要に応じてさらに構成を追加できます。

キャッシュを有効にしたので、キャッシュ名と、キャッシュ サイズ、キャッシュ有効期限などのキャッシュ プロパティの構成を指定しましょう。

これを行う最も簡単な方法は、次のとおりです。 application.yaml

spring:
  cache:
    cache-names: customers, users, roles
    caffeine:
      spec: maximumSize=500, expireAfterAccess=60s
ログイン後にコピー
に構成を追加します

上記の構成は次の操作を実行します

  • 使用可能なキャッシュ名を顧客、ユーザー、およびロールに制限します。最大キャッシュ サイズを 500 に設定します。

  • キャッシュ内のオブジェクトの数がこの制限に達すると、オブジェクトはキャッシュ削除ポリシーに従ってキャッシュから削除されます。キャッシュの有効期限を 1 分に設定します。

  • これは、アイテムがキャッシュに追加されてから 1 分後にキャッシュから削除されることを意味します。

application.yaml ファイルでキャッシュを構成する代わりに、キャッシュを構成する別の方法があります。

キャッシュ構成クラスに CacheManager Bean を追加して提供できます。これにより、application.yaml# での上記の構成とまったく同じジョブを完了できます。

@Bean
public CacheManager cacheManager() {
    Caffeine<Object, Object> caffeineCacheBuilder =
        Caffeine.newBuilder()
            .maximumSize(500)
            .expireAfterAccess(
                    1, TimeUnit.MINUTES);
     
    CaffeineCacheManager cacheManager = 
            new CaffeineCacheManager(
            "customers", "roles", "users");
    cacheManager.setCaffeine(caffeineCacheBuilder);
    return cacheManager;
}
ログイン後にコピー

コード例では、Java 構成を使用します。

Java では、アイテムがキャッシュから削除されたときに実行されるように

RemovalListener を構成したり、キャッシュ統計ログを有効にしたりするなど、さらに多くのことを行うことができます。 メソッドの結果のキャッシュ

使用しているサンプル Spring Boot アプリケーションには、すでに次の API GET

/API/v1/customer/{id}

Retrieve customer記録。

CustomerService クラスの SpringBoot が Caffeine を使用してキャッシュを実装する方法getCustomerByd(longCustomerId)

メソッドにキャッシュを追加します。

これを行うには、2 つのことを行うだけです。

1. コメント

@CacheConfig(cacheNames="customers")

CustomerService ## に追加します。 # クラス このオプションを指定すると、CustomerService のすべてのキャッシュ可能なメソッドがキャッシュ名「customers」を使用するようになります

2. 向方法 Optional getCustomerById(Long customerId) 添加注释 @Cacheable

@Service
@Log4j2
@CacheConfig(cacheNames = "customers")
public class CustomerService {
 
    @Autowired
    private CustomerRepository customerRepository;
 
    @Cacheable
    public Optional<Customer> getCustomerById(Long customerId) {
        log.info("Fetching customer by id: {}", customerId);
        return customerRepository.findById(customerId);
    }
}
ログイン後にコピー

另外,在方法 getCustomerById() 中添加一个 LOGGER 语句,以便我们知道服务方法是否得到执行,或者值是否从缓存返回。

 代码如下:log.info("Fetching customer by id: {}", customerId);
ログイン後にコピー

测试缓存是否正常工作

这就是缓存工作所需的全部内容。现在是测试缓存的时候了。

启动您的应用程序,并点击客户获取url

http://localhost:8080/api/v1/customer/

在第一次API调用之后,您将在日志中看到以下行—“ Fetching customer by id ”。

但是,如果再次点击API,您将不会在日志中看到任何内容。这意味着该方法没有得到执行,并且从缓存返回客户记录。

现在等待一分钟(因为缓存过期时间设置为1分钟)。

一分钟后再次点击GETAPI,您将看到下面的语句再次被记录——“通过id获取客户”。

这意味着客户记录在1分钟后从缓存中删除,必须再次从数据库中获取。

为什么缓存有时会很危险

缓存更新/失效

通常我们缓存 GET 调用,以提高性能。

但我们需要非常小心的是缓存对象的更新/删除。

@CachePut
@cacheexecute
ログイン後にコピー

如果未将 @CachePut/@cacheexecute 放入更新/删除方法中,GET调用中缓存返回的对象将与数据库中存储的对象不同。考虑下面的示例场景。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

如您所见,第二个请求已将人名更新为“ John Smith ”。但由于它没有更新缓存,因此从此处开始的所有请求都将从缓存中获取过时的个人记录(“ John Doe ”),直到该项在缓存中被删除/更新。

缓存复制

大多数现代web应用程序通常有多个应用程序节点,并且在大多数情况下都有一个负载平衡器,可以将用户请求重定向到一个可用的应用程序节点。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

这种类型的部署为应用程序提供了可伸缩性,任何用户请求都可以由任何一个可用的应用程序节点提供服务。

在这些分布式环境(具有多个应用服务器节点)中,缓存可以通过两种方式实现

  • 应用服务器中的嵌入式缓存(正如我们现在看到的)

  • 远程缓存服务器

嵌入式缓存

嵌入式缓存驻留在应用程序服务器中,它随应用程序服务器启动/停止。由于每台服务器都有自己的缓存副本,因此对其缓存的任何更改/更新都不会自动反映在其他应用程序服务器的缓存中。

考虑具有嵌入式缓存的多节点应用服务器的下面场景,其中用户可以根据应用服务器为其请求服务而得到不同的结果。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

正如您在上面的示例中所看到的,更新请求更新了 Application Node2 的数据库和嵌入式缓存。

但是, Application Node1 的嵌入式缓存未更新,并且包含过时数据。因此, Application Node1 的任何请求都将继续服务于旧数据。

要解决这个问题,您需要实现 CACHE REPLICATION —其中任何一个缓存中的任何更新都会自动复制到其他缓存(下图中显示为蓝色虚线)

SpringBoot が Caffeine を使用してキャッシュを実装する方法

远程缓存服务器

解决上述问题的另一种方法是使用远程缓存服务器(如下所示)。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

然而,这种方法的最大缺点是增加了响应时间——这是由于从远程缓存服务器获取数据时的网络延迟(与内存缓存相比)

缓存自定义

到目前为止,我们看到的缓存示例是向应用程序添加基本缓存所需的唯一代码。

然而,现实世界的场景可能不是那么简单,可能需要进行一些定制。在本节中,我们将看到几个这样的例子

缓存密钥

我们知道缓存是密钥、值对的存储。

示例1:默认缓存键–具有单参数的方法

最简单的缓存键是当方法只有一个参数,并且该参数成为缓存键时。在下面的示例中, Long customerId 是缓存键

SpringBoot が Caffeine を使用してキャッシュを実装する方法

示例2:默认缓存键–具有多个参数的方法

在下面的示例中,缓存键是所有三个参数的SimpleKey– countryIdregionIdpersonId

SpringBoot が Caffeine を使用してキャッシュを実装する方法

示例3:自定义缓存密钥

在下面的示例中,我们将此人的 emailAddress 指定为缓存的密钥

SpringBoot が Caffeine を使用してキャッシュを実装する方法

示例4:使用 KeyGenerator 的自定义缓存密钥

让我们看看下面的示例–如果要缓存当前登录用户的所有角色,该怎么办。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

该方法中没有提供任何参数,该方法在内部获取当前登录用户并返回其角色。

为了实现这个需求,我们需要创建一个如下所示的自定义密钥生成器

SpringBoot が Caffeine を使用してキャッシュを実装する方法

然后我们可以在我们的方法中使用这个键生成器,如下所示。

SpringBoot が Caffeine を使用してキャッシュを実装する方法

条件缓存

在某些用例中,我们只希望在满足某些条件的情况下缓存结果

示例1(支持 java.util.Optional –仅当存在时才缓存)

仅当结果中存在 person 对象时,才缓存 person 对象。

@Cacheable( value = "persons", unless = "#result?.id")
public Optional<Person> getPerson(Long personId)
ログイン後にコピー

示例2(如果需要,by-pass缓存)

@Cacheable(value = "persons", condition="#fetchFromCache")
public Optional<Person> getPerson(long personId, boolean fetchFromCache)
ログイン後にコピー

仅当方法参数“ fetchFromCache ”为true时,才从缓存中获取人员。通过这种方式,方法的调用方有时可以决定绕过缓存并直接从数据库获取值。

示例3(基于对象属性的条件计算)

仅当价格低于500且产品有库存时,才缓存产品。

@Cacheable( 
   value="products", 
   condition="#product.price<500",
   unless="#result.outOfStock")
public Product findProduct(Product product)
ログイン後にコピー

@CachePut

我们已经看到 @Cacheable 用于将项目放入缓存。

但是,如果该对象被更新,并且我们想要更新缓存,该怎么办?

我们已经在前面的一节中看到,不更新缓存post任何更新操作都可能导致从缓存返回错误的结果。

@CachePut(key = "#person.id")
public Person update(Person person)
ログイン後にコピー

但是如果 @Cacheable@CachePut 都将一个项目放入缓存,它们之间有什么区别?

主要区别在于实际的方法执行

@Cacheable
@CachePut
ログイン後にコピー

缓存失效

缓存失效与将对象放入缓存一样重要。

当我们想要从缓存中删除一个或多个对象时,有很多场景。让我们看一些例子。

例1

假设我们有一个用于批量导入个人记录的API。

我们希望在调用此方法之前,应该清除整个 person 缓存(因为大多数 person 记录可能会在导入时更新,而缓存可能会过时)。我们可以这样做如下

@CacheEvict(
   value = "persons", 
   allEntries = true, 
   beforeInvocation = true)
public void importPersons()
ログイン後にコピー

例2

我们有一个Delete Person API,我们希望它在删除时也能从缓存中删除 Person 记录。

@CacheEvict(
   value = "persons", 
   key = "#person.emailAddress")
public void deletePerson(Person person)
ログイン後にコピー

默认情况下 @CacheEvict 在方法调用后运行。

以上がSpringBoot が Caffeine を使用してキャッシュを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Springboot が Jasypt を統合して構成ファイルの暗号化を実装する方法 Springboot が Jasypt を統合して構成ファイルの暗号化を実装する方法 Jun 01, 2023 am 08:55 AM

Jasypt の概要 Jasypt は、開発者が最小限の労力で基本的な暗号化機能を自分のプロジェクトに追加できる Java ライブラリであり、暗号化の仕組みを深く理解する必要はありません。一方向および双方向暗号化の高いセキュリティ。標準ベースの暗号化テクノロジー。パスワード、テキスト、数値、バイナリを暗号化します... Spring ベースのアプリケーション、オープン API への統合、JCE プロバイダーでの使用に適しています... 次の依存関係を追加します: com.github.ulisesbocchiojasypt-spring-boot-starter2. 1.1 Jasypt の特典はシステムのセキュリティを保護し、コードが漏洩した場合でもデータ ソースは保証されます。

SpringBoot が Redisson を統合して遅延キューを実装する方法 SpringBoot が Redisson を統合して遅延キューを実装する方法 May 30, 2023 pm 02:40 PM

使用シナリオ 1. 注文は正常に行われましたが、支払いが 30 分以内に行われませんでした。支払いがタイムアウトになり、注文が自動的にキャンセルされました 2. 注文に署名があり、署名後 7 日間評価が行われませんでした。注文がタイムアウトして評価されない場合、システムはデフォルトでプラスの評価を設定します 3. 注文は正常に行われます。販売者が 5 分間注文を受け取らない場合、注文はキャンセルされます。 4. 配送がタイムアウトします。 SMS リマインダーをプッシュします... 遅延が長く、リアルタイム パフォーマンスが低いシナリオでは、タスク スケジュールを使用して定期的なポーリング処理を実行できます。例: xxl-job 今日は選択します

Redis を使用して SpringBoot に分散ロックを実装する方法 Redis を使用して SpringBoot に分散ロックを実装する方法 Jun 03, 2023 am 08:16 AM

1. Redis は分散ロックの原則を実装しており、分散ロックが必要な理由 分散ロックについて話す前に、分散ロックが必要な理由を説明する必要があります。分散ロックの反対はスタンドアロン ロックです。マルチスレッド プログラムを作成するとき、共有変数を同時に操作することによって引き起こされるデータの問題を回避します。通常、ロックを使用して共有変数を相互に除外し、データの正確性を確保します。共有変数の使用範囲は同じプロセス内です。共有リソースを同時に操作する必要があるプロセスが複数ある場合、どうすれば相互排他的になるのでしょうか?今日のビジネス アプリケーションは通常マイクロサービス アーキテクチャであり、これは 1 つのアプリケーションが複数のプロセスをデプロイすることも意味します。複数のプロセスが MySQL の同じレコード行を変更する必要がある場合、順序の乱れた操作によって引き起こされるダーティ データを避けるために、分散が必要です。今回導入するスタイルはロックされています。ポイントを獲得したい

Springbootがjarパッケージにファイルを読み込んだ後にファイルにアクセスできない問題を解決する方法 Springbootがjarパッケージにファイルを読み込んだ後にファイルにアクセスできない問題を解決する方法 Jun 03, 2023 pm 04:38 PM

Springboot はファイルを読み取りますが、jar パッケージにパッケージ化した後、最新の開発にアクセスできません。jar パッケージにパッケージ化した後、Springboot がファイルを読み取れない状況があります。その理由は、パッケージ化後、ファイルの仮想パスが変更されるためです。は無効であり、ストリーム経由でのみアクセスできます。読み取ります。ファイルはリソースの下にあります publicvoidtest(){Listnames=newArrayList();InputStreamReaderread=null;try{ClassPathResourceresource=newClassPathResource("name.txt");Input

SpringBootとSpringMVCの比較と差異分析 SpringBootとSpringMVCの比較と差異分析 Dec 29, 2023 am 11:02 AM

SpringBoot と SpringMVC はどちらも Java 開発で一般的に使用されるフレームワークですが、それらの間には明らかな違いがいくつかあります。この記事では、これら 2 つのフレームワークの機能と使用法を調べ、その違いを比較します。まず、SpringBoot について学びましょう。 SpringBoot は、Spring フレームワークに基づいたアプリケーションの作成と展開を簡素化するために、Pivo​​tal チームによって開発されました。スタンドアロンの実行可能ファイルを構築するための高速かつ軽量な方法を提供します。

SQL ステートメントを使用せずに Springboot+Mybatis-plus を実装して複数のテーブルを追加する方法 SQL ステートメントを使用せずに Springboot+Mybatis-plus を実装して複数のテーブルを追加する方法 Jun 02, 2023 am 11:07 AM

Springboot+Mybatis-plus が SQL ステートメントを使用して複数テーブルの追加操作を実行しない場合、私が遭遇した問題は、テスト環境で思考をシミュレートすることによって分解されます: パラメーターを含む BrandDTO オブジェクトを作成し、パラメーターをバックグラウンドに渡すことをシミュレートします。 Mybatis-plus で複数テーブルの操作を実行するのは非常に難しいことを理解してください。Mybatis-plus-join などのツールを使用しない場合は、対応する Mapper.xml ファイルを設定し、臭くて長い ResultMap を設定するだけです。対応する SQL ステートメントを記述します。この方法は面倒に見えますが、柔軟性が高く、次のことが可能です。

SpringBoot が Redis をカスタマイズしてキャッシュのシリアル化を実装する方法 SpringBoot が Redis をカスタマイズしてキャッシュのシリアル化を実装する方法 Jun 03, 2023 am 11:32 AM

1. RedisAPI のデフォルトのシリアル化メカニズムである RedisTemplate1.1 をカスタマイズします。API ベースの Redis キャッシュ実装では、データ キャッシュ操作に RedisTemplate テンプレートを使用します。ここで、RedisTemplate クラスを開いて、クラスのソース コード情報を表示します。publicclassRedisTemplateextendsRedisAccessorimplementsRedisOperations、BeanClassLoaderAware{//キーを宣言、値の各種シリアル化メソッド、初期値は空 @NullableprivateRedisSe

Springbootでapplication.ymlの値を取得する方法 Springbootでapplication.ymlの値を取得する方法 Jun 03, 2023 pm 06:43 PM

プロジェクトでは、構成情報が必要になることがよくありますが、この情報はテスト環境と本番環境で構成が異なる場合があり、実際のビジネス状況に基づいて後で変更する必要がある場合があります。これらの構成をコードにハードコーディングすることはできません。構成ファイルに記述することをお勧めします。たとえば、この情報を application.yml ファイルに書き込むことができます。では、コード内でこのアドレスを取得または使用するにはどうすればよいでしょうか?方法は2つあります。方法 1: @Value アノテーションが付けられた ${key} を介して、構成ファイル (application.yml) 内のキーに対応する値を取得できます。この方法は、マイクロサービスが比較的少ない状況に適しています。方法 2: 実際には、プロジェクト、業務が複雑な場合、ロジック

See all articles