The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Infinispan Client

Infinispan is a distributed, in-memory key/value store that provides Quarkus applications with a highly configurable and independently scalable data layer. This extension gives you client functionality that connects applications running on Quarkus with remote Infinispan clusters.

To find out more about Infinispan, visit the Infinispan documentation.

ソリューション

We recommend that you complete each step in the following sections to create the application. However, you can proceed directly to the completed solution as follows:

Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git or download an archive. Locate the solution in the infinispan-client-quickstart directory.

Adding the Infinispan client extension

Run the following command in the base directory of your Quarkus project to add the infinispan-client extension:

CLI
quarkus extension add 'infinispan-client'
Maven
./mvnw quarkus:add-extension -Dextensions="infinispan-client"
Gradle
./gradlew addExtension --extensions="infinispan-client"

This command adds the following dependency to your build file:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-infinispan-client</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-infinispan-client")

Infinispanクライアントの設定

src/main/resources ディレクトリの application.properties をテキストエディタで開いて下さい。

Note that Infinispan documentation refers to a hotrod-client.properties file. You can configure the Infinispan client with either properties file but application.properties always takes priority over hotrod-client.properties.

Additionally, you cannot update configuration properties at runtime. If you modify application.properties or hotrod-client.properties, you must rebuild the application before those changes take effect.

Connecting to Infinispan clusters

Add the following properties to connect to Infinispan Server:

# Infinispan Server address
quarkus.infinispan-client.server-list=localhost:11222

# Authentication
quarkus.infinispan-client.auth-username=admin
quarkus.infinispan-client.auth-password=password

# Infinispan client intelligence
# Use BASIC as a Docker for Mac workaround
quarkus.infinispan-client.client-intelligence=BASIC
Running Infinispan Server

To use the Infinispan client extension, you need at least one running instance of Infinispan Server.

Check out our 5-minute Getting stated with Infinispan tutorial to run Infinispan Server locally.

Infinispan Server also enables authentication and security authorization by default, so you need to create a user with permissions.

  • If you run the Infinispan Server image, pass the USER="admin" and PASS="password" parameters.

  • If you run the bare metal distribution, use the Command Line Interface (CLI) as follows:

    $ ./bin/cli.sh user create admin -p password

認証メカニズム

You can use the following authentication mechanisms with the Infinispan client:

  • DIGEST-MD5

  • PLAIN (recommended only in combination with TLS encryption)

  • EXTERNAL

Other authentication mechanisms, such as SCRAM and GSSAPI, are not yet verified with the Infinispan client.

認証の設定についての詳しい情報は Hot Rod Endpoint Authentication Mechanisms に存在します。

You must configure authentication in the hotrod-client.properties file if you use Dependency Injection.

シリアライゼーション(Key Value型のサポート)

By default, the client will support keys and values of the following types: byte[], primitive wrappers (e.g. Integer, Long, Double), String, Date and Instant. User types require some additional steps that are detailed here. Let’s say we have the following user classes:

Author.java
public class Author {
   private final String name;
   private final String surname;

   public Author(String name, String surname) {
      this.name = Objects.requireNonNull(name);
      this.surname = Objects.requireNonNull(surname);
   }
   // Getter/Setter/equals/hashCode/toString は省略
}
Book.java
public class Book {
   private final String title;
   private final String description;
   private final int publicationYear;
   private final Set<Author> authors;
   private final BigDecimal price;

   public Book(String title, String description, int publicationYear, Set<Author> authors, BigDecimal price) {
      this.title = Objects.requireNonNull(title);
      this.description = Objects.requireNonNull(description);
      this.publicationYear = publicationYear;
      this.authors = Objects.requireNonNull(authors);
      this.price = price;
   }
   // Getter/Setter/equals/hashCode/toString は省略
}

ユーザ型のシリアライズは、https://github.com/infinispan/protostream[Protostream]と呼ばれるprotobufをベースにしたライブラリを使用します。

Infinispan caches can store keys and values in different encodings, but recommend using Protocol Buffers (Protobuf).

For more information see our Cache Encoding and Marshalling guide.

アノテーションに基づくシリアライゼーション

これは、ユーザクラスに protostream アノテーションを追加することで自動的に行えます。加えて、初期化子がアノテーションされたインターフェースが1つ必要です。これは、サポートするクラスの生成方法を制御します。

ここでは、先述のクラスをどのように変更するかの例を示します。

Author.java
    @ProtoFactory
    public Author(String name, String surname) {
        this.name = Objects.requireNonNull(name);
        this.surname = Objects.requireNonNull(surname);
    }

    @ProtoField(number = 1)
    public String getName() {
        return name;
    }

    @ProtoField(number = 2)
    public String getSurname() {
        return surname;
    }
Book.java
    @ProtoFactory
    public Book(String title, String description, int publicationYear, Set<Author> authors) {
        this.title = Objects.requireNonNull(title);
        this.description = Objects.requireNonNull(description);
        this.publicationYear = publicationYear;
        this.authors = Objects.requireNonNull(authors);
    }

    @ProtoField(number = 1)
    public String getTitle() {
        return title;
    }

    @ProtoField(number = 2)
    public String getDescription() {
        return description;
    }

    @ProtoField(number = 3, defaultValue = "-1")
    public int getPublicationYear() {
        return publicationYear;
    }

    @ProtoField(number = 4)
    public Set<Author> getAuthors() {
        return authors;
    }

クラスが変更可能なフィールドしかない場合、 ProtoFactory アノテーションは必要ありません。あなたのクラスが引数なしのコンストラクタを持っていると仮定します。

必要なのは、設定を指定する為のアノテーションを付与した非常にシンプルな GeneratedSchema インターフェイスだけです。

BooksSchema.java
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.types.java.math.BigDecimalAdapter;

@AutoProtoSchemaBuilder(includeClasses = { Book.class, Author.class, BigDecimalAdapter.class }, schemaPackageName = "book_sample")
interface BookStoreSchema extends GeneratedSchema {
}
Protostream provides default Protobuf mappers for commonly used types as BigDecimal, included in the org.infinispan.protostream.types package.

そこで今回は、含まれるクラスのマーシャラとスキーマを自動生成して、スキーマパッケージに自動で配置します。パッケージは用意する必要はありませんが、Infinispanクエリ機能を利用する場合は生成されたパッケージを知っておく必要があります。

Quarkusでは、 schemaFileNameschemaFilePath 属性は、 AutoProtoSchemaBuilder アノテーションに設定すべきではありません。いずれかを設定すると、ネイティブランタイムエラーが発生します。

カスタムシリアライゼーション

前の方法は、ユーザが自分のクラスにアノテーションを付けられる場合のために提案されています。残念ながら、ユーザはキャッシュに入れるすべてのクラスにアノテーションを付けることができないかもしれません。このような場合はスキーマを定義し、自分で独自のマーシャラを作成しなければなりません。

Protobuf スキーマ

2つの方法のいずれかでprotobufスキーマを提供できます。

  1. Proto ファイル + プロジェクトの META-INF ディレクトリに .proto ファイルを置けます。これらのファイルは、初期化時に自動的に取り上げられます。

    library.proto
    package book_sample;
    
    message Book {
      required string title = 1;
      required string description = 2;
      required int32 publicationYear = 3; // no native Date type available in Protobuf
      repeated Author authors = 4;
      requited double price = 5; // no native BigDecimal type available in Protobuf
    }
    
    message Author {
      required string name = 1;
      required string surname = 2;
    }
  2. コード + org.infinispan.protostream.FileDescriptorSource 型の生成されたBeanを定義することにより、ユーザコードで直接protoスキーマを定義できます。

       @Produces
       FileDescriptorSource bookProtoDefinition() {
          return FileDescriptorSource.fromString("library.proto", "package book_sample;\n" +
                "\n" +
                "message Book {\n" +
                "  required string title = 1;\n" +
                "  required string description = 2;\n" +
                "  required int32 publicationYear = 3; // no native Date type available in Protobuf\n" +
                "\n" +
                "  repeated Author authors = 4;\n" +
                "\n" +
                "  required double price = 5; // no native BigDecimal type available in Protobuf\n" +
                "}\n" +
                "\n" +
                "message Author {\n" +
                "  required string name = 1;\n" +
                "  required string surname = 2;\n" +
                "}");
       }
ユーザマーシャラ

最後にすべきことは、proto スキーマで定義された各ユーザクラスの org.infinispan.protostream.MessageMarshaller 実装を提供することです。このクラスは、上記のコードベースの proto スキーマの定義と同様の方法で @Produces を介して提供されます。

こちらは、Author と Book クラスのマーシャラクラスです。

型名は <protobuf package>.<protobuf message> と正確に一致している必要があります!
AuthorMarshaller.java
public class AuthorMarshaller implements MessageMarshaller<Author> {

   @Override
   public String getTypeName() {
      return "book_sample.Author";
   }

   @Override
   public Class<? extends Author> getJavaClass() {
      return Author.class;
   }

   @Override
   public void writeTo(ProtoStreamWriter writer, Author author) throws IOException {
      writer.writeString("name", author.getName());
      writer.writeString("surname", author.getSurname());
   }

   @Override
   public Author readFrom(ProtoStreamReader reader) throws IOException {
      String name = reader.readString("name");
      String surname = reader.readString("surname");
      return new Author(name, surname);
   }
}
BookMarshaller.java
public class BookMarshaller implements MessageMarshaller<Book> {

   @Override
   public String getTypeName() {
      return "book_sample.Book";
   }

   @Override
   public Class<? extends Book> getJavaClass() {
      return Book.class;
   }

   @Override
   public void writeTo(ProtoStreamWriter writer, Book book) throws IOException {
      writer.writeString("title", book.getTitle());
      writer.writeString("description", book.getDescription());
      writer.writeInt("publicationYear", book.getPublicationYear());
      writer.writeCollection("authors", book.getAuthors(), Author.class);
      writer.writeDouble("price", book.getPrice().doubleValue());
   }

   @Override
   public Book readFrom(ProtoStreamReader reader) throws IOException {
      String title = reader.readString("title");
      String description = reader.readString("description");
      int publicationYear = reader.readInt("publicationYear");
      Set<Author> authors = reader.readCollection("authors", new HashSet<>(), Author.class);
      BigDecimal price = BigDecimal.valueOf(reader.readDouble("price"));
      return new Book(title, description, publicationYear, authors, price);
   }
}

そして、以下のように定義してマーシャラを渡します。

   @Produces
   MessageMarshaller authorMarshaller() {
      return new AuthorMarshaller();
   }

   @Produces
   MessageMarshaller bookMarshaller() {
      return new BookMarshaller();
   }
上記のように生成されたMarshallerメソッドは、型なしで MessageMarshaller を返さなければなりません。さもないと、それが見つかりません。

依存性注入

As you saw above we support the user injecting Marshaller configuration. You can do the inverse with the Infinispan client extension providing injection for RemoteCacheManager and RemoteCache objects. There is one global RemoteCacheManager that takes all the configuration parameters setup in the above sections.

It is very simple to inject these components. All you need to do is to add the @Inject annotation to the field, constructor or method. In the below code we utilize field and constructor injection.

SomeClass.java
    @Inject SomeClass(RemoteCacheManager remoteCacheManager) {
       this.remoteCacheManager = remoteCacheManager;
    }

    @Inject @Remote("myCache")
    RemoteCache<String, Book> cache;

    RemoteCacheManager remoteCacheManager;

RemoteCache 宣言に Remote というオプションのアノテーションが追加されていることにお気づきでしょうか。これは、注入される名前付きキャッシュを指定するための修飾子アノテーションです。このアノテーションは必須ではなく、指定しなかった場合はデフォルトのキャッシュが注入されます。

その他の型は注入のためにサポートされている場合がありますが、詳細については他のセクションを参照してください。

Registering Protobuf Schemas with Infinispan Server

You need to register the generated Protobuf schemas with Infinispan Server to perform queries or convert from Protobuf to other media types such as JSON.

You can check the schemas that exist under the Schemas tab by logging into Infinispan Console at http://localhost:11222

By default, Protobuf schemas generated this way will be registered by this extension when the client first connects. However, it might be required to handle the registration manually as a schema may evolve over time when used in production, so you can disable this from occurring by configuring the quarkus.infinispan-client.use-schema-registration to false.

To configure the schema manually please use Infinispan Operator for Kubernetes deployments, Infinispan Console, REST API or the Hot Rod Java Client.

問い合わせ

Infinispan クライアントは、上記の ProtoStreamMarshaller が設定されている限り、インデックス付きと非インデックス付きの両方の問い合せをサポートしています。これにより、ユーザはプロトスキーマのプロパティに基づいて問い合せできます。

Query は、 ProtoStreamMarshaller の設定時に設定できるproto定義に基づいて構築されます。上記のいずれのシリアライズ方法でも、起動時に自動的にスキーマをサーバに登録し、リモートの Infinispan サーバーに保存されているオブジェクトを問い合せる機能を自動的に得られます。

詳細は Infinispan のドキュメント 問い合せ を参照してください。

Quarkus Infinispanクライアントエクステンションでは、Query DSLまたはIckle Query 言語のいずれかを使用できます。

カウンター

Infinispanにはカウンターという概念もあり、Quarkus Infinispanのクライアントはそれらもサポートしています。

The Quarkus Infinispan client extension allows for Dependency Injection of the CounterManager directly. All you need to do is annotate your field, constructor or method, and you get it with no fuss. You can then use counters as you would normally.

@Inject
CounterManager counterManager;

詳細は Infinispan のドキュメント クラスタカウンタ を参照してください。

ニアキャッシング

ニア・キャッシングは既定では無効になっていますが、プロファイル構成プロパティ quarkus.infinispan-client.near-cache-max-entries を 0 より大きい値に設定することで有効にできます。 また、正規表現を構成して、quarkus.infinispan-client.near-cache-name-pattern 属性を通じたキャッシュの一部のみニア・キャッシングを適用できます。

暗号化

この時点での暗号化には、作業を開始するための追加のステップが必要です。

最初のステップは、 hotrod-client.properties ファイルがトラストストアおよび/またはキーストアを指すように設定することです。これについては、 ここで さらに詳しく説明します。

The Infinispan Client extension enables SSL/TLS by default. You can read more about this at Using SSL With Native Executables.

追加機能

The Infinispan Client has additional features that were not mentioned here. This means this feature was not tested in a Quarkus environment, and they may or may not work. Please let us know if you need these added!

Dev Services for Infinispan

When you use the infinispan-client extension in dev mode or in test, Quarkus automatically starts an Infinispan server and configure your application.

Enabling / Disabling Dev Services for Infinispan

Dev Services for Infinispan is automatically enabled unless:

  • quarkus.infinispan-client.devservices.enabled is set to false

  • the quarkus.infinispan-client.server-list is configured

Dev Services for Infinispan relies on Docker to start the broker. If your environment does not support Docker, you will need to start the broker manually, or connect to an already running broker. You can configure the broker address using quarkus.infinispan-client.server-list.

共有サーバー

Quarkus will share the Infinispan broker if you have multiple applications running in dev mode. Dev Services for Infinispan implements a service discovery mechanism for your multiple Quarkus applications running in dev mode to share a single broker.

Dev Services for Infinispan starts the container with the quarkus-dev-service-infinispan label which is used to identify the container.

If you need multiple (shared) Infinispan server, you can configure the quarkus.infinispan-client.devservices.service-name attribute and indicate the server name. It looks for a container with the same value, or starts a new one if none can be found. The default service name is infinispan.

Sharing is enabled by default in dev mode, but disabled in test mode. You can disable the sharing with quarkus.infinispan-client.devservices.shared=false.

ポートの設定

By default, Dev Services for Infinispan picks a random port and configures the application. You can set the port by configuring the quarkus.infinispan-client.devservices.port property.

Testing helpers

To start an Infinispan Server for your unit tests, Quarkus provides one QuarkusTestResourceLifecycleManager that relies on Infinispan Server Test Container.

  • io.quarkus.test.infinispan.client.InfinispanTestResource will start a single instance on port 11222 with user 'admin' and password 'password'.

To use them, you need to add the io.quarkus:quarkus-test-infinispan-client dependency to your pom.xml.

For more information about the usage of a QuarkusTestResourceLifecycleManager please read Quarkus test resource.

設定リファレンス

ビルド時に固定される設定プロパティ - それ以外の設定プロパティは実行時に上書き可能

Configuration property

タイプ

デフォルト

If DevServices has been explicitly enabled or disabled. DevServices is generally enabled by default, unless there is an existing configuration present. When DevServices is enabled Quarkus will attempt to automatically configure and start a database when running in Dev or Test mode and when Docker is running.

Environment variable: QUARKUS_INFINISPAN_CLIENT_DEVSERVICES_ENABLED

boolean

true

Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly.

Environment variable: QUARKUS_INFINISPAN_CLIENT_DEVSERVICES_PORT

int

Indicates if the Infinispan server managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for Infinispan starts a new container. The discovery uses the quarkus-dev-service-infinispan label. The value is configured using the service-name property. Container sharing is only used in dev mode.

Environment variable: QUARKUS_INFINISPAN_CLIENT_DEVSERVICES_SHARED

boolean

true

The value of the quarkus-dev-service-infinispan label attached to the started container. This property is used when shared is set to true. In this case, before starting a container, Dev Services for Infinispan looks for a container with the quarkus-dev-service-infinispan label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it starts a new container with the quarkus-dev-service-infinispan label set to the specified value. This property is used when you need multiple shared Infinispan servers.

Environment variable: QUARKUS_INFINISPAN_CLIENT_DEVSERVICES_SERVICE_NAME

string

infinispan

List of the artifacts to automatically download and add to the Infinispan server libraries. For example a Maven coordinate (org.postgresql:postgresql:42.3.1) or a dependency location url. If an invalid value is passed, the Infinispan server will throw an error when trying to start.

Environment variable: QUARKUS_INFINISPAN_CLIENT_DEVSERVICES_ARTIFACTS

list of string

Whether a health check is published in case the smallrye-health extension is present.

Environment variable: QUARKUS_INFINISPAN_CLIENT_HEALTH_ENABLED

boolean

true

Sets the bounded entry count for near cache. If this value is 0 or less near cache is disabled.

Environment variable: QUARKUS_INFINISPAN_CLIENT_NEAR_CACHE_MAX_ENTRIES

int

0

Sets the host name/port to connect to. Each one is separated by a semicolon (eg. host1:11222;host2:11222).

Environment variable: QUARKUS_INFINISPAN_CLIENT_SERVER_LIST

string

Enables or disables Protobuf generated schemas upload to the server. Set it to 'false' when you need to handle the lifecycle of the Protobuf Schemas on Server side yourself. Default is 'true'.

Environment variable: QUARKUS_INFINISPAN_CLIENT_USE_SCHEMA_REGISTRATION

boolean

true

Sets client intelligence used by authentication Available values: * BASIC - Means that the client doesn’t handle server topology changes and therefore will only use the list of servers supplied at configuration time. * TOPOLOGY_AWARE - Use this provider if you don’t want the client to present any certificates to the remote TLS host. * HASH_DISTRIBUTION_AWARE - Like TOPOLOGY_AWARE but with the additional advantage that each request involving keys will be routed to the server who is the primary owner which improves performance greatly. This is the default.

Environment variable: QUARKUS_INFINISPAN_CLIENT_CLIENT_INTELLIGENCE

string

HASH_DISTRIBUTION_AWARE

Enables or disables authentication. Set it to false when connecting to an Infinispan Server without authentication. deployments. Default is 'true'.

Environment variable: QUARKUS_INFINISPAN_CLIENT_USE_AUTH

boolean

true

Sets username used by authentication.

Environment variable: QUARKUS_INFINISPAN_CLIENT_AUTH_USERNAME

string

Sets password used by authentication

Environment variable: QUARKUS_INFINISPAN_CLIENT_AUTH_PASSWORD

string

Sets realm used by authentication

Environment variable: QUARKUS_INFINISPAN_CLIENT_AUTH_REALM

string

default

Sets server name used by authentication

Environment variable: QUARKUS_INFINISPAN_CLIENT_AUTH_SERVER_NAME

string

infinispan

Sets client subject, necessary for those SASL mechanisms which require it to access client credentials.

Environment variable: QUARKUS_INFINISPAN_CLIENT_AUTH_CLIENT_SUBJECT

string

Specifies a CallbackHandler to be used during the authentication handshake. The `Callback`s that need to be handled are specific to the chosen SASL mechanism.

Environment variable: QUARKUS_INFINISPAN_CLIENT_AUTH_CALLBACK_HANDLER

string

Sets SASL mechanism used by authentication. Available values: * DIGEST-MD5 - Uses the MD5 hashing algorithm in addition to nonces to encrypt credentials. This is the default. * EXTERNAL - Uses client certificates to provide valid identities to Infinispan Server and enable encryption. * PLAIN - Sends credentials in plain text (unencrypted) over the wire in a way that is similar to HTTP BASIC authentication. You should use PLAIN authentication only in combination with TLS encryption.

Environment variable: QUARKUS_INFINISPAN_CLIENT_SASL_MECHANISM

string

DIGEST-MD5

Specifies the filename of a truststore to use to create the SSLContext. You also need to specify a trustStorePassword. Setting this property implicitly enables SSL/TLS.

Environment variable: QUARKUS_INFINISPAN_CLIENT_TRUST_STORE

string

Specifies the password needed to open the truststore You also need to specify a trustStore. Setting this property implicitly enables SSL/TLS.

Environment variable: QUARKUS_INFINISPAN_CLIENT_TRUST_STORE_PASSWORD

string

Specifies the type of the truststore, such as JKS or JCEKS. Defaults to JKS if trustStore is enabled.

Environment variable: QUARKUS_INFINISPAN_CLIENT_TRUST_STORE_TYPE

string