Eclipse MicroProfileを使ったマイクロサービスの構築

Eclipse MicroProfileを使用したマイクロサービスの構築

1. 概要

この記事では、EclipseMicroProfileに基づくマイクロサービスの構築に焦点を当てます。

JAX-RS、CDI、JSON-PAPIを使用してRESTfulWebアプリケーションを作成する方法を見ていきます。

2. マイクロサービスアーキテクチャ

簡単に言えば、マイクロサービスは、いくつかの独立したサービスの集合として完全なシステムを形成するソフトウェアアーキテクチャスタイルです。

それぞれが1つの機能的な境界に焦点を合わせ、RESTなどの言語に依存しないプロトコルを使用して他と通信します。

3. Eclipse MicroProfile

Eclipse MicroProfileは、Microservicesアーキテクチャー向けにEnterprise Javaを最適化することを目的としたイニシアチブです。 これはJavaEE WebProfile APIのサブセットに基づいているため、JavaEEアプリケーションと同じようにMicroProfileアプリケーションを構築できます。

MicroProfileの目標は、マイクロサービスを構築するための標準APIを定義し、複数のMicroProfileランタイムにわたってポータブルアプリケーションを提供することです。

4. Mavenの依存関係

Eclipse MicroProfileアプリケーションの構築に必要なすべての依存関係は、次のBOM(Bill Of Materials)依存関係によって提供されます。


    org.eclipse.microprofile
    microprofile
    1.2
    pom
    provided

MicroProfileランタイムにはすでにAPIと実装が含まれているため、スコープはprovidedとして設定されます。

5. 表現モデル

簡単なリソースクラスを作成することから始めましょう。

public class Book {
    private String id;
    private String name;
    private String author;
    private Integer pages;
    // ...
}

ご覧のとおり、このBookクラスにはアノテーションがありません。

6. CDIの使用

簡単に言えば、CDIは依存性注入とライフサイクル管理を提供するAPIです。 WebアプリケーションでのエンタープライズBeanの使用を簡素化します。

次に、本の表現のストアとしてCDIマネージドBeanを作成しましょう。

@ApplicationScoped
public class BookManager {

    private ConcurrentMap inMemoryStore
      = new ConcurrentHashMap<>();

    public String add(Book book) {
        // ...
    }

    public Book get(String id) {
        // ...
    }

    public List getAll() {
        // ...
    }
}

すべてのクライアントで状態が共有されるインスタンスが1つだけ必要なため、このクラスに@ApplicationScopedで注釈を付けます。 そのために、タイプセーフなメモリ内データストアとしてConcurrentMapを使用しました。 次に、CRUD操作のメソッドを追加しました。

これで、BeanはCDIに対応し、BeanBookEndpoint using@Injectアノテーションに注入できます。

7. JAX-RS API

JAX-RSでRESTアプリケーションを作成するには、@ApplicationPathで注釈が付けられたApplicationクラスと、@Path.で注釈が付けられたリソースを作成する必要があります。

7.1. JAX RSアプリケーション

JAX-RSアプリケーションは、Webアプリケーションでリソースを公開するベースURIを識別します。

次のJAX-RSアプリケーションを作成しましょう。

@ApplicationPath("/library")
public class LibraryApplication extends Application {
}

この例では、Webアプリケーション内のすべてのJAX-RSリソースクラスがLibraryApplicationに関連付けられており、同じlibraryパス(ApplicationPath annotation.の値)の下にあります。

この注釈付きクラスは、JAX RSランタイムに、リソースを自動的に見つけて公開するように伝えます。

7.2. JAXRSエンドポイント

Resourceクラスとも呼ばれるEndpointクラスは、1つのリソースを定義する必要がありますが、同じタイプの多くは技術的に可能です。

@Pathでアノテーションが付けられた、または@Path or @HttpMethodでアノテーションが付けられた少なくとも1つのメソッドを持つ各Javaクラスはエンドポイントです。

次に、その表現を公開するJAX-RSエンドポイントを作成します。

@Path("books")
@RequestScoped
public class BookEndpoint {

    @Inject
    private BookManager bookManager;

    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getBook(@PathParam("id") String id) {
        return Response.ok(bookManager.get(id)).build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllBooks() {
        return Response.ok(bookManager.getAll()).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response add(Book book) {
        String bookId = bookManager.add(book);
        return Response.created(
          UriBuilder.fromResource(this.getClass())
            .path(bookId).build())
            .build();
    }
}

この時点で、Webアプリケーションの/library/booksパスの下にあるBookEndpointリソースにアクセスできます。

7.3. JAX RSJSONメディアタイプ

JAX RSは、RESTクライアントと通信するための多くのメディアタイプをサポートしていますが、JSOP-P APIの使用を指定しているためEclipse MicroProfile restricts the use of JSONです。 そのため、メソッドに@Consumes(MediaType.APPLICATION_JSON)と@Produces(MediaType.APPLICATION_JSON).のアノテーションを付ける必要があります。

@Consumesアノテーションは、受け入れられる形式を制限します。この例では、JSONデータ形式のみが受け入れられます。 HTTPリクエストヘッダーContent-Typeapplication/jsonである必要があります。

同じ考えが@Producesアノテーションの背後にあります。 JAX RSランタイムは、JSON形式への応答をマーシャリングする必要があります。 リクエストHTTPヘッダーAcceptapplication/json.である必要があります

8. JSON-P

JAX RSランタイムはJSON-Pをすぐにサポートするため、メソッドの入力パラメーターまたは戻り値の型としてJsonObjectを使用できます。

しかし、現実の世界では、多くの場合、POJOクラスを使用します。 したがって、JsonObjectとPOJOの間のマッピングを行う方法が必要です。 ここで、JAXRSエンティティプロバイダーが活躍します。

JSON入力ストリームをBook POJOにマーシャリングするには、タイプBook,のパラメーターを使用してリソースメソッドを呼び出し、クラスBookMessageBodyReader:を作成する必要があります。

@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class BookMessageBodyReader implements MessageBodyReader {

    @Override
    public boolean isReadable(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType) {

        return type.equals(Book.class);
    }

    @Override
    public Book readFrom(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType,
      MultivaluedMap httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

        return BookMapper.map(entityStream);
    }
}

同じプロセスを実行して、BookをJSON出力ストリームにアンマーシャリングします。つまり、BookMessageBodyWriter:を作成して、戻り値の型がBook,であるリソースメソッドを呼び出します。

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class BookMessageBodyWriter
  implements MessageBodyWriter {

    @Override
    public boolean isWriteable(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType) {

        return type.equals(Book.class);
    }

    // ...

    @Override
    public void writeTo(
      Book book, Class type,
      Type genericType,
      Annotation[] annotations,
      MediaType mediaType,
      MultivaluedMap httpHeaders,
      OutputStream entityStream) throws IOException, WebApplicationException {

        JsonWriter jsonWriter = Json.createWriter(entityStream);
        JsonObject jsonObject = BookMapper.map(book);
        jsonWriter.writeObject(jsonObject);
        jsonWriter.close();
    }
}

BookMessageBodyReaderBookMessageBodyWriterには@Providerの注釈が付けられているため、JAXRSランタイムによって自動的に登録されます。

9. アプリケーションの構築と実行

MicroProfileアプリケーションは移植可能であり、準拠するMicroProfileランタイムで実行する必要があります。 アプリケーションをOpen Libertyでビルドして実行する方法を説明しますが、準拠しているEclipseMicroProfileを使用できます。

構成ファイルserver.xmlを使用してOpenLibertyランタイムを構成します。


    
        jaxrs-2.0
        cdi-1.2
        jsonp-1.0
    
    
    
    

プラグインliberty-maven-pluginをpom.xmlに追加しましょう:



    net.wasdev.wlp.maven.plugins
    liberty-maven-plugin
    2.1.2
    
        
            io.openliberty
            openliberty-runtime
            17.0.0.4
            zip
        
        ${basedir}/src/main/liberty/config/server.xml
        ${package.file}
        ${packaging.type}
        false
        project
        
            /
            ${project.artifactId}-${project.version}.war
            9080
            9443
        
    
    
        
            install-server
            prepare-package
            
                install-server
                create-server
                install-feature
            
        
        
            package-server-with-apps
            package
            
                install-apps
                package-server
            
        
    

このプラグインは、プロパティセットをスローするように構成可能です。


    
    library
    ${project.build.directory}/${app.name}-service.jar
    runnable

上記のexecの目標により、実行可能なjarファイルが生成されるため、アプリケーションは独立してデプロイおよび実行できる独立したマイクロサービスになります。 Dockerイメージとして展開することもできます。

実行可能jarを作成するには、次のコマンドを実行します。

mvn package

マイクロサービスを実行するには、次のコマンドを使用します。

java -jar target/library-service.jar

これにより、Open Libertyランタイムが開始され、サービスがデプロイされます。 エンドポイントにアクセスして、次のURLですべての書籍を取得できます。

curl http://localhost:9080/library/books

結果はJSONです:

[
  {
    "id": "0001-201802",
    "isbn": "1",
    "name": "Building Microservice With Eclipse MicroProfile",
    "author": "example",
    "pages": 420
  }
]

1冊の本を入手するには、次のURLをリクエストします。

curl http://localhost:9080/library/books/0001-201802

そして結果はJSONです:

{
    "id": "0001-201802",
    "isbn": "1",
    "name": "Building Microservice With Eclipse MicroProfile",
    "author": "example",
    "pages": 420
}

次に、APIを操作して新しい本を追加します。

curl
  -H "Content-Type: application/json"
  -X POST
  -d '{"isbn": "22", "name": "Gradle in Action","author": "example","pages": 420}'
  http://localhost:9080/library/books

ご覧のとおり、応答のステータスは201であり、ブックが正常に作成されたことを示しています。Locationは、ブックにアクセスできるURIです。

< HTTP/1.1 201 Created
< Location: http://localhost:9080/library/books/0009-201802

10. 結論

この記事では、Eclipse MicroProfileに基づいてシンプルなマイクロサービスを構築する方法を示し、JAX RS、JSON-P、およびCDIについて説明しました。

コードは利用可能ですover on Github;これはMavenベースのプロジェクトであるため、インポートしてそのまま実行するのは簡単です。