Spring BootアプリケーションをOpen Libertyで動かしてみる

# What's？

Open Libertyには、Open Liberty上でのSpring Bootの実行をサポートするフィーチャーがあるようです。

どういうこと？と思ったので、調べるついでに試してみることにしました。

今回はSpring BootアプリケーションをOpen Liberty上で動かすことにフォーカスするので、Spring BootおよびOpen Libertyについては簡単に紹介するだけにします。

# Spring Boot？

Spring Bootは、Springベースのアプリケーションを簡単に作成できるフレームワークです。

https://spring.io/projects/spring-boot

# Open Liberty？

Open Libertyは、IBMの開発しているJava EE／Jakarta EEのアプリケーションサーバであるWebSphere LibertyのOSS版です。

https://openliberty.io/

Open Libertyとはコア部分が同じで、機能追加したものがWebSphere Libertyだと考えればよさそうです。

> What is the relationship between Open Liberty and WebSphere Liberty?

https://www.ibm.com/products/cloud-pak-for-applications/liberty

このあたりは以下でも書きました。

https://qiita.com/charon/items/5763441104e7dca52074

# Open LibertyのSpring Bootサポート

Spring BootアプリケーションをOpen Libertyにデプロイすることに関するページはこちらです。

https://openliberty.io/docs/24.0.0.11/deploy-spring-boot.html

このページを見ると、以下のようなことが書かれています。

- Open LibertyにはSpring Bootをサポートするフィーチャーがある
- Open LibertyにSpring Bootアプリケーションをデプロイすると、アプリケーション側のWebコンテナを無効にして代わりにOpen LibertyのWebコンテナを使用する
- JAR、WARどちらの形式でもSpring Bootアプリケーションをデプロイ可能
- `springBootUtility thin`コマンドを使うことで、効率的なDockerイメージを生成できる 

Spring Bootサポートフィーチャーのリファレンスページはこちら。

https://openliberty.io/docs/24.0.0.11/reference/feature/springBoot-3.0.html

こちらを見ると、Spring Web MVCおよびSpring WebFluxを対象とするフィーチャーのようです。  
また`spring-boot-starter-security`などを組み込むと、Open Libertyが提供するフィーチャーではなくSpring Boot Starterが提供する機能を使うようになるようです。

Spring Bootサポートフィーチャーには、Spring Boot 3.0.4以上に対応する`springBoot-3.0`、Spring Boot 2.0.1以上に対応する`springBoot-2.0`、Spring Boot 1.5.8に対応する`springBoot-1.5`の3種類があるようです。

https://www.ibm.com/docs/ja/was-liberty/nd?topic=SSAW57_liberty/com.ibm.websphere.wlp.core.doc/ae/twlp_dep_springboot.htm

現在のSpring BootでEOLになっていないのはSpring Boot 3.3以上になるので、今回は`springBoot-3.0`を使います。

`springBoot-3.0`がサポートするSpring Boot Starterは以下のとおりです。

| Spring Boot Starter | 対応するOpen Libertyフィーチャー |
|:--------------------|:------------------------------|
| spring-boot-starter | springBoot-3.0 |
| spring-boot-starter-web | springBoot-3.0、servlet-6.0、servlet-6.1、pages-3.0 |
| spring-boot-starter-websocket | springBoot-3.0、websocket-2.0 |
| spring-boot-starter-webflux | springBoot-3.0、servlet-6.0、servlet-6.1、pages-3.0 |

対応するフィーチャーは、Open Libertyの`server.xml`で有効にする必要があります。

これを見ると、Spring WebFluxも含めてJakarta Servlet上での実行をサポートするみたいですね。

`springBoot-3.0`はJava 17、21、23をサポートしています。

またSpring Bootのこちらのガイドをベースにして

https://spring.io/guides/gs/spring-boot

Open Libertyにデプロイするガイドもあります。こちらではDockerイメージの作成まで行います。

https://openliberty.io/guides/spring-boot.html

今回は簡単なSpring Bootアプリケーションを作成し、Open Libertyにデプロイ、Uber JARとして実行するところまでやってみようと思います。

# 環境

今回の環境はこちらです。

```shell
$ java --version
openjdk 17.0.13 2024-10-15
OpenJDK Runtime Environment (build 17.0.13+11-Ubuntu-2ubuntu124.04)
OpenJDK 64-Bit Server VM (build 17.0.13+11-Ubuntu-2ubuntu124.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /home/charon/.sdkman/candidates/maven/current
Java version: 17.0.13, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-49-generic", arch: "amd64", family: "unix"
```

# Spring Bootアプリケーションを作成する

まずはSpring Bootアプリケーションを作成しましょう。今回使用する依存関係は単純に`web`のみにします。

```shell
$ curl -s https://start.spring.io/starter.tgz \
  -d bootVersion=3.4.0 \
  -d javaVersion=17 \
  -d type=maven-project \
  -d name=spring-boot-open-liberty \
  -d groupId=com.example \
  -d artifactId=spring-boot-open-liberty \
  -d version=0.0.1-SNAPSHOT \
  -d packageName=com.example.app \
  -d dependencies=web \
  -d baseDir=spring-boot-open-liberty | tar zxvf -
```

ふつうのSpring Bootプロジェクトです。

```shell
$ cd spring-boot-open-liberty
$ tree -a
.
├── .gitattributes
├── .gitignore
├── .mvn
│   └── wrapper
│       └── maven-wrapper.properties
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── app
    │   │               └── SpringBootOpenLibertyApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── example
                    └── app
                        └── SpringBootOpenLibertyApplicationTests.java

17 directories, 10 files
```

```xml: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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>3.4.0</version>
                <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>spring-boot-open-liberty</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>spring-boot-open-liberty</name>
        <description>Demo project for Spring Boot</description>
        <url/>
        <licenses>
                <license/>
        </licenses>
        <developers>
                <developer/>
        </developers>
        <scm>
                <connection/>
                <developerConnection/>
                <tag/>
                <url/>
        </scm>
        <properties>
                <java.version>17</java.version>
        </properties>
        <dependencies>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                </dependency>

                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                        <scope>test</scope>
                </dependency>
        </dependencies>

        <build>
                <plugins>
                        <plugin>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-maven-plugin</artifactId>
                        </plugin>
                </plugins>
        </build>

</project>
```

簡単なRestControllerを作成します。

```java:src/main/java/com/example/app/HelloController.java
package com.example.app;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping(value = "/hello", produces = {"text/plain"})
    public String message(@RequestParam(required = false) String word) {
        return String.format("Hello %s!!", word != null ? word : "World");
    }
}
```

確認。

```shell
$ mvn spring-boot:run
```

```shell
$ curl localhost:8080/hello
Hello World!!


$ curl 'localhost:8080/hello?word=Spring+Boot'
Hello Spring Boot!!
```

# Spring BootアプリケーションをOpen Libertyで動かしてみる

作成したSpring BootアプリケーションをOpen Libertyで動かしてみます。

フィーチャーのリファレンスやガイドを参考に

https://openliberty.io/docs/24.0.0.11/reference/feature/springBoot-3.0.html

https://openliberty.io/guides/spring-boot.html

こんな`server.xml`を作成。

```xml:src/main/liberty/config/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>servlet-6.0</feature>
        <feature>springBoot-3.0</feature>
    </featureManager>

    <httpEndpoint id="defaultHttpEndpoint"
                  httpPort="9080"
                  httpsPort="9443" />

    <springBootApplication location="spring-boot-open-liberty-0.0.1-SNAPSHOT.jar" />

    <ssl id="defaultSSLConfig" trustDefaultCerts="true" />
</server>
```

フィーチャーは、`springBoot-3.0`と`servlet-6.0`を有効にしました。

```xml
    <featureManager>
        <feature>servlet-6.0</feature>
        <feature>springBoot-3.0</feature>
    </featureManager>
```

`springBootApplication`の`location`にはSpring BootアプリケーションのUber JARファイルの名前を指定すればよさそうです。

```xml
    <springBootApplication location="spring-boot-open-liberty-0.0.1-SNAPSHOT.jar" />
```

続いて、`pom.xml`に以下の設定を追加。

```xml
                        <plugin>
                                <groupId>io.openliberty.tools</groupId>
                                <artifactId>liberty-maven-plugin</artifactId>
                                <version>3.11.1</version>
                                <executions>
                                        <execution>
                                                <id>package-server</id>
                                                <phase>package</phase>
                                                <goals>
                                                        <goal>create</goal>
                                                        <goal>install-feature</goal>
                                                        <goal>deploy</goal>
                                                        <goal>package</goal>
                                                </goals>
                                        </execution>
                                </executions>
                                <configuration>
                                        <runtimeArtifact>
                                                <groupId>io.openliberty</groupId>
                                                <artifactId>openliberty-kernel</artifactId>
                                                <version>24.0.0.11</version>
                                                <type>zip</type>
                                        </runtimeArtifact>
                                        <appsDirectory>apps</appsDirectory>
                                        <deployPackages>spring-boot-project</deployPackages>
                                        <include>minify,runnable</include>
                                        <packageName>${project.build.finalName}-wlp</packageName>
                                </configuration>
                        </plugin>
```

説明はまた後で。

ひとまずパッケージングして起動してみます。  
※`liberty:dev`ゴールも実行してみましたが、あんまり意味がなさそうでした

```shell
$ mvn package liberty:run -DskipTests
```

起動。

```shell
[INFO]   .   ____          _            __ _ _
[INFO]  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[INFO] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[INFO]  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[INFO]   '  |____| .__|_| |_|_| |_\__, | / / / /
[INFO]  =========|_|==============|___/=/_/_/_/
[INFO]  :: Spring Boot ::                (v3.4.0)
[INFO] 2024-11-30T14:02:52.833+09:00  INFO 18368 --- [spring-boot-open-liberty] [ecutor-thread-2] c.e.a.SpringBootOpenLibertyApplication   : Starting SpringBootOpenLibertyApplication using Java 17.0.13 with PID 18368 (/home/charon/spring-boot-open-liberty/target/liberty/wlp/usr/servers/defaultServer/apps/thin-spring-boot-open-liberty-0.0.1-SNAPSHOT.jar started by charon in /home/charon/spring-boot-open-liberty/target/liberty/wlp/usr/servers/defaultServer)
[INFO] 2024-11-30T14:02:52.837+09:00  INFO 18368 --- [spring-boot-open-liberty] [ecutor-thread-2] c.e.a.SpringBootOpenLibertyApplication   : No active profile set, falling back to 1 default profile: "default"
[INFO] [監査      ] CWWKT0016I: Web アプリケーションが使用可能です (default_host): http://localhost:9080/
[INFO] 2024-11-30T14:02:54.371+09:00  INFO 18368 --- [spring-boot-open-liberty] [ecutor-thread-6] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1449 ms
[INFO] 2024-11-30T14:02:54.857+09:00  INFO 18368 --- [spring-boot-open-liberty] [ecutor-thread-2] c.e.a.SpringBootOpenLibertyApplication   : Started SpringBootOpenLibertyApplication in 2.725 seconds (process running for 4.516)
[INFO] [監査      ] CWWKZ0001I: アプリケーション spring-boot-open-liberty が 3.351 秒で開始しました。
[INFO] [監査      ] CWWKF0012I: サーバーは次のフィーチャーをインストールしました。[servlet-6.0, springBoot-3.0]。
[INFO] [監査      ] CWWKF0011I: defaultServer サーバーは、Smarter Planet に対応する準備ができました。defaultServer サーバーは 4.487 秒で始動しました。
```

指定したフィーチャーが有効になっています。

```shell
サーバーは次のフィーチャーをインストールしました。[servlet-6.0, springBoot-3.0]。
```

Open LibertyのHTTPポートは9080で指定しているので

```xml
    <httpEndpoint id="defaultHttpEndpoint"
                  httpPort="9080"
                  httpsPort="9443" />
```

こちらで確認。

```shell
$ curl localhost:9080/hello
Hello World!!


$ curl 'localhost:9080/hello?word=Spring+Boot'
Hello Spring Boot!!
```

OKですね。

`package`ゴールを実行しているのでUber JARも生成されており、こちらでも実行できます。

```shell
$ java -jar target/spring-boot-open-liberty-0.0.1-SNAPSHOT-wlp.jar
```

確認結果は省略します。

ひとまず動かすところはできました。

# もうちょっと確認

Spring BootアプリケーションをOpen Liberty上で動かせたので、もう少し気になるところを見ていきたいと思います。

## なんの上で動いているのか？

Spring BootアプリケーションをOpen Libertyにデプロイするページの説明で、「Open LibertyにSpring Bootアプリケーションをデプロイすると、アプリケーション側のWebコンテナを無効にして代わりにOpen LibertyのWebコンテナを使用する」という話がありました。

https://openliberty.io/docs/24.0.0.11/deploy-spring-boot.html

こちらを確認してみましょう。

RestControllerのメソッド内で、スタックトレースを出力するように変更します。

```java
    @GetMapping(value = "/hello", produces = {"text/plain"})
    public String message(@RequestParam(required = false) String word) {
        Thread.dumpStack();
        return String.format("Hello %s!!", word != null ? word : "World");
    }
```

起動。

```shell
$ mvn package liberty:run -DskipTests
```

アクセスしてみます。

```shell
$ curl localhost:9080/hello
```

この時に得られたスタックトレースはこちら。

```shell
[INFO] [err] java.lang.Exception: Stack trace
[INFO] [err]    at java.base/java.lang.Thread.dumpStack(Thread.java:1389)
[INFO] [err]    at com.example.app.HelloController.message(HelloController.java:11)
[INFO] [err]    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[INFO] [err]    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
[INFO] [err]    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[INFO] [err]    at java.base/java.lang.reflect.Method.invoke(Method.java:569)
[INFO] [err]    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)
[INFO] [err]    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
[INFO] [err]    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
[INFO] [err]    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986)
[INFO] [err]    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891)
[INFO] [err]    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
[INFO] [err]    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088)
[INFO] [err]    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978)
[INFO] [err]    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
[INFO] [err]    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
[INFO] [err]    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
[INFO] [err]    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
[INFO] [err]    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
[INFO] [err]    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
[INFO] [err]    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:203)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
[INFO] [err]    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
[INFO] [err]    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:203)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
[INFO] [err]    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
[INFO] [err]    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:203)
[INFO] [err]    at [internal classes]
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
[INFO] [err]    at java.base/java.lang.Thread.run(Thread.java:840)
```

なんの上で動いているのかわかりませんね！

```shell
[INFO] [err]    at [internal classes]
```

ただ、こういうのを見るとOpen Libertyの上で動いているんだなという気がします。

```shell
[INFO] [err]    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:203)
```

ちなみに、通常のSpring Bootアプリケーションとして動かしてスタックトレースを取得するとこうなります。

```shell
java.lang.Exception: Stack trace
        at java.base/java.lang.Thread.dumpStack(Thread.java:1389)
        at com.example.app.HelloController.message(HelloController.java:11)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:569)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
        at java.base/java.lang.Thread.run(Thread.java:840)
```

## Liberty Maven Pluginの設定？

Liberty Maven Pluginの設定を、いきなりこんな感じで追加していました。

```xml
                        <plugin>
                                <groupId>io.openliberty.tools</groupId>
                                <artifactId>liberty-maven-plugin</artifactId>
                                <version>3.11.1</version>
                                <executions>
                                        <execution>
                                                <id>package-server</id>
                                                <phase>package</phase>
                                                <goals>
                                                        <goal>create</goal>
                                                        <goal>install-feature</goal>
                                                        <goal>deploy</goal>
                                                        <goal>package</goal>
                                                </goals>
                                        </execution>
                                </executions>
                                <configuration>
                                        <runtimeArtifact>
                                                <groupId>io.openliberty</groupId>
                                                <artifactId>openliberty-kernel</artifactId>
                                                <version>24.0.0.11</version>
                                                <type>zip</type>
                                        </runtimeArtifact>
                                        <appsDirectory>apps</appsDirectory>
                                        <deployPackages>spring-boot-project</deployPackages>
                                        <include>minify,runnable</include>
                                        <packageName>${project.build.finalName}-wlp</packageName>
                                </configuration>
                        </plugin>
```

ここを少し見ていきたいと思います。

こちらは、`package`ゴールを実行する時にLiberty Maven Pluginの`create`、`install-feature`、`package`ゴールを実行するように設定しています。

```xml
                                <executions>
                                        <execution>
                                                <id>package-server</id>
                                                <phase>package</phase>
                                                <goals>
                                                        <goal>create</goal>
                                                        <goal>install-feature</goal>
                                                        <goal>deploy</goal>
                                                        <goal>package</goal>
                                                </goals>
                                        </execution>
                                </executions>
```

簡単に言うと、Open Libertyサーバを作成 → 必要なフィーチャーをインストール → アプリケーションをデプロイ → パッケージングして`java -jar`コマンドで実行可能にする、といった感じです。

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/create.md

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/install-feature.md

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/deploy.md

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/package.md

続いてこの部分。

```xml
                                <configuration>
                                        <runtimeArtifact>
                                                <groupId>io.openliberty</groupId>
                                                <artifactId>openliberty-kernel</artifactId>
                                                <version>24.0.0.11</version>
                                                <type>zip</type>
                                        </runtimeArtifact>
                                        <appsDirectory>apps</appsDirectory>
                                        <deployPackages>spring-boot-project</deployPackages>
                                        <include>minify,runnable</include>
                                        <packageName>${project.build.finalName}-wlp</packageName>
                                </configuration>
```

こちらは使用するOpen Libertyのランタイムを指定しています。最小構成のカーネルを選択して、あとは必要なものをフィーチャーとしてインストールします。

```xml
                                        <runtimeArtifact>
                                                <groupId>io.openliberty</groupId>
                                                <artifactId>openliberty-kernel</artifactId>
                                                <version>24.0.0.11</version>
                                                <type>zip</type>
                                        </runtimeArtifact>
```

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/installation-configuration.md

こちらの設定は、Spring Bootサポートに関するページを見た方がよさそうです。

```xml
                                        <appsDirectory>apps</appsDirectory>
                                        <deployPackages>spring-boot-project</deployPackages>
                                        <include>minify,runnable</include>
                                        <packageName>${project.build.finalName}-wlp</packageName>
```

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/spring-boot-support.md

`appsDirectory`は`apps`ディレクトリにコピーするようにしています。これはデフォルト値で、他に選択できるのは`dropins`です。

`deployPackages`はOpen Libertyランタイムのアプリケーションディレクトリにコピーするパッケージを表していて、Spring Bootアプリケーションの場合は`spring-boot-project`を選択します。

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/deploy.md

`include`は`minify,runnable`を指定すればよさそうです。

https://github.com/OpenLiberty/ci.maven/blob/liberty-maven-3.11.1/docs/package.md

https://openliberty.io/guides/spring-boot.html

`packageName`はビルド結果のパッケージ名を指定します。

```xml
                                        <packageName>${project.build.finalName}-wlp</packageName>
```

デフォルト値は`${project.build.finalName}`でSpring Boot Maven Pluginで作成したUber JARが置き換えられるのですが、今回は別名を指定しています。

Spring Boot Maven Pluginで作成したJARファイルとのサイズ差はこんな感じですね。

```shell
$ ll -h target/*.jar
-rw-rw---- 1 charon charon 45M 11月 30 14:09 target/spring-boot-open-liberty-0.0.1-SNAPSHOT-wlp.jar
-rw-rw-r-- 1 charon charon 20M 11月 30 14:09 target/spring-boot-open-liberty-0.0.1-SNAPSHOT.jar
```

コメントアウトして

```xml
					<!--
					<packageName>${project.build.finalName}-wlp</packageName>
					-->
```

再度パッケージングすると

```shell
$ mvn clean package -DskipTests
```

Spring Boot Maven Pluginで作成したUber JARが置き換えられました。

```shell
$ ll -h target/*.jar
-rw-rw-r-- 1 charon charon 45M 11月 30 19:25 target/spring-boot-open-liberty-0.0.1-SNAPSHOT.jar
```

こんなところでしょうか。

ということで、Spring BootをOpen Libertyで動かしてみました。