What's?
Open Libertyには、Open Liberty上でのSpring Bootの実行をサポートするフィーチャーがあるようです。
どういうこと?と思ったので、調べるついでに試してみることにしました。
今回はSpring BootアプリケーションをOpen Liberty上で動かすことにフォーカスするので、Spring BootおよびOpen Libertyについては簡単に紹介するだけにします。
Spring Boot?
Spring Bootは、Springベースのアプリケーションを簡単に作成できるフレームワークです。
Open Liberty?
Open Libertyは、IBMの開発しているJava EE/Jakarta EEのアプリケーションサーバであるWebSphere LibertyのOSS版です。
Open Libertyとはコア部分が同じで、機能追加したものがWebSphere Libertyだと考えればよさそうです。
What is the relationship between Open Liberty and WebSphere Liberty?
このあたりは以下でも書きました。
Open LibertyのSpring Bootサポート
Spring BootアプリケーションをOpen Libertyにデプロイすることに関するページはこちらです。
このページを見ると、以下のようなことが書かれています。
- Open LibertyにはSpring Bootをサポートするフィーチャーがある
- Open LibertyにSpring Bootアプリケーションをデプロイすると、アプリケーション側のWebコンテナを無効にして代わりにOpen LibertyのWebコンテナを使用する
- JAR、WARどちらの形式でもSpring Bootアプリケーションをデプロイ可能
-
springBootUtility thin
コマンドを使うことで、効率的なDockerイメージを生成できる
Spring Bootサポートフィーチャーのリファレンスページはこちら。
こちらを見ると、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種類があるようです。
現在の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のこちらのガイドをベースにして
Open Libertyにデプロイするガイドもあります。こちらではDockerイメージの作成まで行います。
今回は簡単なSpring Bootアプリケーションを作成し、Open Libertyにデプロイ、Uber JARとして実行するところまでやってみようと思います。
環境
今回の環境はこちらです。
$ 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
のみにします。
$ 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プロジェクトです。
$ 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 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を作成します。
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");
}
}
確認。
$ mvn spring-boot:run
$ curl localhost:8080/hello
Hello World!!
$ curl 'localhost:8080/hello?word=Spring+Boot'
Hello Spring Boot!!
Spring BootアプリケーションをOpen Libertyで動かしてみる
作成したSpring BootアプリケーションをOpen Libertyで動かしてみます。
フィーチャーのリファレンスやガイドを参考に
こんな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
を有効にしました。
<featureManager>
<feature>servlet-6.0</feature>
<feature>springBoot-3.0</feature>
</featureManager>
springBootApplication
のlocation
にはSpring BootアプリケーションのUber JARファイルの名前を指定すればよさそうです。
<springBootApplication location="spring-boot-open-liberty-0.0.1-SNAPSHOT.jar" />
続いて、pom.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
ゴールも実行してみましたが、あんまり意味がなさそうでした
$ mvn package liberty:run -DskipTests
起動。
[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 秒で始動しました。
指定したフィーチャーが有効になっています。
サーバーは次のフィーチャーをインストールしました。[servlet-6.0, springBoot-3.0]。
Open LibertyのHTTPポートは9080で指定しているので
<httpEndpoint id="defaultHttpEndpoint"
httpPort="9080"
httpsPort="9443" />
こちらで確認。
$ curl localhost:9080/hello
Hello World!!
$ curl 'localhost:9080/hello?word=Spring+Boot'
Hello Spring Boot!!
OKですね。
package
ゴールを実行しているのでUber JARも生成されており、こちらでも実行できます。
$ 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コンテナを使用する」という話がありました。
こちらを確認してみましょう。
RestControllerのメソッド内で、スタックトレースを出力するように変更します。
@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");
}
起動。
$ mvn package liberty:run -DskipTests
アクセスしてみます。
$ curl localhost:9080/hello
この時に得られたスタックトレースはこちら。
[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)
なんの上で動いているのかわかりませんね!
[INFO] [err] at [internal classes]
ただ、こういうのを見るとOpen Libertyの上で動いているんだなという気がします。
[INFO] [err] at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:203)
ちなみに、通常のSpring Bootアプリケーションとして動かしてスタックトレースを取得するとこうなります。
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の設定を、いきなりこんな感じで追加していました。
<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
ゴールを実行するように設定しています。
<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
コマンドで実行可能にする、といった感じです。
続いてこの部分。
<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のランタイムを指定しています。最小構成のカーネルを選択して、あとは必要なものをフィーチャーとしてインストールします。
<runtimeArtifact>
<groupId>io.openliberty</groupId>
<artifactId>openliberty-kernel</artifactId>
<version>24.0.0.11</version>
<type>zip</type>
</runtimeArtifact>
こちらの設定は、Spring Bootサポートに関するページを見た方がよさそうです。
<appsDirectory>apps</appsDirectory>
<deployPackages>spring-boot-project</deployPackages>
<include>minify,runnable</include>
<packageName>${project.build.finalName}-wlp</packageName>
appsDirectory
はapps
ディレクトリにコピーするようにしています。これはデフォルト値で、他に選択できるのはdropins
です。
deployPackages
はOpen Libertyランタイムのアプリケーションディレクトリにコピーするパッケージを表していて、Spring Bootアプリケーションの場合はspring-boot-project
を選択します。
include
はminify,runnable
を指定すればよさそうです。
packageName
はビルド結果のパッケージ名を指定します。
<packageName>${project.build.finalName}-wlp</packageName>
デフォルト値は${project.build.finalName}
でSpring Boot Maven Pluginで作成したUber JARが置き換えられるのですが、今回は別名を指定しています。
Spring Boot Maven Pluginで作成したJARファイルとのサイズ差はこんな感じですね。
$ 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
コメントアウトして
<!--
<packageName>${project.build.finalName}-wlp</packageName>
-->
再度パッケージングすると
$ mvn clean package -DskipTests
Spring Boot Maven Pluginで作成したUber JARが置き換えられました。
$ 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で動かしてみました。