Furyu
[フリュー公式]

Tech Blog

フリュー株式会社の技術ブログです

2018年07月19日

Spring Boot 2系でServiceによる起動をさせてみる

こんにちは、フリューのジョンです。

以前CentOS7でのSpring Bootの起動について記載させていただきました。
CentOS7でのSpring Bootの起動について

その後Spring Boot 2系がリリースされましたが、Gradleの場合は若干修正になりました。
とはいえ①の部分のみです。

Spring Boot 1系ではbootJarというタスクではなく以下のようなものでした。

今後はbootJarタスクを利用してやるようです。

詳しくは https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html を参考にしてください。

 


2018年03月27日

CentOS7でのSpring Bootの起動について

こんにちは。フリューのジョンです。

さてさて、以前以下の記事でSpring Bootアプリケーションのserviceでの起動について触れました。
Spring Boot アプリケーションの再起動時にハマったこと

しかし、上記はCentOS6での話でした。CentOS7になるとより柔軟なサービスの管理ができます。
さて、何が変わるのでしょうか?

serviceとsystemctlの違い

私が感じている良い点としては以下です

  1. systemctl statusでサービスの状態がわかる(いつ起動したのかなどもわかります)
  2. 後述する、ユニットファイルの設定によって起動の依存を記述することができる(あるサービスが起動していなければ動かさないなど
  3. 起動時、停止時に呼ばれるスクリプトを指定することができる

実際に複雑なマイクロサービスを作っていく上では欲しい機能になるかと思います。

変更方法

主に前回のものとの比較になりますが2点が異なるのみです。

サービスの登録方法がことなる

サービスの登録には以下のコマンドを実行していましたが

CentOS7では、プロセス名.service というユニットファイルを /usr/lib/systemd/system に配置します。
中身は以下のようになります。(中身の詳細は 9.6. システムのユニットファイルの作成および変更 を参照ください)

プロセスの起動方法が異なる

サービスの実行には以下コマンドで実行していましたが、

CentOS7では、systemctlコマンドを利用します。

この2点だけです。それ以外のconfファイルの書き方、配置などは全く変わりません。

補足

デフォルトのユニットファイル設定では /var/log/messages にログが吐き出されます。
そのため、アプリケーションのログは別に出しているし、ここに吐き出されたくない場合はユニットファイルのServiceに以下を追加します。

まとめ

systemctlコマンドによる起動で再起動スクリプトを自作する必要もありません(serviceによる起動でも同じですが
マイクロサービスを進めていくには、インフラ回りについてきちんと勉強していく必要があると感じます。

それでは素敵なマイクロサービス運用、Spring Bootライフを!!

弊社では一緒にサービスを作ってくれるSpringエンジニアを募集しています!!

詳しくはこちら

追記:

Spring Boot 2系でのリリースについて若干変更がありましたのでページを作りました。
Spring Boot 2系でServiceによる起動をさせてみる


2018年03月8日

Spring Boot アプリケーションの再起動時にハマったこと

こんにちは。フリューのジョンです。

Spring Boot良いですよね。設定が楽ですね。弊社ではマイクロサービスを勧めていく上でSpring Bootを使うことが増えてきました。

ただ、Spring Bootのアプリケーションを再起動する際にkillをしても、たまにプロセスが死なない時があり、再起動に失敗するということがありました。

何かいい方法はないのかなぁと見ていたところ以下が見つかりました。
https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
この方法を入れると今までは

という感じで起動していましたが

で起動するようになります。startの他には以下があります

  • stop
  • force-stop
  • restart
  • force-reload
  • status
  • run

この方法で起動するには前準備が必要です。

 

前準備

mavenプロジェクトであればpom.xmlに以下pluginを追加します

次にconfファイルを作成します。ファイル名はjarの名前と同じにしておきます。${application}.conf(confファイルは環境変数に設定してある場合は無くても良いです

次にpackagingしたjarファイルをサーバにデプロイし、権限を変えておきます。

配置したjarと同じ場所に先ほど作成したconfファイルを配置し、その後以下でリンクを作成します。

これで終わりです。

 

再起動方法

jarファイルをデプロイした後に、以下コマンドで再起動をしていくことになると思います。

 

なぜ動くのか

mavenのpluginを入れることでjarファイルの先頭にスクリプトが挿入されます。
このスクリプトがserviceからの起動に対して動くことになります。

参考: Spring Boot の Fully Executable Jar はなぜ動くのか

 

application.ymlに書いた日本語文字列が文字化けする

起動はできたのですが、application.ymlに書いた文字列が文字化けしてしまいました。

そこで先ほど記載したconfのJAVA_OPTSにfile.encodingを追加します。

 

まとめ

以上の設定をすることで今までのところ再起動失敗というのはなくなりました。

素敵なマイクロサービス運用、Spring Bootライフを!!

弊社では一緒にサービスを作ってくれるSpringエンジニアを募集しています!!

詳しくはこちら

 


2017年07月24日

Spring Securityを使ったAjax通信について

こんにちは。フリューのジョンです。

最近はVue.jsがあればテンプレートエンジンなんていらないと思いながらThymeleafを触っています。

さて、今回はSpring Securityを使ったAjax通信についてハマったのでそれの解消方法について書かせていただきます。

具体的には、Spring Securityの機能の一つである、クロスサイトスクリプティング防止機能でハマりました。

クロスサイトスクリプティングの説明については、今回省きます。他サイトを参照してください。

概要

環境は以下のとおりです。

spring-boot 1.5.3.RELEASE
spring-boot-starter-security 1.5.3.RELEASE
Thymeleaf 3.0.6.RELEASE

結論から言えば、Spring Securityを導入すると、単純なPOSTアクセスをすることができなくなります。
理由としては、認可した場所からのリクエストであることを検証するためにトークンが必要になるためです。その為、これを解消するには以下の方法があります。

  • Formにトークンを付ける。
  • Cookieにトークンをつけて、リクエストヘッダにトークンをつけて送信する。
  • GETで対処する  ← ダメゼッタイ、ユルサナイ

上手くいかない例

まずうまくいかない、例を見てみましょう。

この状態でボタンを叩くと以下のような画面になります。

spring-security-postが上手くいかない例

Formにトークンを付ける

これはSpring Security+Thymeleafを導入すると簡単に対応できます。

具体的にはFormのaction属性をThymeleafのものにします。

Formタグを見てみると自動でinput[type=’hidden’]が追加されているのがわかると思います。

spring-security-form送信(上手くいく例

Ajaxにする場合、このinput[name=’_csrf’]の値をJavaScriptで取得すれば良いのです。しかし、この方法はFormタグがなければ成り立ちません。

FormがないAjaxのpost通信をするためには、以下の方法があります。

Cookieにトークンをつけて、リクエストヘッダにトークンをつけて送信する

Spring Securityでは、Cookieにトークンをつけることができます。そのためには、CookieCsrfTokenRepositoryを使用します。

withHttpOnlyFalseとしているのは、HTTPでもCookieにトークンをつけてもらうためです(デフォルトはHTTPSだけにしかCookieは付いてきません)。リクエストを見てみると、以下のようにXSRF-TOKENという名前のCookieがついているのがわかります。

spring-security-cookieが付いている

このCookieの値をJavaScriptで読み込み、リクエストヘッダにX-XSRF-TOKENをつけます。

これによりAjax通信が可能になります。しかし、いちいちCookieをとってリクエストヘッダに渡すのは面倒ですね。

Axiosというライブラリではそれを解消してくれます。内部でcookie()を見て、リクエストヘッダに追加してくれているのです。

非常に便利ですね。

Cookieの名前、ヘッダの名前は、デフォルトの値ですので、変更可能です。もちろんAxiosの方も変更が可能です。

AxiosのFormData通信

ちょっと話が変わりますが、Spring SecurityでのAjaxのlogin機能を実装しようとした時、すこし、ハマりましたので追記します。

Axiosで通信するとデフォルトはJsonでの通信になります。しかし、loginには、FormDataでパラメータを渡さなければいけません。

実装方法としては、以下のようにAxiosのpostメソッドの第3パラメータに変換メソッドを追加してあげます。

まとめ

Spring Securityを使ったajax通信は少しだけ工夫が必要です。
しかし、その設定は本当に少しだけです。
ここではSpring Securityの機能自体について触れませんでしたが、Spring Securityは本当に素晴らしいので、ぜひ使ってみてください。

そして、Ajax通信だけのために、jQueryを使うのは止めましょう。Axiosを使ってみましょう。(個人の感想です)

最後に

弊社は、Springを実践利用してバリバリコード書きたいエンジニア募集中です!

詳しくはこちら


2017年07月24日

Doma2を使った複数データベースアクセス

こんにちは。フリューのジョンです。

個人的意見ではありますがSpring Data JPAのほうが好きですが、今回はDoma2を使った複数データベースアクセスを実装して躓いたので書かせていただきたいと思います。

概要

環境としましては以下のようになります。

spring-boot 1.5.3.RELEASE
doma-spring-boot-starter 1.1.0
spring-boot-starter-aop 1.5.4.RELEASE

複数のデータベースアクセスの具体的な要件は以下になります。

  • データベースアクセスをするメソッドに対して、アノテーションを付けてアクセス先を切り替える
  • アノテーションを付けていない場合はデフォルトのデータベースにアクセスする
  • 接続先はDomaの基本に合わせて、DataSourceの切り替えをしたい

以上の要件を満たすために、AbstractRoutingDataSourceとAnnotation、ThreadLocalを利用しました。

実装については、Qiitaの「Spring Bootで複数データベースを扱うウェブアプリケーションのサンプル」の記事を参考にさせていただきました。

実装

Daoには実装は加えません。

肝になるのは、AbstractRoutingDataSourceです。AbstractRoutingDataSourceはSpringのJDBCパッケージの中にあります。
このクラスを実装したモノを、Domaのconfigを継承したConfigrationクラスが返却することで対応が可能です。

ここで、AppConfigはルートである必要があります。(もしかすると、そうでなくてもいける方法があるのかもしれませんが、私が調べた限り出来ませんでした……)

接続先を保存するためにstaticでデータを作っておきます。ThreadLocalですので取扱には注意です。

メソッドに必要なアノテーションは以下のように設定します

アノテーションの実装は以下になります。
アノテーションがあるメソッドが動く前に接続先をHolderにセットして、動作した後に開放しています。

接続先はenumで持つようにします。

ここまでで実装終わりです。

使い方

以下のようになります。

まとめ

今回はアノテーションを使った振り分け方を行いましたが、リクエストパラメータやCookieを使って振り分けるというのも良いかと思います。

Doma2がConfigを勝手に参照してくれるのは、とても楽ですね。設定だけでうまくいきました。

最後に

弊社は、Springを実践利用してバリバリコード書きたいエンジニア募集中です!

詳しくはこちら