直近でWildFly 11でSpring Boot動かすのに調べたことのメモ。といっても、WildFlyプラスそのプロジェクト固有事情による設定とかの内容も混じっている。ただまぁ、自分用の作業ログなので余りそのへんは気にしない。
ソースコード
https://github.com/kagamihoge/wildflyspringboot
環境
とりあえず動かす
とりあえず https://projects.spring.io/spring-boot/#quick-start コピペして動かす。
<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kagamihoge</groupId> <artifactId>wildflyspringboot</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <name>wildflyspringboot</name> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
package com.kagamihoge.wildflyspringboot.controller; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @EnableAutoConfiguration public class SampleController { @RequestMapping("/") @ResponseBody String home() { return "Hello World!"; } public static void main(String[] args) throws Exception { SpringApplication.run(SampleController.class, args); } }
起動して http://localhost:8080/ でアクセスできるのを確認する。
Automatic restart
ソースコード編集すると自動反映されるヤツをいれる。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
組み込みサーバーをUndertowにする
73.13 Use Undertow instead of Tomcat
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>
Thymeleaf
Spring Boot で Thymeleaf 使い方メモを参考に設定。
warの生成とdynamic web projectとしても実行できるようにする
Spring Bootをeclipseのdynamic web projectとして実行する - kagamihogeの日記
最終的な成果物はwar
になるので変更する。また、プロジェクト固有の事情で、Eclipseのserverビューから起動するヤツも併用可能にした。
finalName
このままmvn package
とかするとwildflyspringboot-0.0.1-SNAPSHOT.war
みたいな名前のwarになる。なのでpom.xmlにfinalNameを指定する。
<build> <finalName>wildflyspringboot</finalName> ... </build>
コンテキストパス
warの名前と合わせるために、組み込みコンテナで起動したときにもhttp://localhost:8080/wildflyspringboot/
みたいなコンテキストパスでアクセスさせる。
src/main/resources/application.yml を作成して以下を追加する。
server: contextPath: /wildflyspringboot
logging Per-deployment Loggingでlog4j
WildFlyのPer-deployment Loggingでlog4j
を使うのでsrc/main/resources/log4j.xml
を作成。今時log4jなのはプロジェクト固有事情。
組み込みコンテナでlog4が使えなかった
組み込みコンテナだとlog4jが動かなかった。あまり突っ込んで調査しなかったが、logbackは動くのでまぁいっかと妥協した。
プロパティファイル
spring-bootのプロファイルを使用してプロファイルを切り替え。とりあえず、ここでは以下の二種類のファイルを作ったとして話を進める。
/src/main/resources/ application-dev.yml application-procuction.yml
mavenのプロファイルでspring-bootのプロファイルを切り替える
プロジェクト固有事情でmavenのビルド時にプロパティファイルを切り替える必要があった。つまりmvn package -P production
とかやる。なのでmavenのプロファイルをspring-bootのプロファイルに連動させる必要があった。
更なる縛りプレイとして、政治的事情で、WildFlyをいじれない。単一war内で完結する必要がある。つまり、コマンドライン引数・JNDI・システムプロパティ・OS環境変数、でspring-bootのプロファイル指定が出来ない。ぶっちゃけかなり困った。
で、spring-bootのリファレンスExternalized Configurationを見て残ったのがServletContext
の初期化パラメータでプロファイルを指定する方法。詳細は Spring Bootでweb.xmlのcontext-param経由でspring.profiles.activeを指定 を参照。
まず、web.xmlのcontext-paramにspring-bootのプロファイルを指定する、mavenのプレースホルダを記述する。mavenビルド時にこのプレースホルダが、ビルド時に指定されたmavenのプロファイルで書き換えられる。これにより、mavenのプロファイルとspring-bootのプロファイルを連動した。
ぶっちゃけかなり面倒。いま思うとsprin-bootのプロファイルにこだわなくても良かったかなぁ……とも思う。
プロファイルの切り替え(動的webプロジェクト)
eclipseの動的webプロジェクトとして動かす場合、Servers -> WildFly -> Open launch configuration -> VM argumentsに-Dspring.profiles.active=dev
とか追加する。
プロファイルの切り替えのやり方は色々あるんで、とりあえず一例として。
データソース
まず依存性を追加する。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
WildFlyのJNDI経由の場合
Connection to a JNDI DataSource の通り、application-production.yml
に以下のような決め打ちのプロパティ名で設定を追加すると勝手にDataSourceを設定してくれる。
spring: datasource: jndi-name: java:/PostgresDS
組み込みコンテナ(Undertow)の場合
Tomcatとは異なりUndertowにはJNDIは無い。ので、DataSourceを自前で設定する。これも以下のような決め打ちのプロパティ名があるのでそれをapplication-dev.yml
に追加する。参照:29.1.2 Connection to a production database
spring: datasource: url: jdbc:postgresql://192.168.10.23:5432/testdb username: postgres password: a
PostgreSQLのjdbcドライバが無いって怒られるので、適当なバージョンのものをpom.xmlに追加する。
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.1.4</version> </dependency>
動作確認するにはDataSourceをDIしたり、JdbcTemplateをDIして適当なクエリを発行してみる。
@Autowired JdbcTemplate jdbcTemplate; int result1 =jdbcTemplate.queryForObject("select 1", Integer.class); logger.info("select 1="+result1);
validation
Spring Getting Started - Validating Form Inputあたりを参考に設定する。
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
@GetMapping("hello2") public String hello2(@RequestParam(name="param") @NotEmpty @NotNull String param) { logger.info("param=" + param); return "hello"; }
ユニットテスト
spring-framework上でのユニットテストはこれまで通り。spring-boot-starter-test
がspring-bootのテスト用ライブラリに加えてMockitoやらHamcrestやらメジャーどころも入れてくれるので追加する。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
spring-bootアプリケーションそのもののユニットテスト。
package com.kagamihoge.wildflyspringboot; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Import; import org.springframework.test.context.junit4.SpringRunner; import com.kagamihoge.wildflyspringboot.ApplicationTest.MyTestsConfiguration; @RunWith(SpringRunner.class) @SpringBootTest(properties = {"spring.profiles.active=test"}) @Import(MyTestsConfiguration.class) public class ApplicationTest { @Test public void test() { } @TestConfiguration static class MyTestsConfiguration { } }
@TestConfiguration
を付与する内部クラスで、ユニットテスト用のconfigクラスを作成。
@Import(MyTestsConfiguration.class)
でそのconfigクラスをインポート。
@SpringBootTest(properties = {"spring.profiles.active=test"})
で、spring-bootアプリケーションとしてのテストを指定し、spring-bootのプロファイルにtest
を指定。src/test/java/application-test.yml
を作っておけばそれが使われる。