kagamihogeの日記

kagamihogeの日記です。

WildFly 11 + Spring Boot

直近でWildFly 11でSpring Boot動かすのに調べたことのメモ。といっても、WildFlyプラスそのプロジェクト固有事情による設定とかの内容も混じっている。ただまぁ、自分用の作業ログなので余りそのへんは気にしない。

ソースコード

https://github.com/kagamihoge/wildflyspringboot

環境

  • jdk1.8.0_152
  • Eclipse 4.7.1
  • WildFly 11.0.0.Final
  • spring-boot 1.5.9.RELEASE

とりあえず動かす

とりあえず 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

WildFlyPer-deployment Logginglog4jを使うので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とか追加する。

f:id:kagamihoge:20171230141014j:plain

プロファイルの切り替えのやり方は色々あるんで、とりあえず一例として。

データソース

まず依存性を追加する。

     <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

PostgreSQLjdbcドライバが無いって怒られるので、適当なバージョンのものを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を作っておけばそれが使われる。

アトラス作品ファンのオフ会 真・眼鏡祭Ⅲ(2017/11/25)に行ってきた

11/25 真・眼鏡祭Ⅲ - 東京が死んで僕が生まれた - Twipla に行ってきました。当日の様子はTwitterのハッシュタグ 眼鏡祭1125から追えます。

f:id:kagamihoge:20171127233914p:plain

眼鏡祭はアトラス作品ファンの大規模オフ会です。今回の参加者は200人強、一・二次会を含めるとほぼ一日かけてのイベントです。一次会会場は新宿某所をワンフロア貸切、二次会はバーを2フロア占有でした。当日は天候にも恵まれ、朝方に交通機関は若干乱れたようですが、特に大きな混乱も無い一日となりました。

コスプレOKなオフ会

眼鏡祭の特色としてコスプレOKな点がまず挙げられ、以下の全体集合写真が雰囲気を良く伝えています。

コスプレを良くする方に聞いてもアトラス作品だけでこれだけの人数が集まる事はまず無いとのこと。コスプレをする・しないに関わらず、写真から分かる通りのお祭り感覚を目当てに参加している人は多いです。

今回のコスプレの傾向としては、P5がやや多目なもののバラけた印象でした。ジョーカーは相変わらず強くて怪盗団始めP5コープのキャラクタがまず目を引きます。P4・P3の根強い人気は変わりなく。そして人ではなく悪魔、さらには早くもDSJやD×2のコスプレには驚かされました。

また、眼鏡祭のコスプレの特色として、今となっては懐かしいものやマイナーな作品のコスプレが人数は少なくてもゼロになることがほとんど無く、新旧色とりどりのコスプレが集まるのは特筆すべき点でしょう。

コスプレして、飲んで、オタクの話題で盛り上がる

眼鏡祭は特にこれというコンテンツはなく、単なるオフ会に過ぎません。人数の規模やコスプレOKな点を除くと、本当にただのオフ会です。にも関わらず10年近く開催され続けている理由は、アニメ・マンガ・ゲーム、いわゆるオタクな話題を一日中していられる、というシンプルさにあります。

コスプレしてもしなくても、撮ったり撮られたり。そして何より、好きな作品のコスプレしてる人とその作品で盛り上がるのは、本当にかけがえのない楽しさがあります。

コスプレではなく仮装

眼鏡祭は人数の多さと熱気が高く、自力である程度テンションを上げないと飲み込まれかねない凄まじさがあります。そこで、何かしら盛り上げるための工夫……つまりコスプレ、敷居が高ければ仮装、を推奨しています。

眼鏡祭ではコスプレを仮装と呼びます。仮装とはいわゆるコスプレを含み、それ以外では例えば、普段では恥ずかしいグッズ類を身に付けたり、プリントTシャツを着たり、P4千枝のジャージをとりあえず羽織ってみたり……そうするだけでもテンションは上がります。仮装という呼び方にはそういう思いが込められている、と私は解釈しています。

一人で来ても楽しめるのか?

はっきり言って、200人規模のオフ会に知り合い無く来るのは相当な勇気が必要です。実際どうなのか、こればかりは初参加者のツイートを見てください、としか言えません。

ステルスマーケティングめいた引用をしましたが、当然肯定的な意見ばかりでは無いです。ただし、データ的に眼鏡祭のリピート率はかなり高いです。なお、参加者の比率はおおむね1~2割は初参加または数回目です。初めましてが自分しかいない、ということは無いです。

さまざまな初心者向けの仕掛け

初心者向けの配慮は様々な仕組みが施されています。

たとえば、今回は参加者特典のノベルティとして上記のようなシールが各参加者に二枚配布されました。お目当てのキャラクターが欲しいのであれば他の参加者と交換するしかないので、会話のとっかかりにこのシールを使えるようになっています。

参加者はそれぞれ上記のような名札を下げています。青が運営、黒が常連、赤が初参加。会場の注意事項では、困ったらまず青札へ、とアナウンスがされます。黒い常連勢の中には赤札に積極的に話しかけるよう心掛けている人も多いようです。

会場入場後の流れは、まず6~7人のグループに分かれてテーブルに着席し、まずはその少人数での交流開始になります。乾杯後は歩き回ってもいいし、気が合えばそのままで構いません。

友人同士同じテーブルになりたいなど要望があれば可能な限り応えてくれます。このあたりの相談は遠慮なく主催にTwitterで連絡するのが良いです。

注意点:コスプレイベントでは無い

眼鏡祭はコスプレが派手で目立ちますが、いわゆるコスプレイベントではありません。あくまでも交流がメインのオフ会です。そのため色々なルールがあります。たとえば、写真撮影は同意の上行うこと、SNSへのアップも本人同意の上行うこと、など。

また、会場は単なるカフェなので設備は撮影に向いているとは言えません。加えて、更衣室もカフェの一室をビニールシートなどで区切っただけなので、照明であるとかの設備は整っているとは言えません。

みんなの力でつくられる眼鏡祭

眼鏡祭は有志一同で運営しています。何等かのイベント会社が運営しているわけではありません。眼鏡祭は200人超の人間がほぼ一日動き続けるイベントです。そこで動く、人・物・金・情報、の量を考えると、あらゆる苦労の連続であることは想像に難くありません。

しかし、あらゆる領域のスキルが求められるということは、逆を言うと、誰であっても貢献できる可能性があります。

もし、眼鏡祭に何かしらを返せれば……という思いがあれば、運営を手伝ってみるのも一手です。

会場設営や更衣室関連は比較的目に見えるところなのでツイートを引用させて頂きましたが、有志スタッフの皆さんの尽力には毎回頭が下がります。

ほかのイベントにも行ってみる

これは個人的な意見ですが眼鏡祭本編だけで友人関係を築くのは至難の業です。何しろ200人もの人が目まぐるしく流れていくので、覚えるのも覚えてもらうのも一苦労です。

そこで、眼鏡祭にたくさんいるパーリーピーポーの、もう少し人数が絞られる他イベントに足を運ぶのがオススメです。

まずは眼鏡祭の忘年会こと想年会。これはホントに眼鏡勢が集まるただの飲み会です。

関西勢には朗報の関西眼鏡祭も決まりました。

眼鏡祭主催マソーさんのゲーマーが集うリターナー会。

プラモデルをもくもく作る会には自分も行く予定です。

開催済みのイベントですがペルソナ系コピーバンドのライブ DreamCastTV another edition PERSONA Fes なんてものもありました。

上は自分が捕捉できているものだけなので、当然、これ以外にも沢山のイベントなり飲み会があります。

眼鏡祭は初心者向け配慮が充実してます。しかし、それを自分のコープとして育てていくのは自分次第です。とはいえあまり気負わず、気軽にテキトーになんか行ってみるのが良いとおもいます。

さいごに

最後になりましたが主催のマソーさんはじめ有志運営スタッフのみなさん本当におつかれさまでした。また、今回参加者の皆さん、俺と話し相手になってくれた方々や、微妙な写真撮影に付き合わせてしまった方々、色々すいませんがありがとうございました。別のイベントやまたの機会があればよろしくお願いします。

URL一覧

著者近影

JEP 307: Parallel Full GC for G1をテキトーに訳した

http://openjdk.java.net/jeps/307 をテキトーに訳した。

JEP 307: Parallel Full GC for G1

Owner    Stefan Johansson
Created 2017/01/17 11:40
Updated 2017/11/13 16:52
Type    Feature
Status  Targeted
Component   hotspot?/?gc
Scope   Implementation
Discussion  hotspot dash gc dash dev at openjdk dot java dot net
Effort  M
Duration    M
Priority    3
Reviewed by Mikael Vidstedt
Endorsed by Mikael Vidstedt
Release 10
Issue   8172890

Summary

G1のワーストケースのレイテンシ改善のため、パラレルのフルGCを導入します。

Non-Goals

すべてのユースケースにおけるパラレルGCのフルGCのパフォーマンス調整。

Motivation

G1 GCJDK 9のデフォルトになりました。以前のデフォルトのパラレルGCには、パラレルフルGCがあります。ユーザが直面するフルGCインパクトを最小化するため、G1フルGCもパラレルに出来るのが望ましいです。

Description

G1 GCはフルGCを避けるように設計されていますが、コンカレントコレクションが速やかにメモリを回収出来ない場合はフルGCにフォールバックします。G1 GCの現在の実装はシングルスレッドのmark-sweep-compactアルゴリズムです。我々はmark-sweep-compactアルゴリズムをパラレル化し、また、YoungとMixedのコレクションに同じ数のスレッドを使うようにしよう、と考えています。スレッド数は-XX:ParallelGCThreadsオプションで制御可能にしますが、YoungとMixedコレクションに使われるスレッド数にも影響します。

Testing

  • フルGC時間の改善を確認するためにその時間を分析します。G1はフルGCを避けるよう設計されているので、ベンチマークスコアの確認ではおそらく不十分です。
  • ボトルネックを見つけ出すのにVTuneもしくはSolaris Studio Performance Analyzerを使用したランタイム分析をします。

Risks and Assumptions

  • G1の基本設計がパラレルフルGCを阻害しないという仮定の上にこのJEPは立っています。
  • G1にはリージョンがあるので、単一スレッドのフルGCよりもパラレルフルGC後の方が余計にメモリを浪費する可能性がかなり高いです。